home *** CD-ROM | disk | FTP | other *** search
- Unit Storage;
-
- { STORAGE.PAS - 13 Jan 91
-
- This unit was created to replace the original system storage that was
- created for the DMG. It is designed to be object oriented and will
- also alow for external compression routines to be designed into the
- system with a registration code for each.
-
- The system will take a buffer pointer and run it through the compressor
- until it reaches a NULL (0) character in the buffer. This limits you
- to storing only readable messages. Once the compressor is finished,
- the resulting bitstream is then written to the disk. An index number
- is returned for where this was written.
-
- The system that reads the messages only needs an index and filename.
- It will create a buffer for the message up to the memory restraints.
-
- You MUST do a .done when you are through with the buffer or the space
- will not be released to the heap.
-
- NOTES:
- The compression algorythm on this system is VERY rudimentary and is
- designed for text only type of material. It strips all spaces out of
- your text and compresses the next character with 128. This generally
- saves around 20% storage of a typical text file. The other change
- is to do the same with the lower case 'e' character. This is then
- combined with a 64. Between the two you get around %30 compression
- on your text files... Pretty nifty...
-
- Note that there is no modifications or remaps of any character ranging
- from 000..159. This is so that you can take a standard FIDO file and
- read it without remapping the soft carriage returns and linefeeds
- (8D and 8A).
-
- }
-
- {$F+,O+,S-,R-}
-
- Interface
-
- Uses Dos, Objects;
-
- CONST stStoreError = -120;
- stStoreReadErr = 197;
- stStoreWriteErr = 198;
- stStoreUnknownErr = 199;
-
- TYPE PBuffer = ^BBuffer;
- BBuffer = ARRAY [0..65530] OF BYTE;
- PCharBuf = ^CharBuf;
- CharBuf = ARRAY [0..65530] OF CHAR;
-
- TYPE PList = ^LList;
- LList = RECORD
- OldItem : LONGINT;
- NewItem : LONGINT;
- Next : PList;
- END;
-
- TYPE PStorage = ^TStorage;
- TStorage = OBJECT(TBufStream)
- SFileName : FNameStr;
- SCleanName : FNameStr;
- SCleanIndex : PList;
- SMode : WORD;
- SIndex : LONGINT;
- SHoldBuf : POINTER;
- SHoldBufLen : WORD;
- CONSTRUCTOR Init(AFileName : FNameStr; AMode, Size : WORD);
- PROCEDURE WriteMsg(VAR Buf);
- PROCEDURE ReadMsg(VAR Buf : PCharBuf; Index : LONGINT);
- PROCEDURE DeleteMsg(Index : LONGINT);
- PROCEDURE CleanUpMsg;
- FUNCTION NewIndex(Index : LONGINT) : LONGINT;
- PROCEDURE DeleteCleanUp;
- PROCEDURE Compress(VAR Buf); VIRTUAL;
- PROCEDURE DeCompress(VAR Buf); VIRTUAL;
- DESTRUCTOR Done; VIRTUAL;
- END;
-
- Implementation
-
- CONST MarkerWord = $93D2;
- RegBasicComp : BYTE = $01;
-
- VAR ExpandSize : WORD;
- CompressSize : WORD;
- Marker : WORD;
-
- {----------------------------------------------------------------------------}
-
- CONSTRUCTOR TStorage.Init;
- BEGIN
- TBufStream.Init(AFileName,AMode,Size);
- IF Status <> stOk THEN
- Status := stStoreError
- ELSE
- BEGIN
- SFileName := FEXPAND(AFileName);
- SCleanName := '';
- SCleanIndex := NIL;
- SMode := AMode;
- SIndex := 0;
- SHoldBuf := NIL;
- SHoldBufLen := 0
- END
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.WriteMsg;
- VAR WritePosn : WORD;
- p : PBuffer;
- BEGIN
- p := PBuffer(@Buf);
- SIndex := GetSize;
- TBufStream.Seek(SIndex);
- Marker := MarkerWord;
- TBufStream.Write(Marker,SIZEOF(Marker));
- ExpandSize := 0;
- WHILE (p^[ExpandSize] <> 0) DO
- INC(ExpandSize);
- TBufStream.Write(ExpandSize,SIZEOF(ExpandSize));
- Compress(Buf);
- CompressSize := 0;
- WHILE (p^[CompressSize] <> 0) DO
- INC(CompressSize);
- TBufStream.Write(CompressSize,SIZEOF(CompressSize));
- WritePosn := 0;
- WHILE WritePosn < CompressSize DO
- IF CompressSize - WritePosn > BufSize THEN
- BEGIN
- TBufStream.Write(p^[WritePosn],BufSize);
- INC(WritePosn,BufSize)
- END
- ELSE
- BEGIN
- TBufStream.Write(p^[WritePosn],CompressSize - WritePosn);
- WritePosn := CompressSize
- END;
- Flush;
- IF Status <> stOk THEN
- Status := stStoreError
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.ReadMsg;
- VAR DeleteCheck : BYTE;
- BEGIN
- IF (SHoldBuf <> NIL) AND (SHoldBufLen > 0) THEN
- BEGIN
- FREEMEM(SHoldBuf,SHoldBufLen);
- SHoldBuf := NIL;
- SHoldBufLen := 0
- END;
- Seek(Index);
- Read(Marker,SIZEOF(Marker));
- IF Marker = MarkerWord THEN
- BEGIN
- Read(ExpandSize,SIZEOF(ExpandSize));
- Read(CompressSize,SIZEOF(CompressSize));
- END
- ELSE
- BEGIN
- Seek(Index);
- ExpandSize := GetSize - Index;
- IF ExpandSize >= SIZEOF(CharBuf) THEN
- ExpandSize := SIZEOF(CharBuf) - 1;
- CompressSize := ExpandSize
- END;
- Read(DeleteCheck,1);
- IF (DeleteCheck < $FF) OR (Marker <> MarkerWord) THEN
- BEGIN
- SHoldBufLen := ExpandSize + 1;
- GETMEM(SHoldBuf,SHoldBufLen);
- FILLCHAR(SHoldBuf^,SHoldBufLen,0);
- BBuffer(SHoldBuf^)[0] := DeleteCheck;
- Read(BBuffer(SHoldBuf^)[1],CompressSize - 1);
- IF Marker = MarkerWord THEN
- DeCompress(SHoldBuf^);
- END
- ELSE
- BEGIN
- SHoldBufLen := 1;
- GETMEM(SHoldBuf,1);
- BBuffer(SHoldBuf^)[0] := 0;
- Error(stStoreError,stStoreReadErr) {Disk Read Error}
- END;
- PCharBuf(Buf) := @SholdBuf^;
- IF Status <> stOk THEN
- Status := stStoreError
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.DeleteMsg;
- VAR CompressType : BYTE;
- BEGIN
- Seek(Index);
- Read(Marker,SIZEOF(Marker));
- IF Marker = MarkerWord THEN
- BEGIN
- Seek(Index + SIZEOF(Marker) + SIZEOF(ExpandSize) + SIZEOF(CompressSize));
- CompressType := $FF; {Mark Compression Type as Deleted!}
- Write(CompressType,SIZEOF(CompressType))
- END;
- IF Status <> stOk THEN
- Status := stStoreError
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.CleanUpMsg;
- VAR Dir : DirStr;
- FName : NameStr;
- Ext : ExtStr;
- T : TBufStream;
- TmpPtr : POINTER;
- TFile : FILE;
- OldItem : LONGINT;
- NewItem : LONGINT;
- LinkPtr : PList;
- BEGIN
- FSplit(SFileName,Dir,FName,Ext);
- SCleanName := Dir + FName + '.$$$';
- T.Init(SCleanName,stCreate,1024);
- Seek(0);
- OldItem := 0;
- WHILE OldItem < GetSize - 1 DO BEGIN
- Read(Marker,SIZEOF(Marker));
- IF Marker <> MarkerWord THEN
- Error(stStoreError,stStoreUnknownErr);
- Read(ExpandSize,SIZEOF(ExpandSize));
- Read(CompressSize,SIZEOF(CompressSize));
- GETMEM(TmpPtr,CompressSize);
- Read(TmpPtr^,CompressSize);
- IF (Status = stOk) AND (BBuffer(TmpPtr^)[0] < $FF) THEN
- BEGIN
- NewItem := T.GetPos;
- T.Write(Marker,SIZEOF(Marker));
- T.Write(ExpandSize,SIZEOF(ExpandSize));
- T.Write(CompressSize,SIZEOF(CompressSize));
- T.Write(TmpPtr^,CompressSize);
- GETMEM(LinkPtr,SIZEOF(LList));
- LinkPtr^.OldItem := OldItem;
- LinkPtr^.NewItem := NewItem;
- LinkPtr^.Next := SCleanIndex;
- SCleanIndex := LinkPtr
- END;
- FREEMEM(TmpPtr,CompressSize);
- OldItem := GetPos
- END;
- T.Done;
- IF Status <> stOk THEN
- BEGIN
- ASSIGN(TFile,SCleanName);
- ERASE(TFile);
- SCleanName := '';
- Status := stStoreError
- END
- END;
-
- {----------------------------------------------------------------------------}
-
- FUNCTION TStorage.NewIndex;
- VAR PLink : PList;
- BEGIN
- PLink := SCleanIndex;
- NewIndex := -1;
- WHILE (PLink <> NIL) AND (PLink^.OldItem <> Index) DO
- PLink := PLink^.Next;
- IF (PLink <> NIL) AND (PLink^.OldItem = Index) THEN
- NewIndex := PLink^.NewItem
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.DeleteCleanUp;
- VAR TFile : FILE;
- PLink : PList;
- BEGIN
- IF SCleanName <> '' THEN
- BEGIN
- {$I-} ASSIGN(TFile,SCleanName);
- ERASE(TFile); {$I+}
- ErrorInfo := IOResult;
- IF ErrorInfo <> stOk THEN
- Status := stStoreError;
- SCleanName := '';
- WHILE SCleanIndex <> NIL DO BEGIN
- PLink := SCleanIndex;
- SCleanIndex := PLink^.Next;
- FREEMEM(PLink,SIZEOF(LList))
- END
- END
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.Compress;
- VAR p : PBuffer;
- ReadPosn : WORD;
- WritePosn : WORD;
- SpaceCount : WORD;
- BEGIN
- p := PBuffer(@Buf);
- ReadPosn := 0;
- WritePosn := 0;
- WHILE (p^[ReadPosn] <> 0) AND (ReadPosn < 65530) DO BEGIN
- SpaceCount := 0;
- WHILE (p^[ReadPosn + SpaceCount] = 32) DO
- INC(SpaceCount);
- IF SpaceCount > 1 THEN
- BEGIN
- INC(ReadPosn,SpaceCount);
- WHILE SpaceCount > 0 DO
- IF SpaceCount > 255 THEN
- BEGIN
- p^[WritePosn] := 255;
- p^[WritePosn + 1] := 255;
- INC(WritePosn,2);
- DEC(SpaceCount,255)
- END
- ELSE
- BEGIN
- p^[WritePosn] := 255;
- p^[WritePosn + 1] := SpaceCount;
- INC(WritePosn,2);
- SpaceCount := 0
- END;
- SpaceCount := 2
- END;
- IF SpaceCount = 1 THEN
- IF (p^[ReadPosn + 1] >= 64) AND (p^[ReadPosn + 1] <= 127) THEN
- BEGIN
- p^[WritePosn] := p^[ReadPosn + 1] + 128;
- INC(WritePosn);
- INC(ReadPosn,2)
- END
- ELSE
- SpaceCount := 0;
- IF SpaceCount = 0 THEN
- BEGIN
- IF p^[ReadPosn + 1] = 101 THEN
- BEGIN
- p^[WritePosn] := p^[ReadPosn] + 64;
- INC(ReadPosn,2)
- END
- ELSE
- BEGIN
- p^[WritePosn] := p^[ReadPosn];
- INC(ReadPosn)
- END;
- INC(WritePosn)
- END
- END;
- p^[WritePosn] := 0;
- MOVE(p^[0],p^[1],WritePosn + 1);
- p^[0] := RegBasicComp
- END;
-
- {----------------------------------------------------------------------------}
-
- PROCEDURE TStorage.DeCompress;
- VAR p : PBuffer;
- ReadPosn : WORD;
- Count : WORD;
- Total : WORD;
- BEGIN
- p := PBuffer(@Buf);
- ReadPosn := 0;
- Total := 0;
- WHILE (p^[Total + 1] <> 0) DO
- INC(Total);
- IF p^[0] = RegBasicComp THEN
- BEGIN
- MOVE(p^[1],p^[0],Total);
- p^[Total] := 0;
- WHILE (p^[ReadPosn] <> 0) AND (ReadPosn < SholdBufLen) DO BEGIN
- CASE p^[ReadPosn] OF
- 255 : BEGIN
- Count := p^[ReadPosn + 1];
- MOVE(p^[ReadPosn + 2],p^[ReadPosn + Count],SHoldBufLen - ReadPosn - 2);
- FILLCHAR(p^[ReadPosn],Count,32);
- INC(ReadPosn,Count)
- END;
- 192..254 : BEGIN
- MOVE(p^[ReadPosn],p^[ReadPosn + 1],SHoldBufLen - ReadPosn);
- p^[ReadPosn] := 32;
- DEC(p^[ReadPosn + 1],128);
- INC(ReadPosn,2)
- END;
- 160..191 : BEGIN
- MOVE(p^[ReadPosn],p^[ReadPosn + 1],SHoldBufLen - ReadPosn);
- p^[ReadPosn + 1] := 101;
- DEC(p^[ReadPosn],64);
- INC(ReadPosn,2)
- END;
-
- 000..159 : INC(ReadPosn)
- END
- END
- END
- END;
-
- {----------------------------------------------------------------------------}
-
- DESTRUCTOR TStorage.Done;
- VAR TFile : FILE;
- PLink : PList;
- BEGIN
- IF (SHoldBuf <> NIL) AND (SHoldBufLen > 0) THEN
- FREEMEM(SHoldBuf,SHoldBufLen);
- TBufStream.Done;
- IF SCleanName <> '' THEN
- BEGIN
- ASSIGN(TFile,SFileName);
- ERASE(TFile);
- ASSIGN(TFile,SCleanName);
- RENAME(TFile,SFileName);
- SCleanName := ''
- END;
- WHILE SCleanIndex <> NIL DO BEGIN
- PLink := SCleanIndex;
- SCleanIndex := PLink^.Next;
- FREEMEM(PLink,SIZEOF(LList))
- END
-
- END;
-
- {----------------------------------------------------------------------------}
-
- END.