unpack.asm
上传用户:xiaoan1112
上传日期:2013-04-11
资源大小:19621k
文件大小:14k
源码类别:

操作系统开发

开发平台:

Visual C++

  1. COMMENT #
  2. UNPACK.ASM
  3. Copyright (c) 1991 - Microsoft Corp.
  4. All rights reserved.
  5. Microsoft Confidential
  6. Functions for uncompressing an LZ compressed buffer.
  7. Created 11-28-89 johnhe
  8. TABS = 7
  9. END_COMMENT #
  10. RING_BUF_LEN EQU 4096
  11. UNPB_BUF_LEN EQU (512 * 17)
  12. INDEX_LEN EQU 2
  13. WIN_MAX_STR_LEN EQU 16
  14. LANG_MAX_STR_LEN EQU (16 + INDEX_LEN)
  15. MAX_STR_LEN EQU (LANG_MAX_STR_LEN + 2)
  16. LANGUAGE_COMPRESS EQU 1
  17. WINDOWS_COMPRESS EQU 2
  18. ; =========================================================================
  19. DOSSEG
  20. .MODEL LARGE,C
  21. .DATA
  22. ; =========================================================================
  23. ; UnpackSet has to allocated before a call to either ClearRingBuffer for
  24. ; Unpack. It will contain a ptr to a segment allocated for use by the
  25. ; unpack functions. When it is allocated it must be normalize to the
  26. ; allocated buffer + 16 so that it can be used with a zero offset by
  27. ; the unpack functions.
  28. ; =========================================================================
  29. PUBLIC UnpackSeg
  30. UnpackSeg dd (?)
  31. ; =========================================================================
  32. ; BUFFER_SEG is not a real segment in the program but is used to get the
  33. ; offsets into a buffer pointed to by UnpackSeg. By using this dummy segment
  34. ; it allows setting DS to WORD PTR UnpackSeg[2] and then accessing all of
  35. ; the area without using segment over-rides.
  36. ; =========================================================================
  37. BUFFER_SEG  SEGMENT at 00
  38. ORG 0
  39. RingBuf db RING_BUF_LEN DUP (?) ; Must org @ 0
  40. RingBufEnd LABEL BYTE
  41. UnpackBuffer db UNPB_BUF_LEN DUP (?)
  42. UnpackBufEnd LABEL BYTE
  43. lToDo dd (?) ; Total bytes remaining in unpack buf
  44. lWritten dd (?) ; Keeps track of total unpacked bytes
  45. iOutFile dw (?) ; Open file handle passed by caller
  46. CtrlFlags dw (?) ; Currunt control byte from upack buf
  47. RingIndex dw (?) ; Start offset in RingBuffer
  48. Char db (?) ; Current char from packed buffer
  49. SplitPoint db (?) ; Determines where to start
  50. OldSplitPoint db (?) ; Saves last spit point
  51. BUFFER_SEG ENDS
  52. ; =========================================================================
  53. .CODE
  54. EXTRN fUpdateByteCount:FAR ; Must be explicitly FAR
  55. ; =========================================================================
  56. ; Sets up the ring buffer for a new file by filling the buffer with
  57. ; spaces and setting the ctrl flags and buffer index to known starting
  58. ; values.
  59. ;
  60. ; void ClearRingBuffer( int CompressType )
  61. ;
  62. ; ARGUMENTS: int - Compression type (0 == Language group, 1 == Windows)
  63. ; RETURNS:  void
  64. ;
  65. ; RingIndex =  MAX_STR_LEN (depending on compression type)
  66. ; CtrlFlags = 0;
  67. ; SplitPoint = 0;
  68. ; memset( RingBuffer, ' ', RING_BUF_LEN - MAX_STR_LEN );
  69. ;
  70. ; =========================================================================
  71. ClearRingBuffer PROC USES DS ES DI, CompressType:BYTE
  72. mov AX,WORD PTR UnpackSeg[2] ; Get the allocated segment
  73. mov DS,AX
  74. mov ES,AX
  75. ASSUME DS:BUFFER_SEG, ES:BUFFER_SEG
  76. xor AX,AX ; DS:AX -> Start of ring buff
  77. mov CtrlFlags,AX
  78. mov SplitPoint,AL
  79. mov DI,AX ; DS:DI -> Start of ring buff
  80. mov RingIndex, RING_BUF_LEN - LANG_MAX_STR_LEN
  81. cmp CompressType,WINDOWS_COMPRESS
  82. jne @F
  83. mov RingIndex, RING_BUF_LEN - WIN_MAX_STR_LEN 
  84. @@:
  85. mov AX,2020h ; AX == '  '
  86. mov CX,(RING_BUF_LEN / 2) ; Storing words so use half
  87. cld
  88. rep stosw ; Fill buffer with ' ' chars
  89. ret
  90. ClearRingBuffer ENDP
  91. ; =========================================================================
  92. ; Uncompresses a portion of a compressed file which was compressed using
  93. ; LZ compression algorithm. Before the function is called the ring buffer
  94. ; and unpacked buffer must be allocated. Before each new file is unpacked
  95. ; a call must be done to ClearRingBuffer() to initialize the buffers and
  96. ; indices. As the buffer is unpacked it is written to the destination
  97. ; file when ever the index in the unpacked buffer reaches a point
  98. ; MAX_STR_LEN from the end of the buffer. Each time the buffer is flushed
  99. ; the ptr to the packed buffer must be normalized to prevent a possible
  100. ; segment wrap of the ptr.
  101. ; long Unpack( int iFile, char far *InBuf, long lPackedBytes )
  102. ; ARGUMENTS: iFile  - Open DOS file handle to write the unpacked bytes
  103. ;  InBuf  - Ptr to buffer to be unpacked
  104. ;    lPackedBytes  - Length of the buffer in bytes
  105. ; RETURNS:  long - Number of bytes written to the file.
  106. ;
  107. ;
  108. ; Register will be setup and used as follows within the function
  109. ;
  110. ; ES:BX -> Next byte in packed buffer
  111. ; DS:SI -> Ring buffer
  112. ; DS:DI -> Next byte in unpack buffer
  113. ; BP     ==  CtrlFlags
  114. ; DX    General use
  115. ; CX    General use
  116. ; =========================================================================
  117. Unpack PROC USES DS ES DI SI,iFile:WORD, PackedBuf:PTR, lPackedBytes:DWORD
  118. mov AX,WORD PTR UnpackSeg[2]; Get the allocated unpack segment
  119. mov DS,AX
  120. ASSUME DS:BUFFER_SEG
  121. les AX,lPackedBytes ; ES:AX == number of bytes to unpack
  122. mov WORD PTR lToDo,AX ; Move number for faster access
  123. mov WORD PTR lToDo[2],ES ; lToDo = Total byte to unpacked
  124. mov AL,SplitPoint ; Save split point in case this is
  125. mov OldSplitPoint,AL ; a continuation of a previous unpack
  126. mov SI,RingIndex ; DS:SI -> current pos. in ring buffer
  127. mov AX,iFile ; Put iFile into new segment
  128. mov iOutFile,AX
  129. les BX,PackedBuf ; Get input buffer and normalize
  130. call NEAR PTR NormalizePackPtr ; ES:BX -> normalize packed buffer
  131. mov DI,OFFSET UnpackBuffer ; DS:DI -> Unpack buffer
  132. xor AX,AX ; Reset everything else to 0
  133. mov SplitPoint,AL
  134. mov WORD PTR lWritten,AX
  135. mov WORD PTR lWritten[2],AX
  136. push BP ; Save BP for cleanup later
  137. mov BP,CtrlFlags ; BP will always hold the ctrl flags
  138. cmp OldSplitPoint,1 ; See if this is a continuation
  139. je SplitPoint1 ; of a previous file and if so
  140. mov AL,Char ; may need last char from unpack buf
  141. cmp OldSplitPoint,2 ; to start at the place where it
  142. je SplitPoint2 ; was left off last time
  143. MainLoop: ; Start of loop which will continue until lToDo == 0
  144. mov AX,WORD PTR lToDo ; See if all bytes are unpacked
  145. or AX,WORD PTR lToDo[2]
  146. jnz CheckUnpackBuf ; Continue if both bytes != 0
  147. jmp UnpackExit ; Jump to successfull exit point
  148. CheckUnpackBuf: ; See if time to flush buffer
  149. and SI,0fffh ; Make ptr to wrap back to 0 if > 4095
  150. cmp DI,OFFSET UnpackBufEnd - MAX_STR_LEN
  151. jl GetNextChar  ; Buffer not full yet
  152. call NEAR PTR FlushUnpackBuffer ; Else flush the buffer
  153. or AX,AX ; AX will be -1 if error else 0
  154. jz GetNextChar
  155. jmp ErrorExit
  156. GetNextChar:
  157. mov AL,ES:[BX] ; Get next char from in buf
  158. inc BX ; Increment packed buffer ptr
  159. sub WORD PTR lToDo,1 ; Decrement remaining packed bytes
  160. sbb WORD PTR lToDo[2],0
  161. AnyFlagsLeft:
  162. shr BP,1 ; High byte has bit mask of flags
  163. test BP,0ff00h  ; Any flags left in this byte?
  164. jnz TestFlag ; If yes go forward and check the flag
  165. ; Set bit mask to for next 8 characters
  166. or AX,0ff00h ; Set all bits in high byte for count
  167. mov BP,AX
  168. mov AX,WORD PTR lToDo ; See if all bytes are unpacked
  169. or AX,WORD PTR lToDo[2]
  170. jnz SplitPoint1 ; Continue if both bytes != 0
  171. ; If we get here it means we ran out of characters in the
  172. ; unpacked buffer but there's still more to do on the next
  173. ; call so set up to continue where we left off and then
  174. ; flush the buffer and return. We we return on the next
  175. ; call we already have the new control word can continue
  176. ; where we left off
  177. mov SplitPoint,1 ; Set starting point for next call
  178. jmp SHORT UnpackExit
  179. SplitPoint1: ; At this point we just used the char
  180. mov AL,ES:[BX] ; as ctrlbyte and need another char
  181. inc BX ; Increment packed buffer ptr
  182. sub WORD PTR lToDo,1 ; Decrement remaining packed count
  183. sbb WORD PTR lToDo[2],0
  184. TestFlag:
  185. test BP,1 ; If flag == 1 character is not
  186. jz UnpackIt ; special so just copy it
  187. mov [DI],AL ; Store char in unpacked buffer
  188. mov [SI],AL ; Also store it in the ring buffer
  189. inc DI ; Point to next char in unpacked
  190. inc SI ; and ring buffer
  191. jmp MainLoop
  192. ; Flag bit was 0 so get a string from ring buf
  193. UnpackIt:
  194. mov DX,WORD PTR lToDo ; See if all bytes are unpacked
  195. or DX,WORD PTR lToDo[2]
  196. jnz SplitPoint2 ; Continue if both bytes != 0
  197. ; If we get here it means we ran out of characters in the
  198. ; unpacked buffer but there's still more to do on the next
  199. ; call so set up to continue where we left off and then
  200. ; flush the buffer and return. We we return on the next
  201. ; call we already have the first byte of the control
  202. ; word which determines the ringbuf offset and string count
  203. mov Char,AL ; Save the byte, we need it next call
  204. mov SplitPoint,2 ; Set starting point for next call
  205. jmp SHORT UnpackExit
  206. SplitPoint2: ; offset in ringbuf = ((next char & 0xf0) << 4) + AL
  207. ; length to copy    = (nextchar & 0x0f) + 2)
  208. ; AL has last char from packed buffer
  209. mov AH,ES:[BX] ; Get the ctrl byte from packed buf
  210. inc BX ; Increment packed buffer ptr
  211. sub WORD PTR lToDo,1 ; Decrement remaining packed bytes
  212. sbb WORD PTR lToDo[2],0
  213. xor CX,CX ; Determine the str length in CX
  214. mov CL,AH ; CX = ctrl byte from the packed buf
  215. and CL,0fh ; Mask off the high nibble of low byte
  216. add CL,3
  217. ; inc CL ; Add 2
  218. ; inc CL ; CX == count of bytes to copy
  219. shr AH,1 ; Put hi nibble into low nibble of AH
  220. shr AH,1 ; and now AX will be a 12 bit value
  221. shr AH,1 ; which represents the offset in the
  222. shr AH,1 ; ring buffer
  223. CopyString:
  224. ; The string length may force a wrap of the ringbuffer so
  225. ; we have to anticipate this by having 2 methods of
  226. ; copying. If the ring buffer wraps we do a slow copy that
  227. ; normalizes SI after each movs instruction.
  228. ; Don't need a CX check because the value will always
  229. ; always be >= 3 because of the above ADD CX,3
  230. push ES ; Save the unpacked segment
  231. mov DX,SI ; DS:DX --> Dest ringbuf location
  232. mov SI,AX ; DS:SI --> Source ringbuf location
  233. mov AX,DS
  234. mov ES,AX ; ES:DI --> Dest unpackbuf location
  235. cld
  236. DoCopy:
  237. lodsb ; Get source byte from ring buffer
  238. stosb ; Copy byte to unpacked buffer
  239. xchg DI,DX ; DS:DI --> Dest ringbuf location
  240. stosb ; Copy byte to new ringbuf location
  241. xchg DI,DX ; DS:DI --> Next unpackbuf location
  242. and DX,0fffh ; Prevent wraps in the ring buffer
  243. and SI,0fffh ; Have to do both source ptrs
  244. loop DoCopy
  245. mov SI,DX ; DS:SI --> Next ringbuf offset
  246. pop ES ; ES:BX --> unpacked segment again
  247. jmp MainLoop
  248. ; ==========================================================
  249. ; Function exit points. If the unpacked buffer has anything
  250. ; copied to it which needs to be written it will be flushed
  251. ; if there were no errors.
  252. ; ==========================================================
  253. UnpackExit:
  254. cmp DI,OFFSET UnpackBuffer  ; See if anything in unpack buffer
  255. je SetReturnCount
  256. call NEAR PTR FlushUnpackBuffer ; Need to flush one last time
  257. or AX,AX ; Check for error
  258. jnz ErrorExit
  259. SetReturnCount:
  260. les AX,lWritten
  261. mov DX,ES ; DX:AX == Unpacked bytes written
  262. jmp SHORT UnpackExit2
  263. ErrorExit:
  264. mov AX,-1 ; Signal error
  265. cwd ; DX:AX == -1
  266. UnpackExit2:
  267. mov RingIndex,SI ; Save current ring buffer index
  268. mov CtrlFlags,BP
  269. pop BP
  270. ret
  271. Unpack ENDP
  272. ; =========================================================================
  273. ; Flushes the unpack buffer to file and then resets the output buffer
  274. ; indices to be ready to starting filling the buffer again. After writing
  275. ; to the file a call is done to update the gage on the screen and
  276. ; then the unpacked ptr is normalized.
  277. ;
  278. ; int FlushUnpackBuffer( void )
  279. ;
  280. ; ARGUMENTS: NONE */
  281. ; RETURN: int - OK if disk write successfully else ERROR
  282. ; */
  283. ; =========================================================================
  284. FlushUnpackBuffer:
  285. push SI
  286. mov SI,BX ; Save unpacked offset for normalizing
  287. mov DX,OFFSET UnpackBuffer ; DS:DX --> Start of unpacked buffer
  288. sub DI,DX ; DI == count of bytes to write
  289. mov CX,DI ; CX == Count of byte to write
  290. mov AH,40h ; DOS write handle function
  291. mov BX,iOutFile ; BX = Open file handle
  292. int 21h
  293. jc FlushError ; Error check
  294. cmp AX,DI ; See if all bytes were written
  295. jne FlushError
  296. add WORD PTR lWritten,CX ; Update total bytes
  297. adc WORD PTR lWritten[2],0 ; written to disk
  298. ; Bytes were successfully written so setup and call
  299. ; the function to update the gage on the screen
  300. push DS
  301. push ES
  302. mov AX,@DATA ; Setup ES & DS to C data segment
  303. mov DS,AX
  304. mov ES,AX
  305. xor AX,AX
  306. push AX ; Put byte count on the stack
  307. push CX ; as a long value (dword)
  308. call fUpdateByteCount ; Update the status gage C function
  309. add SP,4 ; Adjust SP for 2 pushes
  310. pop ES
  311. pop DS
  312. mov BX,SI ; ES:BX --> packed buffer
  313. call NEAR PTR NormalizePackPtr ; ES:BX -> normalize packed buffer
  314. FlushExit:
  315. mov DI,OFFSET UnpackBuffer ; Reset DS:DI to start of unpack buf
  316. pop SI
  317. xor AX,AX ; Return OK
  318. ret
  319. FlushError:
  320. pop SI
  321. mov AX,-1 ; Signal error
  322. ret
  323. ; =========================================================================
  324. ; Normalizes ptr to packed buffer in ES:BX
  325. ; =========================================================================
  326. NormalizePackPtr:
  327. push AX
  328. push BX
  329. mov    AX,ES ; AX:BX -> current packed buf location
  330. xchg AX,BX ; Now BX == Segment, AX = Offset
  331. shr AX,1 ; Divid offset in AX by 16
  332. shr AX,1
  333. shr AX,1
  334. shr AX,1
  335. add AX,BX ; Add segment to normalized offset
  336. mov ES,AX ; ES == Normalized segment
  337. pop BX
  338. pop AX
  339. and BX,0fh ; Mask all but 4 low bits of offset
  340. ret ; ES:BX --> normalized packed location
  341. ; Offset will be less than 16
  342. ; =========================================================================
  343. END