DEADSOFTWARE

Testing odcread against a bunch of existing .odc files
[odcread.git] / reader.h
index cfd4fc53194f1242de4890a369e5765bc086bce5..e59f36c2417bf4bdaffad708f99984fcb0250799 100644 (file)
--- a/reader.h
+++ b/reader.h
 #define _READER_H_
 
 #include <iostream>
+#include <vector>
 
 #include <oberon.h>
 #include <store.h>
+#include <alien.h>
 
 namespace odc {
 
+struct TypeEntry {
+       const std::string name;
+       INTEGER baseId;
+
+       TypeEntry(const std::string &typeName) : name(typeName), baseId(-1) {}
+};
+
 /**
- * TYPE Reader
- * Reader for Component Pascal values like integers, reals, or sets. A reader contains a Files.Reader, to which it forwards most operations.
- * Readers are used in the Store.Internalize procedure.
- * Readers are not extensible.
+ * Used by Store.internalize() to read from file.
  */ 
 class Reader {
 private:
-       /*
-        * rider-: Files.Reader
-        * The file rider which links a Reader to a file.
+       /**
+        * The store was read as an Alien because its type is not registered.
+        * @see TypeRegister.
+        */
+       static const unsigned int TYPENOTFOUND = 1;
+       /**
+        * The store was read as an Alien because its version is not in the accepted range.
+        */
+       static const unsigned int ALIENVERSION = 2;
+
+       /**
+        * The input stream associated with this reader.
         */ 
        std::istream &d_rider;
 
-       /*
-        * cancelled-: BOOLEAN  valid during a Store.Internalize call
-        * Tells whether the currently executing Internalize has been called by ReadVersion or TurnIntoAlien.
+       /**
+        * Whether the currently executing Store.internalize() has been cancelled.
+        * If so, it will be read as an Alien.
         */
        bool d_cancelled;
 
        /**
-        * readAlien-: BOOLEAN
-        * Tells whether any alien has been read since the last ConnectTo.
+        * Cause of current read being an Alien.
+        */
+       unsigned int d_cause;
+
+       /**
+        * Whether any alien has been read from the input stream.
         */
        bool d_readAlien;
 
-       INTEGER d_nextElemId;
-       INTEGER d_nextStoreId;
+       /**
+        * The TypeList should be used for consistency checking on type paths.
+        * Currently unused.
+        */
+       std::vector<TypeEntry*> d_typeList;
 
-       public:
        /**
-        * Construct a reader from the istream rider.
-        * @param rider An istream (binary mode).
+        * List of stores that have been read already, to enable repeated occurences
+        * of a single store to reference them.
+        * Elem type stores have IDs that are separate from the IDs of other stores.
         */
-       Reader(std::istream &rider);
+       std::vector<Store*> d_elemList;
+       /**
+        * List of stores that have been read already, to enable repeated occurences
+        * of a single store to reference them.
+        * Elem type stores have IDs that are separate from the IDs of other stores.
+        */
+       std::vector<Store*> d_storeList;
 
        /**
-        * PROCEDURE (VAR rd: Reader) ConnectTo (f: Files.File)
-        * NEW
-        * Connect the reader to a file. All the following operations require connected readers, i.e., rd.rider # NIL. This precondition is not checked explicitly, however. After connecting, the reader's position is at the beginning of the file. If the same reader should be reused on another file, it must first be closed, by connecting it to NIL.
-        * ConnectTo is used internally.
-        * 
-        * Pre
-        * 20   (f = NIL) OR (rd.rider = NIL)
-        * 
-        * Post
-        * f = NIL
-        *      rd.rider = NIL
-        * f # NIL
-        *      (rd.rider # NIL) & (rd.rider.Base() = f)
-        *      rd.Pos() = 0
+        * Stores the reader state so that we can rewind a failed Store.internalize().
         */
-       // FIXME
+       struct ReaderState {
+               /**
+                * Position of the next store in the current level
+                */
+               std::streampos next;
+               /**
+                * Position just after the last read store
+                */
+               std::streampos end;
+       };
 
        /**
-        * PROCEDURE (VAR rd: Reader) Pos (): INTEGER
-        * NEW
-        * Returns the reader's current position.
-        * 
-        * Post
-        * 0 <= result <= rd.rider.Base().Length()
+        * The store that is currently being read.
         */
-       // FIXME
+       Store *d_store;
 
        /**
-        * PROCEDURE (VAR rd: Reader) SetPos (pos: INTEGER)
-        * NEW
-        * Sets the reader's current position to pos.
-        * 
-        * Pre
-        * 20   pos >= 0
-        * 21   pos <= rd.rider.Base().Length()
-        * 
-        * Post
-        * rd.Pos() = pos
-        * ~rd.rider.eof
+        * Reader state at the start of reading the current store (before calling Store.internalize())....
         */
-       // FIXME
+       ReaderState *d_state;
 
+       public:
        /**
+        * Construct a reader from the istream rider.
+        * @param rider An istream (binary mode).
+        */
+       Reader(std::istream &rider);
+
+       /* Omitted reading methods:
+        *
+        * There are a number of ReadX* methods that read a SHORT type but return a LONG type. Those have been omitted.
+        *
         * PROCEDURE (VAR rd: Reader) ReadBool (OUT x: BOOLEAN)
         * NEW
         * Reads a Boolean value.
-        */ 
-       /**
-        * PROCEDURE (VAR rd: Reader) ReadSChar (OUT x: SHORTCHAR)
-        * NEW
-        * Reads a short character (00X..0FFX).
-        */ 
-       SHORTCHAR readSChar();
-       /* PROCEDURE (VAR rd: Reader) ReadXChar (OUT x: CHAR)
-        * NEW
-        * Same as ReadSChar, but has a CHAR-type parameter.
-        * This procedure is provided to simplify migration from Release 1.2 to 1.3.
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadChar (OUT x: CHAR)
-        * NEW
-        * Reads a character (0000X..0FFFFX).
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadByte (OUT x: BYTE)
-        * NEW
-        * Reads a very short integer (-128..127).
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadSInt (OUT x: SHORTINT)
-        * NEW
-        * Reads a short integer (-32768..32767).
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadXInt (OUT x: INTEGER)
-        * NEW
-        * Same as ReadSInt, but has an INTEGER-type parameter.
-        * This procedure is provided to simplify migration from Release 1.2 to 1.3.
-        */ 
-
-       /**
-        * PROCEDURE (VAR rd: Reader) ReadInt (OUT x: INTEGER)
-        * NEW
-        * Reads an integer (-2147483648..2147483647).
-        */
-       INTEGER readInt();
-       /* 
+        *
         * PROCEDURE (VAR rd: Reader) ReadLong (OUT x: LONGINT)
         * NEW
         * Reads a long integer (-9223372036854775808..9223372036854775807).
@@ -136,11 +119,6 @@ private:
         * NEW
         * Reads a short real (32-bit IEEE number).
         * 
-        * PROCEDURE (VAR rd: Reader) ReadXReal (OUT x: REAL)
-        * NEW
-        * Same as ReadSReal, but has a REAL-type parameter.
-        * This procedure is provided to simplify migration from Release 1.2 to 1.3.
-        * 
         * PROCEDURE (VAR rd: Reader) ReadReal (OUT x: REAL)
         * NEW
         * Reads a real (64-bit IEEE number).
@@ -148,99 +126,105 @@ private:
         * PROCEDURE (VAR rd: Reader) ReadSet (OUT x: SET)
         * NEW
         * Reads a set (32 elements).
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadSString (OUT x: ARRAY OF SHORTCHAR)
-        * NEW
-        * Reads a 0X-terminated short string.
-        * 
-        * Pre
-        * invalid index         LEN(x) > Length(string)
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadXString (OUT x: ARRAY OF CHAR)
-        * NEW
-        * Same as ReadSString, but has a string-type parameter.
-        * This procedure is provided to simplify migration from Release 1.2 to 1.3.
-        * 
+        *
         * PROCEDURE (VAR rd: Reader) ReadString (OUT x: ARRAY OF CHAR)
         * NEW
         * Reads a 0X-terminated string.
-        * 
-        * Pre
-        * invalid index         LEN(x) > Length(string)
-        * 
-        * PROCEDURE (VAR rd: Reader) ReadStore (OUT x: Store)
-        * NEW
+        */ 
+       /**
+        * Reads a short character (00X..0FFX).
+        */ 
+       SHORTCHAR readSChar();
+       /**
+        * Reads a string of short characters (00X..0FFX).
+        */ 
+       void readSChar(SHORTCHAR *buf, size_t len);
+       /** 
+        * Reads a character (0000X..0FFFFX).
+        */ 
+       CHAR readLChar();
+       /** 
+        * Reads a string of characters (0000X..0FFFFX).
+        */ 
+       void readLChar(CHAR *buf, size_t len);
+       /**
+        * Reads a very short integer (-128..127).
+        */ 
+       BYTE readByte();
+       /**
+        * Reads a short integer (-32768..32767).
+        */
+       SHORTINT readSInt();
+       /**
+        * Reads an integer (-2147483648..2147483647).
+        */
+       INTEGER readInt();
+       /**
+        * Reads a 0X-terminated short string.
+        * Used to read string that have a known maximum length.
+        */
+       void readSString(SHORTCHAR *out);
+       /** 
+        * (Explanation from the BlackBox source.)
         * Reads a store's type, allocates it, and then reads its contents, by calling the store's Internalize procedure. x may also be NIL, or an alien if the store's module cannot be loaded, or if internalization has been cancelled by the Internalize procedure.
         * If the store has already been read in, a pointer to the same store is returned instead of allocating a new one. This means that arbitrary graphs that have been written with WriteStore are reconstructed correctly, including alias pointers to the same store, cycles, etc.
         * If the file on which the reader operates does not contain correct input, then an assertion trap will be caused (traps 101 to trap 106).
-        * 
-        * Pre
-        * 20   the reader is at the start position of a new store
-        * 
-        * Post
-        * empty store on file
-        *      x = NIL
-        * non-empty store on file
-        *      x # NIL
-        *              x IS Alien
-        *                      x.cause # 0
-        *                      x.type # ""
-        *                      x.file # NIL
-        *                      x.pos >= 0      beginning of store's data
-        *                      x.len >= 0      length of store's data
-        *                      alien store contents are on x.file in the range [x.pos .. x.pos + x.len[.
-        *                      These data include only the store's contents, not its prefix
-        *              ~(x IS Alien)
-        *                      x was read successfully
         */
        Store *readStore();
        /**
-        * PROCEDURE (VAR rd: Reader) ReadVersion (min, max: INTEGER; OUT version: INTEGER)
-        * NEW
-        * Read a version byte and return it in version. If version is not in the specified range [min .. max], the store currently being read is turned into an alien, with cause = alienVersion.
-        * 
-        * Pre
-        * 20   0 <= min <= max
-        * 
-        * Post
-        * min <= version <= max
-        *      legal version
-        * (version < min) OR (version > max)
-        *      illegal version
-        *      rd.cause = alienVersion
-        *      rd.cancelled
-        *      rd.readAlien
-        * 
-        * PROCEDURE (VAR rd: Reader) TurnIntoAlien (cause: INTEGER)
-        * NEW
-        * A store which is currently being internalized can turn itself into an alien, e.g., if it has read a component store which is an alien.
-        * 
-        * Pre
-        * 20   cause > 0
+        * (Explanation from the BlackBox source.)
+        * Read a version byte and return it in version. If version is not in the
+        * specified range [min .. max], the store currently being read is turned
+        * into an alien, with cause = alienVersion.
+        */ 
+       INTEGER readVersion(INTEGER min, INTEGER max);
+       /**
+        * (Explanation from the BlackBox source.)
+        * A store which is currently being internalized can turn itself into an
+        * alien, e.g., if it has read a component store which is an alien.
+        */
+       void turnIntoAlien(int cause);
+
+       /**
+        * @return Whether the current read has been cancelled.
         */
+       bool isCancelled();
 
        private:
+       /**
+        * Read a store.
+        */
        Store *readStoreOrElemStore(bool isElem);
+       /**
+        * Read a Nil store. A Nil store doesn't contain anything, but may require us to skip some bytes.
+        */
        Store *readNilStore();
+       /**
+        * Read a link to an Elem-type store.
+        */
        Store *readLinkStore();
+       /**
+        * Read a link to a non-Elem-type store.
+        */
        Store *readNewLinkStore();
+       /**
+        * Read an alien store.
+        */
+       void internalizeAlien(Alien *alien, std::streampos down, std::streampos end);
        
-       /*
-               TypeName* = ARRAY 64 OF CHAR;
-               TypePath* = ARRAY 16 OF TypeName;
-               OpName* = ARRAY 32 OF CHAR;
-        */
-       inline CHAR *newTypeName() {
-               return new CHAR[64];
-       }
-       inline CHAR **newTypePath() {
-               CHAR **out = new CHAR*[16];
-               for (int i = 0; i < 16; ++i) {
-                       out[i] = newTypeName();
-               }
-               return out;
-       }
-       void readPath(CHAR **path);
+       /**
+        * Make store name consistent with names found in BlackBox source.
+        */
+       std::string &fixTypeName(std::string &name);
+
+       /**
+        * Read a type path.
+        */
+       TypePath readPath();
+       /**
+        * Add another component to the current path. If first==true, start a new path.
+        */
+       void addPathComponent(bool first, const std::string &typeName);
 };
 
 } // namespace odc