MODULE DswDocuments; IMPORT SYSTEM, Kernel, Files; (* !!! make better store type and version checking *) TYPE Name = ARRAY 256 OF SHORTCHAR; ShortString = POINTER TO ARRAY OF SHORTCHAR; String = POINTER TO ARRAY OF CHAR; Store = RECORD (* type: Name; *) next, down, len: INTEGER; pos, end: INTEGER; isElem: BOOLEAN; END; Model* = POINTER TO ABSTRACT RECORD END; Reader* = POINTER TO ABSTRACT RECORD eot*: BOOLEAN; char*: CHAR; END; StdModel = POINTER TO RECORD (Model) str: String; len: INTEGER END; StdReader = POINTER TO RECORD (Reader) base: StdModel; i: INTEGER END; VAR oldReader: Files.Reader; PROCEDURE (m: Model) NewReader* (old: Reader): Reader, NEW, ABSTRACT; PROCEDURE (m: Model) Length* (): INTEGER, NEW, ABSTRACT; PROCEDURE (r: Reader) Base* (): Model, NEW, ABSTRACT; PROCEDURE (r: Reader) Pos* (): INTEGER, NEW, ABSTRACT; PROCEDURE (r: Reader) SetPos* (pos: INTEGER), NEW, ABSTRACT; PROCEDURE (r: Reader) Read*, NEW, ABSTRACT; PROCEDURE (r: Reader) ReadPrev*, NEW, ABSTRACT; PROCEDURE (m: StdModel) NewReader (old: Reader): StdReader; VAR r: StdReader; BEGIN IF (old # NIL) & (old IS StdReader) THEN r := old(StdReader) ELSE NEW(r) END; r.eot := FALSE; r.char := 0X; r.base := m; r.i := 0; RETURN r END NewReader; PROCEDURE (m: StdModel) Length (): INTEGER; BEGIN RETURN m.len END Length; PROCEDURE (r: StdReader) Base (): StdModel; BEGIN RETURN r.base END Base; PROCEDURE (r: StdReader) Pos (): INTEGER; BEGIN RETURN r.i END Pos; PROCEDURE (r: StdReader) SetPos (pos: INTEGER); BEGIN ASSERT(pos >= 0, 20); ASSERT(pos <= r.base.len, 21); r.i := pos END SetPos; PROCEDURE (r: StdReader) Read; BEGIN IF r.i < r.base.len THEN r.char := r.base.str[r.i]; r.eot := FALSE; INC(r.i) ELSE r.char := 0X; r.eot := TRUE END END Read; PROCEDURE (r: StdReader) ReadPrev; BEGIN IF r.i > 0 THEN DEC(r.i); r.char := r.base.str[r.i]; r.eot := FALSE ELSE r.char := 0X; r.eot := TRUE END END ReadPrev; PROCEDURE Import* (loc: Files.Locator; IN name: Files.Name; OUT m: Model; OUT res: INTEGER); CONST docTag = 6F4F4443H; docVersion = 0; Step = 256; VAR f: Files.File; r: Files.Reader; tag, version, chid: INTEGER; s: Store; text: StdModel; PROCEDURE AddChar (ch: CHAR); VAR i, len: INTEGER; t: String; BEGIN IF text = NIL THEN NEW(text); NEW(text.str, Step); chid := 0 END; len := LEN(text.str); IF chid + 1 >= len THEN NEW(t, len + Step); t^ := text.str$; text.str := t; END; text.str[chid] := ch; INC(chid); text.str[chid] := 0X; text.len := chid END AddChar; PROCEDURE ReadSChar (OUT x: SHORTCHAR); VAR i: BYTE; BEGIN r.ReadByte(i); x := SHORT(CHR(i MOD 256)) END ReadSChar; PROCEDURE ReadInt (OUT x: INTEGER); VAR i: ARRAY 4 OF BYTE; BEGIN r.ReadBytes(i, 0, 4); x := i[0] MOD 256 + i[1] MOD 256 * 256 + i[2] MOD 256 * 65536 + i[3] MOD 256 * 16777216 END ReadInt; PROCEDURE ReadBool (OUT x: BOOLEAN); VAR i: SHORTCHAR; BEGIN ReadSChar(i); x := i # 0X END ReadBool; PROCEDURE ReadStore (OUT s: Store); CONST storeVersion = 0X; newBase = 0F0X; newExt = 0F1X; oldType = 0F2X; nil = 80X; link = 81X; store = 82X; elem = 83X; newlink = 84X; elemTName = "Stores.ElemDesc"; modelTName = "Models.ModelDesc"; (* from pre-1.3 *) VAR tag, version, ch: SHORTCHAR; i, x: INTEGER; BEGIN ReadSChar(tag); s.isElem := tag = elem; ASSERT((tag = store) OR (tag = elem), 100); ReadSChar(tag); WHILE tag = newExt DO REPEAT ReadSChar(ch) UNTIL ch = 0X; ReadSChar(tag) END; IF tag = newBase THEN (* !!! get base types *) REPEAT ReadSChar(ch) UNTIL ch = 0X; ELSIF tag = oldType THEN ReadInt(x) (* !!! get from dictionary *) ELSE HALT(102) END; ReadInt(x); (* extension hook = 00000000 *) ReadInt(s.next); s.next := s.next + r.Pos(); ReadInt(s.down); s.down := s.down + r.Pos(); ReadInt(s.len); s.pos := r.Pos(); s.end := s.pos + s.len; ReadSChar(version); (* version *) ASSERT(version = storeVersion, 103); IF s.isElem THEN ReadSChar(version); ASSERT(version = storeVersion, 104) END END ReadStore; PROCEDURE ReadStdTextModel; CONST dictSize = 32; noLCharStdModelVersion = 0; stdModelVersion = 1; VAR s: Store; version, ano: BYTE; org, len, dictlen, i, w, h: INTEGER; R: Files.Reader; x: ARRAY 2 OF BYTE; ch: CHAR; BEGIN r.ReadByte(version); IF version IN {noLCharStdModelVersion, stdModelVersion} THEN ReadInt(org); org := org + r.Pos(); R := f.NewReader(NIL); R.SetPos(org); r.ReadByte(ano); dictlen := 0; WHILE ano # -1 DO IF ano = dictlen THEN ReadStore(s); r.SetPos(s.end); (* attr IS TextModels.AttributesDesc *) IF dictlen < dictSize THEN (* dictattr[dictlen] := attr *) INC(dictlen) END ELSE (* attr := dictattr[ano] *) END; ReadInt(len); IF len > 0 THEN (* pice *) FOR i := 0 TO len - 1 DO R.ReadByte(x[0]); ch := CHR(x[0] MOD 256); AddChar(ch) END ELSIF len < 0 THEN (* longchar pice *) ASSERT(len MOD 2 = 0); FOR i := 0 TO (-len) DIV 2 - 1 DO R.ReadBytes(x, 0, 2); ch := CHR(x[0] MOD 256 + x[1] MOD 256 * 256); AddChar(ch) END ELSE (* len = 0 => embedded view *) ReadInt(w); ReadInt(h); R.ReadByte(x[0]); (* viewcode!!! *) AddChar(02X); ReadStore(s); r.SetPos(s.end) (* random view type *) END; r.ReadByte(ano) END; m := text; res := 0 (* ok *) ELSE res := 4 (* unsupported text model version *) END END ReadStdTextModel; PROCEDURE ReadTextModel; CONST modelVersion = 0; conteinerVersion = 0; textModelVersion = 0; VAR s: Store; version: BYTE; BEGIN ReadStore(s); IF TRUE (*s.type = "TextModels.StdModelDesc"*) THEN r.ReadByte(version); IF version = modelVersion THEN (* Models.Model *) r.ReadByte(version); IF version = conteinerVersion THEN (* Containers.Container *) r.ReadByte(version); IF version = textModelVersion THEN (* TextModels.Model *) ReadStdTextModel ELSE res := 4 (* unsupported text model version *) END ELSE res := 4 (* unsupported text model version *) END ELSE res := 4 (* unsupported text model version *) END ELSE res := 3 (* unsupported version *) END END ReadTextModel; PROCEDURE ReadDocument; VAR s: Store; BEGIN ReadStore(s); IF TRUE (*s.type = "Documents.StdDocumentDesc"*) THEN r.SetPos(s.down); (* !!! *) ReadStore(s); IF TRUE (*s.type = "Documents.ModelDesc"*) THEN r.SetPos(s.down); (* !!! *) ReadStore(s); IF TRUE (*s.type = "TextViews.StdViewDesc"*) THEN r.SetPos(s.down); (* !!! *) ReadTextModel ELSE res := 3 (* unsupported version *) END ELSE res := 3 (* unsupported version *) END ELSE res := 3 (* unsupported version *) END END ReadDocument; BEGIN ASSERT(loc # NIL, 20); ASSERT(name # "", 21); m := NIL; res := 0; f := Files.dir.Old(loc, name, Files.shared); IF f # NIL THEN IF f.Length() > 8 THEN (* !!! calculate minimal document size *) r := f.NewReader(NIL); ReadInt(tag); IF tag = docTag THEN ReadInt(version); IF version = docVersion THEN ReadDocument; f.Close ELSE f.Close; res := 3 (* unsupported version *) END ELSE f.Close; res := 2 (* not document *) END ELSE f.Close; res := 2 (* not document *) END ELSE res := 1 (* unable to open *) END END Import; PROCEDURE Open* (loc: Files.Locator; IN name: Files.Name; OUT m: Model; OUT res: INTEGER); VAR f: Files.File; r: Files.Reader; len: INTEGER; s: ShortString; l: String; text: StdModel; BEGIN m := NIL; res := 0; Import(loc, name, m, res); IF res = 2 THEN f := Files.dir.Old(loc, name, Files.shared); IF f # NIL THEN len := f.Length(); r := f.NewReader(oldReader); oldReader := r; r.SetPos(0); NEW(s, len + 1); r.ReadBytes(SYSTEM.THISARRAY(SYSTEM.ADR(s[0]), len + 1), 0, len); NEW(l, len + 1); Kernel.Utf8ToString(s, l, res); IF res = 0 THEN NEW(text); text.str := l; text.len := LEN(text.str$); m := text; res := 0 (* ok *) ELSE res := 5 (* broken encoding *) END; f.Close ELSE res := 1 (* unable to open *) END END END Open; END DswDocuments.