MEMCOMPR.MOD 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. IMPLEMENTATION MODULE MemCompress;
  2. (*
  3. * REPERTOIRE
  4. * Release 1.6
  5. * By Charles Bradford and Cole Brecheen
  6. * (c) Copyright 1985-1992 PMI
  7. * Green Bay, Wisconsin
  8. * All rights reserved
  9. * (414) 468-6040
  10. *
  11. * $Header: D:/logfiles/mods/memcompr.mov 1.5 10 Mar 1991 15:29:32 coleb $
  12. *
  13. *
  14. * Written and contributed by Doug Whitfield of Hornby Island,
  15. * British Columbia.
  16. *
  17. *)
  18. IMPORT SYSTEM;
  19. IMPORT LowLevel;
  20. IMPORT VStorage;
  21. VAR
  22. Initialized : BOOLEAN;
  23. PROCEDURE Init();
  24. BEGIN
  25. IF Initialized THEN
  26. RETURN;
  27. ELSE
  28. Initialized := TRUE;
  29. END;
  30. LowLevel.Init();
  31. VStorage.Init();
  32. END Init;
  33. (* These procedures perform run-length coding compression and
  34. decompression of memory blocks. InAddress and InSize are input
  35. parameters specifing the starting address and length (in bytes)
  36. of the memory block to be compressed or decompressed. If
  37. OutAlloc is TRUE, OutAddress and OutSize are taken as input
  38. parameters by Compress and the compressed block is put at the
  39. specified location. If OutAlloc is FALSE, Compress attempts to
  40. allocate memory for the compressed block. If the allocation
  41. fails, the compression is abandoned and Compress returns the
  42. value FALSE with ErrorFlag set to AllocationFailed. If the
  43. allocation is successful, Compress returns the allocated area's
  44. address and size. The maximum size of memory block it will
  45. allocate is InSize bytes. If, during compression, the compressed
  46. block exceeds the specified OutSize (when OutAlloc is TRUE) or
  47. InSize (when OutAlloc is FALSE), the compression is abandoned and
  48. Compress returns the value FALSE, with ErrorFlag set to
  49. CompressedTooLarge. (A compressed block can exceed the size of
  50. the uncompressed block from which it is derived if the latter
  51. contains characters with ordinal value 254, as this value is used
  52. as a designator for the start of a run, and isolated occurences
  53. of this character must be translated into two successive
  54. characters to avoid ambiguity.) If compression is successfully
  55. completed, Compress returns the value TRUE with ErrorFlag set to
  56. NoCompressError.
  57. Decompress performs no error testing, and thus assumes that the
  58. size of memory specified to receive the decompressed block is
  59. sufficiently large. If Decompress is called with OutSize equal
  60. to the value of InSize used during compression, this will be
  61. true.
  62. Compress will yield a useful degree of compression if the input
  63. memory block contains runs of successive bytes containing the
  64. same value. Such may be the case, for example, in CGA and EGA
  65. graphics mode screen images. *)
  66. TYPE
  67. Address8086 =
  68. RECORD
  69. CASE : CARDINAL OF
  70. 1 :
  71. a : SYSTEM.ADDRESS;
  72. |2 :
  73. b : POINTER TO CHAR;
  74. END;
  75. END;
  76. VAR
  77. NewCharOrd, OldCharOrd, TempOutSize: CARDINAL;
  78. InCount, OutCount, RunCount, MaxRunCount, CharOrd, Index:
  79. CARDINAL;
  80. InAddress, OutAddress: SYSTEM.ADDRESS;
  81. InCharPointer, OutCharPointer: Address8086;
  82. Char: CHAR;
  83. PROCEDURE GetChar():CARDINAL;
  84. BEGIN
  85. Char := InCharPointer.b^;
  86. LowLevel.IncAddr( InCharPointer.a, 1 );
  87. INC (InCount);
  88. RETURN ORD(Char);
  89. END GetChar;
  90. PROCEDURE PutChar (CharOrd:CARDINAL);
  91. BEGIN
  92. Char := CHR (CharOrd);
  93. OutCharPointer.b^ := Char;
  94. LowLevel.IncAddr( OutCharPointer.a, 1 );
  95. INC(OutCount);
  96. END PutChar;
  97. PROCEDURE CompOut (CharOrd:CARDINAL;RunCount:CARDINAL);
  98. BEGIN
  99. IF CharOrd = 254 THEN
  100. IF RunCount > 1 THEN
  101. PutChar(254); PutChar(RunCount); PutChar(254)
  102. ELSE
  103. PutChar(254); PutChar(254)
  104. END (*IF*);
  105. ELSE
  106. IF RunCount = 1 THEN
  107. PutChar(CharOrd)
  108. ELSIF RunCount = 2 THEN
  109. PutChar(CharOrd); PutChar(CharOrd)
  110. ELSE
  111. PutChar(254); PutChar(RunCount);PutChar(CharOrd)
  112. END (*IF*);
  113. END (*IF*);
  114. END CompOut;
  115. PROCEDURE Compress (InAddress: SYSTEM.ADDRESS; InSize:CARDINAL;
  116. VAR OutAddress: SYSTEM.ADDRESS; VAR OutSize:CARDINAL;
  117. OutAlloc:BOOLEAN):BOOLEAN;
  118. BEGIN
  119. ErrorFlag := Corruption;
  120. IF NOT OutAlloc THEN
  121. IF VStorage.DosAvail (InSize + 5) THEN
  122. VStorage.DosAlloc(OutAddress, InSize + 5);
  123. TempOutSize := InSize
  124. ELSE
  125. ErrorFlag := AllocationFailed;
  126. RETURN FALSE;
  127. END;
  128. ELSE
  129. TempOutSize := OutSize
  130. END;
  131. InCharPointer.a := InAddress; OutCharPointer.a := OutAddress;
  132. InCount := 0; OutCount :=0;
  133. OldCharOrd := GetChar();
  134. LOOP
  135. RunCount := 1;
  136. MaxRunCount := InSize - InCount + 1;
  137. IF MaxRunCount > 253 THEN MaxRunCount := 253 END;
  138. LOOP
  139. NewCharOrd :=GetChar();
  140. IF NewCharOrd = OldCharOrd THEN
  141. INC (RunCount);
  142. IF RunCount = MaxRunCount THEN EXIT END
  143. ELSE
  144. EXIT
  145. END (*IF*)
  146. END (*LOOP*);
  147. CompOut (OldCharOrd,RunCount);
  148. IF OutCount >= TempOutSize THEN;
  149. IF NOT OutAlloc THEN
  150. VStorage.DosDealloc(OutAddress,InSize + 5);
  151. END;
  152. ErrorFlag := CompressedTooLarge;
  153. RETURN FALSE
  154. END;
  155. OldCharOrd := NewCharOrd;
  156. IF InCount = InSize THEN
  157. IF RunCount # MaxRunCount THEN CompOut (OldCharOrd,1) END;
  158. EXIT
  159. END (*IF*)
  160. END (*LOOP*);
  161. IF NOT OutAlloc THEN
  162. OutSize := OutCount;
  163. VStorage.DosDealloc(OutCharPointer.a,InSize + 5 - OutSize);
  164. END;
  165. ErrorFlag := NoCompressError;
  166. RETURN TRUE;
  167. END Compress;
  168. PROCEDURE Decompress (InAddress: SYSTEM.ADDRESS; InSize:CARDINAL;
  169. OutAddress: SYSTEM.ADDRESS; OutSize:CARDINAL);
  170. BEGIN
  171. InCharPointer.a := InAddress; OutCharPointer.a := OutAddress;
  172. InCount := 0; OutCount := 0;
  173. WHILE InCount < InSize DO
  174. CharOrd := GetChar();
  175. IF CharOrd = 254 THEN
  176. RunCount := GetChar();
  177. IF RunCount = 254 THEN
  178. PutChar (254)
  179. ELSE
  180. CharOrd := GetChar();
  181. FOR Index := 1 TO RunCount DO
  182. PutChar (CharOrd);
  183. END (*FOR*)
  184. END (*IF*);
  185. ELSE
  186. PutChar (CharOrd)
  187. END (*IF*)
  188. END (*WHILE*);
  189. OutSize := OutCount;
  190. END Decompress;
  191. BEGIN
  192. Initialized := FALSE;
  193. Init();
  194. END MemCompress.