Portable Object Compiler (c) 1997,2000,03.  All Rights Reserved.

AsciiFiler

Inherits from: Object

Maturity Index: Experimental

Class Description

AsciiFiler is a (somewhat Stepstone compatible) filer class, to archive objects on disk.  Archiving is a general technique for saving (passivating) and later, loading (activating) objects to and from a file.  There are essentially two complementary operations.  storeOn: converts the object as it exists in memory into a flat text file format.  readFrom: does the inverse and translates the process-independent symbolic names again into a process-specific object.

[myObject storeOn:"/tmp/aFile"];

and then later,

myObject = [AsciiFiler readFrom:"/tmp/aFile"];

The readFrom: returns an instance of the class that it finds in the file, not an AsciiFiler instance.

The methods storeOn: and readFrom: are declared in the Object class and are inherited by all objects.

Example

Suppose a class named Record is implemented as follows :

\= Record : Object
{
        id firstname;
        id familyname;
}

+ new
{
        self = [super new];
        firstname = [String str:"Paco"];
        familyname = [String str:"Rodriguez"];
        return self;
}

\=:

Then the following demonstrates how the AsciiFiler class automatically converts instances of Record to a flat file text representation :

int main()
{
	[[Record new] storeOn:"/tmp/aFile"];
}

Inspection of the file aFile would show :

#AsciiFiler i144 
0 #Record @2 @3 
0 #String i4 i5 *4"Paco 
0 #String i9 i10 *9"Rodriguez 

This file can be used to read back an instance of Record into memory, and all this without the developer having to write a single line of code.

File Format

Because we have no intention to reinvent the wheel in this area, we try to keep our AsciiFiler file format partly compatible with the original Stepstone file format.  The following shows a Stepstone dump of a OrdCltn containing some Strings and a Set :

#AsciiFiler i3
10 #OrdCltn @2 i10 i3
10 #IdArray i10 @3 @3 @4 @0 @0 @0 @0 @0 @0 @0
12 #String i11 i11 *11"hello world
20 #Set @5 i20 i1
20 #IdArray i20 @0 @0 @0 @0 @0 @0 @0 @0 @0 @0 @0 @0 @0 @3 @0 @0 @0 @0 @0 @0

Each record in the file is newline terminated.  The first record indicates that this is a (Stepstone) AsciiFiler file, version 3.  Then follows object 1 on line 1, object 2 on line 2 and so on.  The first field for each record is the number of indexed variables (this will always be 0 for the Portable Object Compiler).  Then follows the isa pointer and the instance variables of each object.

Here's a short list of the most commonly used notation in AsciiFiler files.  Note that objects are stored using a notation that allows for back or forward pointers.  For example, the object in record 5 may contain a reference to @3, the object in record 3, or to @10, the object in record 10.

	- i : integer, like in i3
	- S : unsigned short integer, like in S3
	- sharp : class name, such as #String
	- dollar : pointer (only used for NULL pointer)
	- at : object identifier, @0 stands for nil
	- star : NULL terminated char pointer

The Stepstone filer class supports, for reasons explained below, many more type descriptors (characters to encode C types).  They are not necessarily implemented by this class, since the implementation significantly differs.

Automatic I/O

The Stepstone and Portable Object Compiler runtime are said to have automatic I/O, because both compilers and runtimes attempt to do the job of implementing the necessary methods to write and read instance variables for a class, without intervention of the programmer.  Other runtimes sometimes offer only semi-automatic I/O where the programmer has to develop the code to read and write instance variables.

However, the details about what is done automatically and what is left to the programmer differ.  The Stepstone compiler attempts to automatically file all C types (ints, chars, unions, structs etc.).

The Portable Object Compiler emits for each class an implementation for the fileOutIdsFor: and fileInIdsFrom: methods.  These methods take care of the archiving of id instance variables (objects).  Unlike Stepstone, the Portable Object Compiler does not attempt to automatically archive C types; this must be done manually, if the programmer chooses to use instance variables that are raw C types instead of Objective-C objects.

Therefore, if a class adds only id instance variables to its superclass, then storeOn: and readFrom: will immediately work for the class.  Otherwise manual archiving needs to be done, as explained in the following paragraphs.

File Out Operation

Storing an object works in two passes : the filer will first build a table of contents (TOC) by sending fileOutOn: to all objects that can be reached from the object that is being stored.  A second pass will again send fileOutOn: to the objects, this time to actually write the data to the file, assigning to each object a label, which is the offset of the object in the TOC.

The default implementation of fileOutOn:, as implemented in the Object class, uses the compiler generated fileOutIdsFor: method to store all id instance variables.  This might suffice in many applications.

Variables of a different type, or objects that are indirectly owned by the object must be manually written on the Filer, by using the fileOut:type: method.

- fileOutOn:aFiler
{
	[super fileOutOn:aFiler];
	[aFiler fileOut:&myInt type:'i'];
	[aFiler fileOut:&cArray[0] type:'@'];
	[aFiler fileOut:&cArray[1] type:'@'];
	return self;
}

File In Operation

When activating objects, the Filer will first build a table of instances for each record in the file.  The Filer knows what factory class to use, since each record includes the necessary class information.  Then, once all (uninitialized) objects exist, each instance receives a fileInFrom: message.  Only when all instances have had the opportunity to file themselves in, from the Filer, awakeFrom: messages are sent to the objects.  This can be used to perform further initialization, to make objects or string unique etc.

The default implementation of fileInFrom:, as implemented in the Object class, uses the compiler generated fileInIdsFrom: method to restore all id instance variables.  A method fileInFrom: needs to be implemented only to match a corresponding fileOutOn:.

- fileInFrom:aFiler
{
	[super fileInFrom:aFiler];
	[aFiler fileIn:&myInt type:'i'];
	[aFiler fileIn:&cArray[0] type:'@'];
	[aFiler fileIn:&cArray[1] type:'@'];
	return self;
}

If the type description character, passed as argument to fileIn:type: does not match what was used for fileOut:type:, the Filer will signal a TypeInconsistency exception.

Method types

Class Initialization	- initialize

Creating	- new
	- free

Storing and Reading Objects	- store:on:
	- readFrom:

File Out Operation	- fileOut:type:

File In Operation	- fileIn:type:

Methods

initialize
+initialize

Registers the AsciiFiler as default filer.

new
+new

Factory method to create and return a new instance of the class.  The default implementation clears (zeroes) the memory for instance variables and initializes the isa pointer.

free
-free

Frees the memory for this instance, and returns nil.

store:on:
- (BOOL)store:anObjecton:(STR)aFileName

AsciiFiler reimplementation of storeOn:.  Doesn't use the default Filer, but rather AsciiFiler itself as Filer class.  If the default filer is AsciiFiler, then the following are equivalent :

[AsciiFiler store:anObject on:aFileName];

and

[anObject storeOn:aFileName];

readFrom:
-readFrom:(STR)aFileName

AsciiFiler reimplements readFrom: and doesn't use the default Filer, but rather AsciiFiler itself as Filer class.

fileOut:type:
-fileOut:(void *)valuetype:(char)typeDesc

Writes out the data referenced by value to the filer.

fileIn:type:
-fileIn:(void *)valuetype:(char)typeDesc

Reads from the filer and returns data by reference.