lzcomp.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. //--------------------------------------------------------------------------
  2. // LZ Compress Routine
  3. //
  4. //---------------------------------------------------------------------------//
  5. // Copyright (C) Microsoft Corporation. All rights reserved. //
  6. //===========================================================================//
  7. #ifndef _MBCS
  8. #include <gameos.hpp>
  9. #ifndef HEAP_H
  10. #include "heap.h"
  11. #endif
  12. #else
  13. #include <assert.h>
  14. #include <malloc.h>
  15. #define gosASSERT assert
  16. #define gos_Malloc malloc
  17. #define gos_Free free
  18. #endif
  19. //---------------------------------------------------------------------------
  20. // Static Globals
  21. #ifndef NULL
  22. #define NULL 0
  23. #endif
  24. typedef unsigned char* MemoryPtr;
  25. //-----------------------------
  26. //Used by Compressor Routine
  27. MemoryPtr LZCHashBuf = NULL;
  28. unsigned long InBufferUpperLimit = 0;
  29. unsigned long InBufferPos = 0;
  30. MemoryPtr InBuffer = NULL;
  31. unsigned long OutBufferPos = 0;
  32. MemoryPtr OutBuffer = NULL;
  33. unsigned long PrefixCode = 0;
  34. unsigned long FreeCode = 0;
  35. unsigned long MaxCode = 0;
  36. unsigned long NBits = 0;
  37. unsigned long BitOffset = 0;
  38. unsigned char K = 0;
  39. unsigned long codeToWrite = 0;
  40. #define MaxMax 4096
  41. #define Clear 256
  42. #define EOF 257
  43. #define First_Free 258
  44. struct Hash
  45. {
  46. unsigned long hashFirst;
  47. unsigned long hashNext;
  48. unsigned char hashChar;
  49. };
  50. static unsigned char tag_LZCHashBuf[sizeof(Hash) * MaxMax + 1024];
  51. //-----------------------------
  52. //-------------------------------------------------------------------------------
  53. // LZ Compress Routine
  54. // Takes a pointer to dest buffer, a pointer to source buffer and len of source.
  55. // returns length of compressed image.
  56. long LZCompress (MemoryPtr dest, MemoryPtr src, unsigned long srcLen)
  57. {
  58. long result = 0;
  59. if (!LZCHashBuf)
  60. {
  61. /* allocating LZCHashBuf off a gos heap causes problems for applications that need
  62. to reset gos or its heaps*/
  63. LZCHashBuf = (MemoryPtr)&(tag_LZCHashBuf[0]);
  64. }
  65. //Initialize:
  66. unsigned long clearSize = sizeof(Hash) * 256;
  67. __asm
  68. {
  69. mov eax,[dest]
  70. mov [OutBufferPos],eax
  71. mov [OutBuffer],eax
  72. mov eax,[src]
  73. mov [InBufferPos],eax
  74. mov [InBuffer],eax
  75. add eax,[srcLen]
  76. mov [InBufferUpperLimit],eax
  77. mov [BitOffset],0 //zero out BitOffset
  78. //call InitTable
  79. mov [NBits],9 //Starting with 9 bit codes
  80. mov [MaxCode],512 //10 0000 0000 b
  81. mov eax,-1 //Marked as unused
  82. mov ecx,[clearSize] //Clear first 256 entries
  83. mov edi,[LZCHashBuf] //Start at the start of buffer
  84. rep stosb
  85. mov [FreeCode],First_Free //Next code to use is first_free
  86. mov eax,Clear //first byte in buffer or file is CLEAR
  87. //call writeCode
  88. xor edx,edx //make sure the DL is CLEAR
  89. mov edi,[OutBufferPos] //obtain destination address
  90. mov ecx,[BitOffset] //get bitposition
  91. jecxz save1
  92. }
  93. shift1:
  94. __asm
  95. {
  96. shl ax,1
  97. rcl edx,1
  98. loop shift1
  99. or al,[edi]
  100. }
  101. save1:
  102. __asm
  103. {
  104. stosw
  105. mov al,dl
  106. stosb
  107. //AdvanceBuffer
  108. mov ecx,[NBits] ;get number of bits to advance
  109. mov eax,[BitOffset] ;get low word of OutBuffer
  110. add eax,ecx
  111. mov cl,al
  112. shr al,3
  113. add [OutBufferPos],eax
  114. and cl,7
  115. movzx ecx,cl
  116. mov [BitOffset],ecx
  117. //-------------------------------------------------------------------------
  118. // This is the main compression loop
  119. //-------------------------------------------------------------------------
  120. //call ReadChar //get byte from source
  121. mov esi,[InBufferPos] //get address
  122. cmp esi,[InBufferUpperLimit] //Check to see if we are done
  123. cmc //compliment carry
  124. jc doneRC1
  125. lodsb //load byte
  126. mov [InBufferPos],esi
  127. clc
  128. }
  129. doneRC1:
  130. Make_Into_Code:
  131. __asm
  132. {
  133. movzx eax,al //turn char into code
  134. }
  135. //-------------------------------------------------------------------------
  136. Set_AX_Prefix:
  137. __asm
  138. {
  139. mov [PrefixCode],eax //into prefix code
  140. //call ReadChar //more...
  141. mov esi,[InBufferPos] //get address
  142. cmp esi,[InBufferUpperLimit] //Check to see if we are done
  143. cmc //compliment carry
  144. jc doneRC2
  145. lodsb //load byte
  146. mov [InBufferPos],esi
  147. clc
  148. }
  149. doneRC2:
  150. __asm
  151. {
  152. jc FoundEOF //No more input
  153. mov [K],al //Save returned char
  154. mov ebx,[PrefixCode] //check for this pair
  155. //call LookUpCode //in the table
  156. //call Index //index into current table address
  157. lea esi,[ebx*8]
  158. add esi,ebx //EBX * 9
  159. add esi,[LZCHashBuf]
  160. xor edi,edi //flag destination
  161. cmp [esi].hashFirst,-1 //see if code is used
  162. je short exit1 //if == then CARRY = CLEAR, set it
  163. inc edi //flag as used
  164. mov ebx,[esi].hashFirst //get prefix code
  165. }
  166. lookloop:
  167. __asm
  168. {
  169. //call Index //translate prefix or table to index
  170. lea esi,[ebx*8]
  171. add esi,ebx //EBX * 9
  172. add esi,[LZCHashBuf]
  173. cmp [esi].hashChar,al //is the suffix the same? if yes
  174. jne notSame //then we can compress this a
  175. clc //little more by taking this prefix
  176. mov eax,ebx //code and getting a new suffix
  177. jmp short exit2 //in a moment
  178. }
  179. notSame:
  180. __asm
  181. {
  182. cmp [esi].hashNext,-1 //found a new pattern so exit
  183. je exit1 //if == then CARRY = CLEAR, set it
  184. mov ebx,[esi].hashNext //continue through chain to get to
  185. jmp short lookloop //end of chain
  186. }
  187. exit1:
  188. __asm
  189. {
  190. stc
  191. }
  192. exit2:
  193. __asm
  194. {
  195. jnc Set_AX_Prefix //new prefix in EAX
  196. //------------------------------------------------------------------------
  197. //call AddCode //Add to table
  198. mov ebx,[FreeCode] //get the next available hash table code
  199. push ebx
  200. or edi,edi //is this first use of prefix?
  201. je short newprefix
  202. mov [esi].hashNext,ebx //if not, then set next code dest
  203. jmp short addcode
  204. }
  205. newprefix:
  206. __asm
  207. {
  208. mov [esi].hashFirst,ebx //Mark first as used
  209. }
  210. addcode:
  211. __asm
  212. {
  213. cmp ebx,MaxMax //is this the last code?
  214. je exitAC
  215. //call Index //create new entry
  216. lea esi,[ebx*8]
  217. add esi,ebx //EBX * 9
  218. add esi,[LZCHashBuf]
  219. mov [esi].hashFirst,-1 //mark new entry as unused
  220. mov [esi].hashNext,-1
  221. mov [esi].hashChar,al //and save suffix
  222. inc ebx //set up for next code available
  223. }
  224. exitAC:
  225. __asm
  226. {
  227. mov [FreeCode],ebx
  228. pop ebx
  229. }
  230. __asm
  231. {
  232. push ebx //save new code
  233. mov eax,[PrefixCode] //write the old prefix code
  234. //call writeCode
  235. xor edx,edx //make sure the DL is CLEAR
  236. mov edi,[OutBufferPos] //obtain destination address
  237. mov ecx,[BitOffset] //get bitposition
  238. jecxz save5
  239. }
  240. shift5:
  241. __asm
  242. {
  243. shl ax,1
  244. rcl edx,1
  245. loop shift5
  246. or al,[edi]
  247. }
  248. save5:
  249. __asm
  250. {
  251. stosw
  252. mov al,dl
  253. stosb
  254. //AdvanceBuffer
  255. mov ecx,[NBits] ;get number of bits to advance
  256. mov eax,[BitOffset] ;get low word of OutBuffer
  257. add eax,ecx
  258. mov cl,al
  259. shr al,3
  260. add [OutBufferPos],eax
  261. and cl,7
  262. movzx ecx,cl
  263. mov [BitOffset],ecx
  264. pop ebx //back
  265. mov al,[K]
  266. cmp ebx,[MaxCode] //exceeded size?
  267. jb Make_Into_Code //no
  268. cmp [NBits],12 //less than 12 bit encoding?
  269. jb Another_Bit //give it one more
  270. //---------------------------------------------------------------
  271. // All codes up to 12 bits are used: clear table and restart
  272. //---------------------------------------------------------------
  273. mov eax,Clear //write a clear code.....out of bits
  274. //call writeCode
  275. xor edx,edx //make sure the DL is CLEAR
  276. mov edi,[OutBufferPos] //obtain destination address
  277. mov ecx,[BitOffset] //get bitposition
  278. jecxz save2
  279. }
  280. shift2:
  281. __asm
  282. {
  283. shl ax,1
  284. rcl edx,1
  285. loop shift2
  286. or al,[edi]
  287. }
  288. save2:
  289. __asm
  290. {
  291. stosw
  292. mov al,dl
  293. stosb
  294. //AdvanceBuffer
  295. mov ecx,[NBits] ;get number of bits to advance
  296. mov eax,[BitOffset] ;get low word of OutBuffer
  297. add eax,ecx
  298. mov cl,al
  299. shr al,3
  300. add [OutBufferPos],eax
  301. and cl,7
  302. movzx ecx,cl
  303. mov [BitOffset],ecx
  304. //call InitTable //Cleanup table
  305. mov [NBits],9 //Starting with 9 bit codes
  306. mov [MaxCode],512 //10 0000 0000 b
  307. mov eax,-1 //Marked as unused
  308. mov ecx,clearSize //Clear first 256 entries
  309. mov edi,[LZCHashBuf] //Start at the start of buffer
  310. rep stosb
  311. mov [FreeCode],First_Free //Next code to use is first_free
  312. mov al,[K] //Last char
  313. jmp Make_Into_Code
  314. }
  315. //---------------------------------------------------------------
  316. // Extended bit length by a bit, adjusting Max_Code accordingly
  317. //---------------------------------------------------------------
  318. Another_Bit:
  319. __asm
  320. {
  321. inc [NBits] //one more
  322. shl [MaxCode],1 //Double it's size
  323. jmp Make_Into_Code
  324. }
  325. //----------------------------------------------------------------
  326. // No more input: flush what's left and perform housekeeping
  327. //----------------------------------------------------------------
  328. FoundEOF:
  329. __asm
  330. {
  331. mov eax,[PrefixCode] //write the last code
  332. //call writeCode
  333. xor edx,edx //make sure the DL is CLEAR
  334. mov edi,[OutBufferPos] //obtain destination address
  335. mov ecx,[BitOffset] //get bitposition
  336. jecxz save3
  337. }
  338. shift3:
  339. __asm
  340. {
  341. shl ax,1
  342. rcl edx,1
  343. loop shift3
  344. or al,[edi]
  345. }
  346. save3:
  347. __asm
  348. {
  349. stosw
  350. mov al,dl
  351. stosb
  352. //AdvanceBuffer
  353. mov ecx,[NBits] ;get number of bits to advance
  354. mov eax,[BitOffset] ;get low word of OutBuffer
  355. add eax,ecx
  356. mov cl,al
  357. shr al,3
  358. add [OutBufferPos],eax
  359. and cl,7
  360. movzx ecx,cl
  361. mov [BitOffset],ecx
  362. mov eax,EOF //write EOF code
  363. //call writeCode
  364. xor edx,edx //make sure the DL is CLEAR
  365. mov edi,[OutBufferPos] //obtain destination address
  366. mov ecx,[BitOffset] //get bitposition
  367. jecxz save4
  368. }
  369. shift4:
  370. __asm
  371. {
  372. shl ax,1
  373. rcl edx,1
  374. loop shift4
  375. or al,[edi]
  376. }
  377. save4:
  378. __asm
  379. {
  380. stosw
  381. mov al,dl
  382. stosb
  383. //AdvanceBuffer
  384. mov ecx,[NBits] ;get number of bits to advance
  385. mov eax,[BitOffset] ;get low word of OutBuffer
  386. add eax,ecx
  387. mov cl,al
  388. shr al,3
  389. add [OutBufferPos],eax
  390. and cl,7
  391. movzx ecx,cl
  392. mov [BitOffset],ecx
  393. mov eax,[BitOffset] //bits waiting to go?
  394. or eax,eax
  395. je CompressDone //no....just close things up and go back
  396. inc [OutBufferPos]
  397. }
  398. CompressDone:
  399. __asm
  400. {
  401. // return number of bytes in compressed buffer
  402. mov eax,[OutBufferPos]
  403. sub eax,[OutBuffer]
  404. mov [result],eax
  405. }
  406. return(result);
  407. }