DEADSOFTWARE

Finally found out how 16 bit chars are encoded
[odcread.git] / reader.cc
1 #include <reader.h>
2 #include <alien.h>
4 #include <string>
5 #include <assert.h>
7 namespace odc {
9 Reader::Reader(std::istream &rider): d_rider(rider), d_cancelled(false), d_readAlien(false), d_typeList(),
10 d_state(new ReaderState()) {}
12 SHORTCHAR Reader::readSChar() {
13 SHORTCHAR out;
14 d_rider.read(&out, 1);
15 return out;
16 }
18 void Reader::readSChar(SHORTCHAR *buf, size_t len) {
19 d_rider.read(buf, len);
20 }
22 CHAR Reader::readLChar() {
23 CHAR buf;
24 char *bufPtr = (char *)&buf;
25 d_rider.read(bufPtr, 2);
26 if (isLittleEndian()) {
27 return buf - 0x8000;
28 } else {
29 CHAR out;
30 char *outPtr = (char *)&out;
31 outPtr[0] = bufPtr[1]; outPtr[1] = bufPtr[0];
32 return out - 0x8000;
33 }
34 }
36 void Reader::readLChar(CHAR *buf, size_t len) {
37 for (int i = 0; i < len; ++i) {
38 buf[i] = readLChar();
39 }
40 /*
41 char *bufPtr = (char *)buf;
42 int len2 = len * 2;
43 d_rider.read(bufPtr, len2);
44 if (isBigEndian()) {
45 char tmp;
46 for (int i = 0; i < len2; i += 2) {
47 tmp = bufPtr[i];
48 bufPtr[i] = bufPtr[i + 1];
49 bufPtr[i + 1] = tmp;
50 }
51 }
52 */
53 }
55 BYTE Reader::readByte() {
56 BYTE out;
57 d_rider.read((char*)&out, 1);
58 return out;
59 }
61 SHORTINT Reader::readSInt() {
62 SHORTINT buf;
63 char *bufPtr = (char*)&buf;
64 d_rider.read(bufPtr, 2);
65 if (isLittleEndian()) {
66 return buf;
67 } else {
68 SHORTINT out;
69 char *outPtr = (char *)&out;
70 outPtr[0] = bufPtr[1]; outPtr[1] = bufPtr[0];
71 return out;
72 }
73 }
75 INTEGER Reader::readInt() {
76 INTEGER buf;
77 char *bufPtr = (char*)&buf;
78 d_rider.read(bufPtr, 4);
79 if (isLittleEndian()) {
80 return buf;
81 } else {
82 INTEGER out;
83 char *outPtr = (char *)&out;
84 outPtr[0] = bufPtr[3]; outPtr[1] = bufPtr[2]; outPtr[2] = bufPtr[1]; outPtr[3] = bufPtr[0];
85 return out;
86 }
87 }
89 void Reader::readSString(SHORTCHAR *out) {
90 while (*out = readSChar()) {
91 ++out;
92 }
93 }
95 void Reader::turnIntoAlien(int cause) {
96 assert(cause > 0);
97 d_cancelled = true;
98 d_cause = cause;
99 d_readAlien = true;
102 bool Reader::isCancelled() {
103 return d_cancelled;
106 INTEGER Reader::readVersion(INTEGER min, INTEGER max) {
107 INTEGER version = readByte();
108 if (version < min || version > max) {
109 turnIntoAlien(ALIENVERSION);
111 return version;
114 Store* Reader::readStore() {
115 SHORTCHAR kind = readSChar();
116 if (kind == Store::NIL) {
117 //std::cout << "NIL STORE" << std::endl;
118 return readNilStore();
119 } else if (kind == Store::LINK) {
120 //std::cout << "LINK STORE" << std::endl;
121 return readLinkStore();
122 } else if (kind == Store::NEWLINK) {
123 //std::cout << "NEWLINK STORE" << std::endl;
124 return readNewLinkStore();
125 } else if (kind == Store::STORE) {
126 //std::cout << "STORE STORE" << std::endl;
127 return readStoreOrElemStore(false);
128 } else if (kind == Store::ELEM) {
129 //std::cout << "ELEM STORE" << std::endl;
130 return readStoreOrElemStore(true);
131 } else {
132 //std::cout << std::hex << (unsigned int)kind << std::endl;
133 throw 20;
136 // PROCEDURE (VAR rd: Reader) ReadStore* (OUT x: Store), NEW;
137 // VAR a: Alien; t: Kernel.Type;
138 // len, pos, pos1, id, comment, next, down, downPos, nextTypeId, nextElemId, nextStoreId: INTEGER;
139 // kind: SHORTCHAR; path: TypePath; type: TypeName;
140 // save: ReaderState;
142 Store *Reader::readNilStore() {
143 INTEGER comment = readInt();
144 std::streamoff next = readInt();
145 d_state->end = d_rider.tellg();
146 if (next > 0 || (next == 0 && comment % 2 == 1)) {
147 d_state->next = d_state->end + next;
148 } else {
149 d_state->next = 0;
151 return 0;
153 // IF kind = nil THEN
154 // rd.ReadInt(comment); rd.ReadInt(next);
155 // rd.st.end := rd.Pos();
156 // IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END;
157 // x := NIL
159 Store *Reader::readLinkStore() {
160 throw "Reader::readLinkStore() not implemented";
162 // ELSIF kind = link THEN
163 // rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next);
164 // rd.st.end := rd.Pos();
165 // IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END;
166 // x := ThisStore(rd.eDict, id)
168 Store *Reader::readNewLinkStore() {
169 throw "Reader::readNewLinkStore() not implemented";
171 // ELSIF kind = newlink THEN
172 // rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next);
173 // rd.st.end := rd.Pos();
174 // IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END;
175 // x := ThisStore(rd.sDict, id)
177 Store *Reader::readStoreOrElemStore(bool isElem) {
178 INTEGER id = isElem ? d_elemList.size() : d_storeList.size();
179 TypePath path = readPath();
180 //std::cout << path.toString() << std::endl;
181 const std::string &type = path[0];
182 INTEGER comment = readInt();
183 std::streampos pos1 = d_rider.tellg();
184 std::streamoff next = readInt();
185 std::streamoff down = readInt();
186 std::streamoff len = readInt();
187 std::streampos pos = d_rider.tellg();
188 if (next > 0) {
189 d_state->next = pos1 + next + (std::streamoff)4;
190 } else {
191 d_state->next = 0;
193 int downPos = 0;
194 if (down > 0) {
195 downPos = pos1 + down + (std::streamoff)8;
197 d_state->end = pos + len;
198 d_cause = 0;
199 assert(len >= 0);
200 if (next != 0) {
201 assert(d_state->next > pos1);
202 if (down != 0) {
203 assert(downPos < d_state->next);
206 if (down > 0) {
207 assert(downPos > pos1);
208 assert(downPos < d_state->end);
211 const TypeProxyBase *t = TypeRegister::getInstance().get(type); // FIXME type lookup here
212 Store *x = 0;
213 if (t != 0) {
214 x = t->newInstance(id);
215 } else {
216 d_cause = TYPENOTFOUND;
219 if (x != 0) { // IF READING SUCCEEDS, INSERT MORE CHECKS HERE
220 if (true) { // samePath(x, path)
221 ReaderState *save = d_state;
222 d_state = new ReaderState();
223 x->internalize(*this);
224 delete d_state;
225 d_state = save;
227 if (d_cause != 0) {
228 x = 0;
230 assert(d_rider.tellg() == d_state->end);
231 assert(!d_rider.eof());
232 } else {
233 // rd.cause := inconsistentType; AlienTypeReport(rd.cause, type);
234 x = 0;
238 if (x != 0) {
239 if (d_store == 0) {
240 d_store = x;
241 } else {
242 // join(d_store, x)
244 if (isElem) {
245 d_elemList.push_back(x);
246 } else {
247 d_storeList.push_back(x);
249 } else {
250 d_rider.seekg(pos); // x->internalize() could have left us anywhere
251 assert(d_cause != 0);
252 Alien *alien = new Alien(id, path); //, d_cause); //,file
253 if (d_store == 0) {
254 d_store = alien;
255 } else {
256 // join(d_store, alien)
258 if (isElem) {
259 d_elemList.push_back(alien);
260 } else {
261 d_storeList.push_back(alien);
263 ReaderState *save = d_state;
264 d_state = new ReaderState();
265 internalizeAlien(alien, downPos, save->end);
266 delete d_state;
267 d_state = save;
268 assert(d_rider.tellg() == d_state->end);
270 // we've just read the alien, so reset the state
271 d_cause = 0;
272 d_cancelled = false;
273 d_readAlien = true;
274 return alien;
277 return x;
281 void Reader::internalizeAlien(Alien *alien, std::streampos down, std::streampos end) {
282 std::streampos next = down != 0 ? down : end;
283 while (d_rider.tellg() < end) {
284 if (d_rider.tellg() < next) { // for some reason, this means its a piece (unstructured)
285 size_t len = next - d_rider.tellg();
286 char *buf = new char[len];
287 d_rider.read(buf, len);
288 AlienComponent *comp = new AlienPiece(buf, len);
289 alien->getComponents().push_back(comp);
290 } else { // that means we've got a store
291 d_rider.seekg(next);
292 AlienComponent *comp = new AlienPart(readStore());
293 alien->getComponents().push_back(comp);
294 next = d_state->next > 0 ? d_state->next : end;
299 std::string &Reader::fixTypeName(std::string &name) {
300 size_t pos = name.size() - 4;
301 if (pos > 0 && name.substr(pos, 4).compare("Desc") == 0) {
302 return name.replace(pos, 4, "^");
304 return name;
307 TypePath Reader::readPath() {
308 TypePath path;
309 SHORTCHAR kind = readSChar();
310 SHORTCHAR *buf = new SHORTCHAR[64]; // TypeName has a maximum of length 64 (including terminator).
311 int i;
312 for (i = 0; kind == Store::NEWEXT; ++i) {
313 readSString(buf);
314 std::string name(buf);
315 path.push_back(fixTypeName(name));
316 addPathComponent(i == 0, path[i]);
317 // IF path[i] # elemTName THEN INC(i) END;
318 kind = readSChar();
321 if (kind == Store::NEWBASE) {
322 readSString(buf);
323 std::string name(buf);
324 path.push_back(fixTypeName(name));
325 addPathComponent(i == 0, path[i]);
326 ++i;
327 } else if (kind == Store::OLDTYPE) {
328 int id = readInt();
329 if (i > 0) {
330 d_typeList[d_typeList.size() - 1]->baseId = id;
332 while (id != -1) {
333 path.push_back(d_typeList[id]->name);
334 id = d_typeList[id]->baseId;
335 // IF path[i] # elemTName THEN INC(i) END
336 ++i;
338 } else {
339 throw 100;
341 return path;
344 void Reader::addPathComponent(bool first, const std::string &typeName) {
345 int next = d_typeList.size();
346 int curr = next - 1;
347 if (!first) {
348 d_typeList[curr]->baseId = next;
350 d_typeList.push_back(new TypeEntry(typeName));
353 } // namespace odc