There a various ways to store the state of a group of related objects. A working solution would be to use a conventional file system directory in which each of the objects is a file, or, if it contains objects itself, a subdirectory. Unfortunately, this is an inconvenient solution, for example when copying the document. Experience has shown that dividing one logical file into multiple physical files leads to problems.
The solution used by the OLE2-developers was to use compound files. Simply put, a compound file is filesystem in a file. Just like a file system consists of directories and files, a compound file consists of streams and storages.
Bonobo follows this OLE2-approach, and defines interfaces for stores and streams:
GNOME:Stream: the Bonobo interface for streams. This is the counterpart of OLE2's IStream (surprisingly).
GNOME:Storage: the Bonobo interface for streams. This is the counterpart of OLE2's IStorage.
The GNOME::Storage interface specifies the 'directory-part' of the filesystem-in-a-file. The following methods are exported (bonobo-storage.idl):
interface Storage : Unknown { typedef long OpenMode; const OpenMode READ = 1; const OpenMode WRITE = 2; const OpenMode DENY_READ = 4; const OpenMode DENY_WRITE = 8; exception NameExists {}; exception NotFound {}; exception NoPermission {}; typedef sequence<string> directory_list; Stream create_stream (in string path) raises (NameExists); Stream open_stream (in string path, in OpenMode mode) raises (NotFound, NoPermission); Storage create_storage (in string path) raises (NameExists); Storage open_storage (in string path, in OpenMode mode) raises (NotFound, NoPermission); void copy_to (in Storage target); void rename (in string path_name, in string new_path_name) raises (NameExists, NotFound); void commit (); directory_list list_contents (in string path) raises (NotFound); void erase (in string path) raises (NotFound); }; |
create_stream: Creates a new stream object located in the given path. The path needs not to be a file system path, as stream object are not necessarily files. create_stream raises a NameExist when there's already a stream located a the given path. If all goes well, the function return a brand new stream object.
open_stream: Opens an existing stream object in the given path and with the given permissions. open_stream raises a NotFound exception, when the file is, well, not found, and a NoPermission when the client doesn't have sufficient permissions. If all goes well, it returns an open stream object.
create_storage: Creates a new storage at the given path. This is equivalent to the mkdir shell command. This function raises a NameExist when there's already a storage at the given path. The path needs not to be a filesystem path. If all goes well, the function returns a new storage object.
open_storage: Open the storage at the given path with the given permissions. open_storage raises NotFound or NoPermission, as expected.
copy_to: Copies the storage to the given target storage. This is comparable to the shell command cp -R. No exceptions are defined for copy_to.
rename: Renames the given substorage or stream. Exceptions are raised when the source doesn't exist (NotFound), or the target already exists (NameExists).
commit commit reflects changes (for a transacted storage) to the parent level, and flushes any buffers. Note that, at this time, the accompanying revert- function does not exist.
list_contents The list-contents lists the contents of the storage at the given path, like ls does in the shell. On success, the list_contents returns a list with the of streams and storages at the given path.
erase The erase erases the stream or storage existing at the given path. Raises a NotFound-exception when the stream or storage can't be found.
module GNOME { interface Stream : Unknown { typedef sequence<octet> iobuf; enum SeekType { SEEK_SET, SEEK_CUR, SEEK_END }; long read (in long count, out iobuf buffer); long write (in iobuf buffer); long seek (in long offset, in SeekType whence); void truncate (in long length); void copy_to (in string dest, in long bytes, inout long read, inout long written); void commit (); void close (); boolean eos (); long length (); }; }; |
read: Reads 'count' numbers from the stream, and places it in the i/o buffer 'buffer'. read returns with the number of bytes read. read returns -1 on failure in case of a file-based stream.
write: Writes data from 'buffer' to the stream. write returns the number of bytes written.
seek: Moves the stream pointer to the given offset, from the based denoted by the 'SeekType'. The seek type can be either the beginning (SEEK_SET), the end (SEEK_END), or the current position (SEEK_CUR), like the lseek library function.
truncate: Changes the size of a stream to the given length.
copy_to: Copies 'bytes' bytes from the stream to some destination stream 'dest'. After returning, 'read' contains the number of bytes actually read, while 'written' contains the number of bytes actually written.
commit: Ensures that changes made to the streams are reflected in the parent storage.
close: Closes the stream.
eos: Returns a boolean denoting whether or on the stream pointer is a the end of the stream. Similar to the feof library call.
length Returns the length of the stream (in bytes).