DEADSOFTWARE

Testing odcread against a bunch of existing .odc files
[odcread.git] / reader.cc
index 54ca8c1a2ff99ffee3554ca75353775616ea6964..a57e9bebefc50265d0b11cc48160d5c85e9cb3c8 100644 (file)
--- a/reader.cc
+++ b/reader.cc
@@ -1,8 +1,13 @@
 #include <reader.h>
+#include <alien.h>
+
+#include <string>
+#include <assert.h>
 
 namespace odc {
 
-Reader::Reader(std::istream &rider): d_rider(rider), d_cancelled(false), d_readAlien(false) {}
+Reader::Reader(std::istream &rider): d_rider(rider), d_cancelled(false), d_readAlien(false), d_typeList(),
+       d_state(new ReaderState()) {}
 
 SHORTCHAR Reader::readSChar() {
        SHORTCHAR out;
@@ -10,31 +15,116 @@ SHORTCHAR Reader::readSChar() {
        return out;
 }
 
+void Reader::readSChar(SHORTCHAR *buf, size_t len) {
+       d_rider.read(buf, len);
+}
+
+CHAR Reader::readLChar() {
+       CHAR buf;
+       char *bufPtr = (char *)&buf;
+       d_rider.read(bufPtr, 2);
+       if (isLittleEndian()) {
+               return buf;
+       } else {
+               CHAR out;
+               char *outPtr = (char *)&out;
+               outPtr[0] = bufPtr[1]; outPtr[1] = bufPtr[0];
+               return out;
+       }
+}
+
+void Reader::readLChar(CHAR *buf, size_t len) {
+       char *bufPtr = (char *)buf;
+       int len2 = len * 2;
+       d_rider.read(bufPtr, len2);
+       if (isBigEndian()) {
+               char tmp;
+               for (int i = 0; i < len2; i += 2) {
+                       tmp = bufPtr[i];
+                       bufPtr[i] = bufPtr[i + 1];
+                       bufPtr[i + 1] = tmp;
+               }
+       }
+}
+
+BYTE Reader::readByte() {
+       BYTE out;
+       d_rider.read((char*)&out, 1);
+       return out;
+}
+
+SHORTINT Reader::readSInt() {
+       SHORTINT buf;
+       char *bufPtr = (char*)&buf;
+       d_rider.read(bufPtr, 2);
+       if (isLittleEndian()) {
+               return buf;
+       } else {
+               SHORTINT out;
+               char *outPtr = (char *)&out;
+               outPtr[0] = bufPtr[1]; outPtr[1] = bufPtr[0];
+               return out;
+       }
+}
+
 INTEGER Reader::readInt() {
-       char *buf = new char[4];
-       d_rider.read(buf, 4);
+       INTEGER buf;
+       char *bufPtr = (char*)&buf;
+       d_rider.read(bufPtr, 4);
        if (isLittleEndian()) {
-               return *(INTEGER *)buf;
+               return buf;
        } else {
-               char *out = new char[4];
-               out[0] = buf[3]; out[1] = buf[2]; out[2] = buf[1]; out[3] = buf[0];
-               return *(INTEGER *)out;
+               INTEGER out;
+               char *outPtr = (char *)&out;
+               outPtr[0] = bufPtr[3]; outPtr[1] = bufPtr[2]; outPtr[2] = bufPtr[1]; outPtr[3] = bufPtr[0];
+               return out;
        }
 }
 
+void Reader::readSString(SHORTCHAR *out) {
+       while (*out = readSChar()) {
+               ++out;
+       }
+}
+
+void Reader::turnIntoAlien(int cause) {
+       assert(cause > 0);
+       d_cancelled = true;
+       d_cause = cause;
+       d_readAlien = true;
+}
+
+bool Reader::isCancelled() {
+       return d_cancelled;
+}
+
+INTEGER Reader::readVersion(INTEGER min, INTEGER max) {
+       INTEGER version = readByte();
+       if (version < min || version > max) {
+               turnIntoAlien(ALIENVERSION);
+       }
+       return version;
+}
+
 Store* Reader::readStore() {
        SHORTCHAR kind = readSChar();
        if (kind == Store::NIL) {
+               //std::cout << "NIL STORE" << std::endl;
                return readNilStore();
        } else if (kind == Store::LINK) {
+               //std::cout << "LINK STORE" << std::endl;
                return readLinkStore();
        } else if (kind == Store::NEWLINK) {
+               //std::cout << "NEWLINK STORE" << std::endl;
                return readNewLinkStore();
        } else if (kind == Store::STORE) {
+               //std::cout << "STORE STORE" << std::endl;
                return readStoreOrElemStore(false);
        } else if (kind == Store::ELEM) {
+               //std::cout << "ELEM STORE" << std::endl;
                return readStoreOrElemStore(true);
        } else {
+               //std::cout << std::hex << (unsigned int)kind << std::endl;
                throw 20;
        }
 }
@@ -43,7 +133,16 @@ Store* Reader::readStore() {
 //                     len, pos, pos1, id, comment, next, down, downPos, nextTypeId, nextElemId, nextStoreId: INTEGER;
 //                     kind: SHORTCHAR; path: TypePath; type: TypeName;
 //                     save: ReaderState;
+
 Store *Reader::readNilStore() {
+       INTEGER comment = readInt();
+       std::streamoff next = readInt();
+       d_state->end = d_rider.tellg();
+       if (next > 0 || (next == 0 && comment % 2 == 1)) {
+               d_state->next = d_state->end + next;
+       } else {
+               d_state->next = 0;
+       }
        return 0;
 }
 //             IF kind = nil THEN
@@ -51,16 +150,18 @@ Store *Reader::readNilStore() {
 //                     rd.st.end := rd.Pos();
 //                     IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END;
 //                     x := NIL
+
 Store *Reader::readLinkStore() {
-       return 0;
+       throw "Reader::readLinkStore() not implemented";
 }
 //             ELSIF kind = link THEN
 //                     rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next);
 //                     rd.st.end := rd.Pos();
 //                     IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END;
 //                     x := ThisStore(rd.eDict, id)
+
 Store *Reader::readNewLinkStore() {
-       return 0;
+       throw "Reader::readNewLinkStore() not implemented";
 }
 //             ELSIF kind = newlink THEN
 //                     rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next);
@@ -69,148 +170,179 @@ Store *Reader::readNewLinkStore() {
 //                     x := ThisStore(rd.sDict, id)
 
 Store *Reader::readStoreOrElemStore(bool isElem) {
-       INTEGER id = isElem ? d_nextElemId++ : d_nextStoreId++;
-       CHAR** path = newTypePath();
-       readPath(path);
-       CHAR* type = path[0];
-       std::cout << type << std::endl;
+       INTEGER id = isElem ? d_elemList.size() : d_storeList.size();
+       TypePath path = readPath();
+       //std::cout << path.toString() << std::endl;
+       const std::string &type = path[0];
        INTEGER comment = readInt();
-       return 0;
-}
-//                     ReadPath(rd, path); type := path[0];
-//                     nextTypeId := rd.nextTypeId; nextElemId := rd.nextElemId; nextStoreId := rd.nextStoreId;
-//                     rd.ReadInt(comment);
-//                     pos1 := rd.Pos();
-//                     rd.ReadInt(next); rd.ReadInt(down); rd.ReadInt(len);
-//                     pos := rd.Pos();
-//                     IF next > 0 THEN rd.st.next := pos1 + next + 4 ELSE rd.st.next := 0 END;
-//                     IF down > 0 THEN downPos := pos1 + down + 8 ELSE downPos := 0 END;
-//                     rd.st.end := pos + len;
-//                     rd.cause := 0;
-//                     ASSERT(len >= 0, 101);
-//                     IF next # 0 THEN
-//                             ASSERT(rd.st.next > pos1, 102);
-//                             IF down # 0 THEN
-//                                     ASSERT(downPos < rd.st.next, 103)
-//                             END
-//                     END;
-//                     IF down # 0 THEN
-//                             ASSERT(downPos > pos1, 104);
-//                             ASSERT(downPos < rd.st.end, 105)
-//                     END;
-//                     t := ThisType(type);
-//                     IF t # NIL THEN
-//                             x := NewStore(t); x.isElem := kind = elem
-//                     ELSE
-//                             rd.cause := thisTypeRes; AlienTypeReport(rd.cause, type);
-//                             x := NIL
-//                     END;
-//                     IF x # NIL THEN
-//                             IF SamePath(t, path) THEN
-//                                     IF kind = elem THEN
-//                                             x.id := id; AddStore(rd.eDict, rd.eHead, x)
-//                                     ELSE
-//                                             x.id := id; AddStore(rd.sDict, rd.sHead, x)
-//                                     END;
-//                                     save := rd.st; rd.cause := 0; rd.cancelled :=  FALSE;
-//                                     x.Internalize(rd);
-//                                     rd.st := save;
-//                                     IF rd.cause # 0 THEN x := NIL
-//                                     ELSIF (rd.Pos() # rd.st.end) OR rd.rider.eof THEN
-//                                             rd.cause := inconsistentVersion; AlienReport(rd.cause);
-//                                             x := NIL
-//                                     END
-//                             ELSE
+       std::streampos pos1 = d_rider.tellg();
+       std::streamoff next = readInt();
+       std::streamoff down = readInt();
+       std::streamoff len = readInt();
+       std::streampos pos = d_rider.tellg();
+       if (next > 0) {
+               d_state->next = pos1 + next + (std::streamoff)4;
+       } else {
+               d_state->next = 0;
+       }
+       int downPos = 0;
+       if (down > 0) {
+               downPos = pos1 + down + (std::streamoff)8;
+       }
+       d_state->end = pos + len;
+       d_cause = 0;
+       assert(len >= 0);
+       if (next != 0) {
+               assert(d_state->next > pos1);
+               if (down != 0) {
+                       assert(downPos < d_state->next);
+               }
+       }
+       if (down > 0) {
+               assert(downPos > pos1);
+               assert(downPos < d_state->end);
+       }
+
+       const TypeProxyBase *t = TypeRegister::getInstance().get(type); // FIXME type lookup here
+       Store *x = 0;
+       if (t != 0) {
+               x = t->newInstance(id);
+       } else {
+               d_cause = TYPENOTFOUND;
+       }
+
+       if (x != 0) { // IF READING SUCCEEDS, INSERT MORE CHECKS HERE
+               if (true) { // samePath(x, path)
+                       ReaderState *save = d_state;
+                       d_state = new ReaderState();
+                       x->internalize(*this);
+                       delete d_state;
+                       d_state = save;
+
+                       if (d_cause != 0) {
+                               x = 0;
+                       }
+                       assert(d_rider.tellg() == d_state->end);
+                       assert(!d_rider.eof());
+               } else {
 //                                     rd.cause := inconsistentType; AlienTypeReport(rd.cause, type);
-//                                     x := NIL
-//                             END
-//                     END;
-//                     
-//                     IF x # NIL THEN
-//                             IF rd.noDomain THEN
-//                                     rd.store := x;
-//                                     rd.noDomain := FALSE
-//                             ELSE
-//                                     Join(rd.store, x)
-//                             END
-//                     ELSE    (* x is an alien *)
-//                             rd.SetPos(pos);
-//                             ASSERT(rd.cause # 0, 107);
-//                             NEW(a); a.path := path; a.cause := rd.cause; a.file := rd.rider.Base();
-//                             IF rd.noDomain THEN
-//                                     rd.store := a;
-//                                     rd.noDomain := FALSE
-//                             ELSE
-//                                     Join(rd.store, a)
-//                             END;
-//                             IF kind = elem THEN
-//                                     a.id := id; AddStore(rd.eDict, rd.eHead, a)
-//                             ELSE
-//                                     a.id := id; AddStore(rd.sDict, rd.sHead, a)
-//                             END;
-//                             save := rd.st;
-//                             rd.nextTypeId := nextTypeId; rd.nextElemId := nextElemId; rd.nextStoreId := nextStoreId;
-//                             InternalizeAlien(rd, a.comps, downPos, pos, len);
-//                             rd.st := save;
-//                             x := a;
-//                             ASSERT(rd.Pos() = rd.st.end, 108);
-//                             rd.cause := 0; rd.cancelled :=  FALSE; rd.readAlien := TRUE
-//                     END
-
-void Reader::readPath(CHAR **path) {
+                       x = 0;
+               }
+       }
+
+       if (x != 0) {
+               if (d_store == 0) {
+                       d_store = x;
+               } else {
+                       // join(d_store, x)
+               }
+               if (isElem) {
+                       d_elemList.push_back(x);
+               } else {
+                       d_storeList.push_back(x);
+               }
+       } else {
+               d_rider.seekg(pos); // x->internalize() could have left us anywhere
+               assert(d_cause != 0);
+               Alien *alien = new Alien(id, path); //, d_cause); //,file
+               if (d_store == 0) {
+                       d_store = alien;
+               } else {
+                       // join(d_store, alien)
+               }
+               if (isElem) {
+                       d_elemList.push_back(alien);
+               } else {
+                       d_storeList.push_back(alien);
+               }
+               ReaderState *save = d_state;
+               d_state = new ReaderState();
+               internalizeAlien(alien, downPos, save->end);
+               delete d_state;
+               d_state = save;
+               assert(d_rider.tellg() == d_state->end);
+
+               // we've just read the alien, so reset the state
+               d_cause = 0;
+               d_cancelled = false;
+               d_readAlien = true;
+               return alien;
+       }
+
+       return x;
+}
+
+
+void Reader::internalizeAlien(Alien *alien, std::streampos down, std::streampos end) {
+       std::streampos next = down != 0 ? down : end;
+       while (d_rider.tellg() < end) {
+               if (d_rider.tellg() < next) { // for some reason, this means its a piece (unstructured)
+                       size_t len = next - d_rider.tellg();
+                       char *buf = new char[len];
+                       d_rider.read(buf, len);
+                       AlienComponent *comp = new AlienPiece(buf, len);
+                       alien->getComponents().push_back(comp);
+               } else { // that means we've got a store
+                       d_rider.seekg(next);
+                       AlienComponent *comp = new AlienPart(readStore());
+                       alien->getComponents().push_back(comp);
+                       next = d_state->next > 0 ? d_state->next : end;
+               }
+       }
+}
+
+std::string &Reader::fixTypeName(std::string &name) {
+       size_t pos = name.size() - 4;
+       if (pos > 0 && name.substr(pos, 4).compare("Desc") == 0) {
+               return name.replace(pos, 4, "^");
+       }
+       return name;
+}
+
+TypePath Reader::readPath() {
+       TypePath path;
        SHORTCHAR kind = readSChar();
-       for (int i = 0; kind == Store::NEWEXT; ++i) {
-               std::cout << "NEWEXT" << std::endl;
-               //readXString(path[i]);
-//                     AddPathComp(rd); INC(rd.nextTypeId);
+       SHORTCHAR *buf = new SHORTCHAR[64]; // TypeName has a maximum of length 64 (including terminator).
+       int i;
+       for (i = 0; kind == Store::NEWEXT; ++i) {
+               readSString(buf);
+               std::string name(buf);
+               path.push_back(fixTypeName(name));
+               addPathComponent(i == 0, path[i]);
 //                     IF path[i] # elemTName THEN INC(i) END;
-//                     rd.ReadSChar(kind)
+               kind = readSChar();
        }
 
        if (kind == Store::NEWBASE) {
-               std::cout << "NEWBASE" << std::endl;
+               readSString(buf);
+               std::string name(buf);
+               path.push_back(fixTypeName(name));
+               addPathComponent(i == 0, path[i]);
+               ++i;
        } else if (kind == Store::OLDTYPE) {
-               std::cout << "OLDTYPE" << std::endl;
+               int id = readInt();
+               if (i > 0) {
+                       d_typeList[d_typeList.size() - 1]->baseId = id;
+               }
+               while (id != -1) {
+                       path.push_back(d_typeList[id]->name);
+                       id = d_typeList[id]->baseId;
+//                             IF path[i] # elemTName THEN INC(i) END
+                       ++i;
+               }
        } else {
                throw 100;
        }
+       return path;
+}
 
-       // FIXME
-       path[0][0] = 'H';
-       path[0][1] = 'i';
-       path[0][2] = 0;
-}
-//     PROCEDURE ReadPath (VAR rd: Reader; VAR path: TypePath);
-//             VAR h: TypeDict; id, extId: INTEGER; i: INTEGER; kind: SHORTCHAR;
-//
-//             PROCEDURE AddPathComp (VAR rd: Reader);
-//             BEGIN
-//                     IF h # NIL THEN AddBaseId(h, extId, rd.nextTypeId) END;
-//                     AddType(rd.tDict, rd.tHead, rd.nextTypeId, path[i]);
-//                     h := rd.tHead; extId := rd.nextTypeId
-//             END AddPathComp;
-//
-//     BEGIN
-//             h := NIL; i := 0; rd.ReadSChar(kind);
-//             WHILE kind = newExt DO
-//                     rd.ReadXString(path[i]);
-//                     AddPathComp(rd); INC(rd.nextTypeId);
-//                     IF path[i] # elemTName THEN INC(i) END;
-//                     rd.ReadSChar(kind)
-//             END;
-//             IF kind = newBase THEN
-//                     rd.ReadXString(path[i]);
-//                     AddPathComp(rd); INC(rd.nextTypeId); INC(i)
-//             ELSE
-//                     ASSERT(kind = oldType, 100);
-//                     rd.ReadInt(id);
-//                     IF h # NIL THEN AddBaseId(h, extId, id) END;
-//                     REPEAT
-//                             GetThisType(rd.tDict, id, path[i]); id := ThisBaseId(rd.tDict, id);
-//                             IF path[i] # elemTName THEN INC(i) END
-//                     UNTIL id = -1
-//             END;
-//             path[i] := ""
-//     END ReadPath;
+void Reader::addPathComponent(bool first, const std::string &typeName) {
+       int next = d_typeList.size();
+       int curr = next - 1;
+       if (!first) {
+               d_typeList[curr]->baseId = next;
+       }
+       d_typeList.push_back(new TypeEntry(typeName));
+}
 
 } // namespace odc