home *** CD-ROM | disk | FTP | other *** search
- .title GIF_DECOMPRESSOR
- ;++
- ; Define optimized routines for decompressing GIF files.
- ;
- ; procedure GIF_DECOMPRESS_INIT
- ; Initialize internal tables used by the GIF_DECOMPRESS procedure.
- ; arguments:
- ; 4(AP) address of byte containing sizeof output data in bits.
- ; must be in range 2 - 8.
- ;
- ; procedure GIF_DECOMPRESS
- ; Decompress stream of input codes into user buffer.
- ; arguments:
- ; 4(AP) Address of input procedure.
- ; 8(AP) Unspecified. Additional argument for input procedure.
- ; 12(AP) Number of output bytes to produce.
- ; 16(AP) Address of output buffer.
- ;
- ; User-supplied input procedure:
- ; arguments:
- ; 4(AP) Argument specified in call to GIF_DECOMPRESS
- ; 8(AP) Address of quadword to receive output descriptor. The
- ; input routine must fill in the count and buffer address field
- ; of this descritor.
- ;
- ;--
- ;
- ; Define data area that holds string table
- .PSECT GIF_DECOMP_STABLE, WRT, LONG
- GIF_MAC_STABLE::
- CODE_BITS: .LONG 0 ; Current input size
- BITS_USED: .LONG 0 ; Number of bits used with cur buffer.
- TABLE_SIZE: .LONG 0 ; Highest code defined in table
- PREV_CODE: .LONG 0 ; Previous input code
- STACK_PTR: .LONG 0 ; Output stack pointer
- CLEAR_CODE: .LONG 0 ; Code value to signal table clears
- EOI_CODE: .LONG 0 ; Code value to signal data end
- INBUF: .BLKL 2 ; Descriptor filled in by input routine
- ; make tables 4100 instead of 4096 to avoid cache stride.
- PREFIX: .BLKW 4100 ; prefix code table.
- EXTENSION: .BLKB 4100 ; last char in code's expansion.
- STACK: .BLKB 4100 ; Decoder output stack.
- STACK_TOP:
- ARG_LIST: .BLKL 5 ; Copy of argument list.
-
- .PSECT GIF_DECOMP_CODE, NOWRT, LONG, EXE
- ;
- ; Define initialization routine. Initialize the GIF_DECOMP_STABLE psect.
- ;
- .ENTRY GIF_DECOMPRESS_INIT, ^M<R2, R3>
- ;
- ; Compute the clear and EOI codes for the specified data size and initial
- ; input code size.
- ;
- ASHL @4(AP), #1, G^CLEAR_CODE ; Convert Root size to input.
- ADDL3 G^CLEAR_CODE, #1, -
- G^EOI_CODE
- CVTBL @4(AP), R0
- ADDL3 R0, #1, G^CODE_BITS ; Initial code size
- ;
- ; Initialize the decoder table so, each code less than CLEAR_CODE expands
- ; to itself. Clear and EOI have special prefix values to aid testing for
- ; those special codes.
- ;
- CLRL R0
- MOVAW G^PREFIX, R1 ; Base address of code table
- MOVAB G^EXTENSION, R2 ; Base address of suffix table.
- MOVL G^CLEAR_CODE, R3 ; Loop end value.
- 10$:
- MNEGW #1, (R1)[R0] ; Mark code as having no prefix (-1).
- MOVB R0, (R2)[R0] ; Suffix value is save as code value.
- AOBLSS R3, R0, 10$ ; Do next code value.
- MOVW #-2, (R1)[R0] ; Mark clear code specially
- INCL R0 ; EOI code is 1 after clear code.
- MOVW #-2, (R1)[R0] ; Mark EOI code specially
-
- INCL R0
- 20$: CLRW (R1)[R0]
- AOBLEQ #257, R0, 20$ ; Zero rest of table up to 8 bits.
-
- ;
- ; Initialize input state and output stack to prepare for first call to
- ; GIF_DECOMPRESS.
- ;
- 30$: CLRL G^BITS_USED ; Init buffer pointer.
- CLRL G^INBUF ; Zero length of input buffer.
- MNEGL #1, G^PREV_CODE ; No previous code.
- MNEGL #1, G^TABLE_SIZE ; Indicates table just cleared.
- MOVAB G^STACK_TOP, - ; Output stack is initially empty.
- G^STACK_PTR
- MOVL #1, R0 ; Return success.
- RET
- ;
- ; Define main routine for decompressing.
- ;
- .ENTRY GIF_DECOMPRESS, ^M<R2,R3,R4,R5,R6,R7,R8,R9,R10,R11>
- ;
- ; Move variables into registers and make copy of argument list. Note that
- ; the value of AP was made to correspond to the top of the output stack
- ; in order to simplify testing for an empty stack (R10 >= AP).
- ;
- ASHL G^CODE_BITS, #1, R1 ; Compute new max value.
- DECL R1 ; as 2^code_bits - 1
- ; CLRL R2 ; R2 is input code value.
- MOVAW G^PREFIX, R3 ; Base address of PREFIX table
- MOVAB G^EXTENSION, R4 ; Base address of EXTENSION table
- MOVL G^TABLE_SIZE, R5 ; Number of codes defined.
- MOVL G^PREV_CODE, R6 ; Previous input code
- MOVL G^BITS_USED, R7 ; Number of bit within cur. buffer used.
- MOVL G^CODE_BITS, R8 ; Input code size.
- MOVZWL G^INBUF, R9 ; Current # of bytes in input buffer.
- ASHL #3, R9, R9 ; Convert to number of bits in buffer.
- MOVL G^STACK_PTR, R10 ; Recover current output stack position.
- MOVL 16(AP), R11 ; Output pointer.
- MOVQ 4(AP), G^<ARG_LIST+4> ; Copy args 1 and 2.
- MOVQ 12(AP), G^<ARG_LIST+12> ; Copy args 3 and 4.
- MOVAL G^<ARG_LIST>, AP ; Make new AP that overlaps with
- ; the address of the stack top.
- MOVL 12(AP), R0 ; Size of output buffer.
- MOVAB (R11)[R0], 12(AP) ; 12(AP) now has overflow address
- BRB CHECK_IF_DONE ; Jump into loop.
- ;
- ; When done, save registers back to memory to preserve for next call.
- ;
- DONE:
- MOVL R5, G^TABLE_SIZE ; Save table size
- MOVL R6, G^PREV_CODE ; Save previous code
- MOVL R7, G^BITS_USED ; Save # bits used out of input buffer.
- MOVL R8, G^CODE_BITS ; save current code bits.
- MOVL R10, G^STACK_PTR ; Save stack pointer.
- MOVL #1, R0 ; Set success status
- RET ; and return
- ;
- ; Handle case where input code is split between buffers.
- REFILL:
- BSBW SPAN_BUFFER ; do work.
- ASHL R8, #1, R1 ; Regenerate max value.
- DECL R1 ; as 2^code_bits - 1
- BRB CHECK_CODE ; Rejoin loop to process R2.
- ;
- ; Main loop processes input codes until we've filled the user's buffer.
- ; take 26 instructions/input code with 1 branch and 12 memory references.
- ;
- ; Optimally, each input code executes 18 instructions plus 8 instructions
- ; for each output byte produced. The number of branches taken is one less
- ; than twice the number of output bytes produced. Each input code results
- ; in 1 PC relative deferred, 1 register deferred, 3 indexed register deferred
- ; and 2 immediate data memory references. Each output byte results in
- ; 3 autoinc/dec, 1 byte displacement, and 2 indexed register deferred memory
- ; references.
- ;
- .ALIGN LONG
- OUTPUT_BYTE:
- MOVB (R10)+, (R11)+ ; Pop byte from stack, append to output
- CHECK_IF_DONE:
- CMPL R11, 12(AP) ; Any room left in output buffer?
- BGEQ DONE ; No, we are done
- CMPL R10, AP ; Stack empty?
- BLSS OUTPUT_BYTE ; No, copy to output buffer
- ;
- ; process next input code, producing result on stack.
- ;
- ADDL3 R7, R8, R0 ; bits-used + code_bits -> R0
- CMPL R0, R9 ; Is R0 > than number of bits in buffer
- BGTR REFILL ; Yes, do special stuff.
- EXTZV R7, R8, @<INBUF+4>, R2 ; No, directly extract code.
- MOVL R0, R7 ; update pointer by code_bits amount
-
- CHECK_CODE:
- CMPW (R3)[R2], #-2 ; is Code a special code (prefix -2)?
- BEQL SPECIAL_CODE ; Yes, handle it.
- CMPL R2, R5 ; Is code in table?
- BGTR OUT_OF_RANGE ; No, handle it.
-
- MOVL R2, R0 ; Yes, init loop variable to CODE
- 10$:
- MOVB (R4)[R0], -(R10) ; Push extension char onto stack
- CVTWL (R3)[R0], R0 ; Replace code with prefix code
- BGEQ 10$ ; If another code, continue
- ; else add to table.
- EXPAND_TABLE:
- INCL R5 ; Bump table size.
- CMPL R5, #4096 ; at max?
- BGTR 40$ ; Yes, skip.
- 10$:
- MOVW R6, (R3)[R5] ; Prefix for previous code in new code
- MOVB (R10), (R4)[R5] ; Extension is last thing put on stack
- MOVL R2, R6 ; new previous code.
- 20$:
- CMPL R5, R1 ; Is table size < max for code size?
- BLSS OUTPUT_BYTE ; yes, leave it alone
- CMPL R8, #12 ; no, is code_bits at max?
- BGEQ OUTPUT_BYTE ; yes, leave alone
- INCL R8 ; no, go to next higher size.
- ASHL R8, #1, R1 ; Compute new max value.
- DECL R1
- BRB 20$ ; test the new size.
- 40$:
- MOVL #4096, R5 ; Set to dummy entry.
- BRB 10$
- ;--------------------------
- SPECIAL_CODE:
- CMPL R2, G^EOI_CODE ; Is code end of information code.
- BEQL END_OF_INFORMATION
-
- CLRL R8 ; Reset code size
- 10$:
- INCL R8 ; Increase size of code_bits.
- ASHL R8, #1, R1 ; max value for code bits.
- DECL R1
- CMPL G^EOI_CODE, R1 ; Is table size > max value forcode_bits
- BGEQ 10$ ; Yes, try higher code size.
-
- MNEGL #1, R5 ; Flag table size for first code.
- BRW CHECK_IF_DONE
- ;-----------------------------------
-
- OUT_OF_RANGE:
- ADDL3 R5, #1, R0 ; Compute table_size + 1?
- BLEQ FIRST_CODE ; Table size was negative.
- CMPL R0, R2 ; Is code = table_size+1?
- BNEQ BAD_CODE ; No abort.
- ;
- ; Special case, expand previous code onto stack and place final char in front.
- DECL R10 ; Make gap on stack.
- MOVL R6, R0 ; Set loop variable to prev_code
- 20$:
- MOVB (R4)[R0], -(R10) ; Push onto stack
- CVTWL (R3)[R0], R0 ; Get prefix string
- BGEQ 20$
- MOVB (R10), G^<STACK_TOP-1> ; Copy last char to front.
- BRW EXPAND_TABLE ; Add new code to table.
- ;-----------------------------------
- BAD_CODE:
- MOVL #20, R0 ; Bad parameter status.
- RET
- END_OF_INFORMATION:
- MOVL #2160, R0
- RET
- ;-----------------------------------
- FIRST_CODE:
- MOVL R2, R6 ; Update previous code.
- MOVB (R4)[R2], -(R10) ; Push onto stack
- MOVL G^EOI_CODE, R5
- BRW OUTPUT_BYTE
- ;-----------------------------------
- ;
- ; Define subroutine to handle getting input code when buffer spans
- ; boundaries.
- ;
- ; Input:
- ; R7 Number of bits used in INBUF
- ; R8 Code size (number of bits to extract).
- ; R9 Number of bits in INBUF, we assume (R7+R8) > R9
- ;
- ; Output:
- ; R0,R1 Destroyed
- ; R2 Code.
- ; R7 Number of bits used in INBUF
- ; R9 Totoal number of bits in INBUF
- ;
- SPAN_BUFFER:
- SUBL3 R7, R9, R0 ; Calculate bits left in buffer
- PUSHL R0 ; save for later use
- EXTZV R7, R0, @<INBUF+4>, R2 ; Get remaining bits.
- ADDL R8, R7 ; Make phantom bits-used.
- 50$:
- MOVAL G^INBUF, -(SP) ; Output descriptor
- MOVL 8(AP), -(SP) ; user arg for input routine
- CALLS #2, @4(AP) ; Get input
- BLBC R0, 100$ ; abort if error.
- MOVL (SP)+, R0 ; Recover # bits taken from last buffer
- SUBL R9, R7 ; Number of overflow bits becomes # used
- MOVZWL G^INBUF, R9 ; Current # of bytes in input buffer.
- ASHL #3, R9, R9 ; Convert to number of bits.
- CMPL R9, R7 ; Is number of bits to take more
- BLSS 110$ ; Yes, go to special case.
- EXTZV #0, R7, @<INBUF+4>, R1 ; No, extract the bits.
- ASHL R0, R1, R0 ; Shift over by overflow amount
- BISL R0, R2 ; OR into output code.
- RSB
- 100$:
- RET
- ;
- ; Handle the rare case where more bits left to extract than bits in
- ; buffer read.
- 110$:
- EXTZV #0, R9, - ; Extract entire buffer.
- @<INBUF+4>, R1
- ASHL R0, R1, R0 ; Shift over
- BISL R0, R2 ; Add to result
- ADDL3 R9, R0, -(SP) ; update number of bits to shift
- BRB 50$ ; read another buffer.
- ;
- .END
-