1 ;-----------------------------------------------------------------------
\r
4 ; Hardware detection module
\r
10 ; ****** XLIB - Mode X graphics library ****************
\r
11 ; ****** ****************
\r
12 ; ****** Written By Themie Gouthas ****************
\r
14 ; egg@dstos3.dsto.gov.au
\r
15 ; teg@bart.dsto.gov.au
\r
16 ;-----------------------------------------------------------------------
\r
20 Firstly, please note that this module has been built from the ground up
\r
21 in a rush so although I'm confident all the functions work, I have'nt
\r
22 extensively checked them. If any should surface please let me know.
\r
25 This module implements a number of functions comprising an RLE encoding
\r
28 RLE stands for RUN LENGTH ENCODING. It is a quick simple data compression
\r
29 scheme which is commonly used for image data compression or compression
\r
30 of any data. Although not the most efficient system, it is fast, which is
\r
31 why it is used in image storage systems like PCX. This implementation is
\r
32 more efficient than the one used in PCX files because it uses 1 bit to
\r
33 identify a Run Length byte as opposed to two in PCX files, but more on this
\r
36 This set of functions can be used to implement your own compressed image
\r
37 file format or for example compress game mapse for various levels etc.
\r
38 The uses are limited by your imagination.
\r
40 I opted for trading off PCX RLE compatibility for the improved compression
\r
43 Here is how the data is un-compressed to give an idea of its structure.
\r
46 STEP 1 read a byte from the RLE compressed source buffer.
\r
48 STEP 2 if has its high bit then the lower 7 bits represent the number of
\r
49 times the next byte is to be repeated in the destination buffer.
\r
50 if the count (lower 7 bits) is zero then
\r
51 we have finished decoding goto STEP 5
\r
54 STEP 3 Read a data from the source buffer and copy it directly to the
\r
58 STEP 4 Read a data from the source buffer and copy it to the destination
\r
59 buffer the number of times specified by step 2.
\r
62 STEP 5 Stop, decoding done.
\r
64 If the byte does not have the high bit set then the byte itself is transfered
\r
65 to the destination buffer.
\r
67 Data bytes that have the high bit already set and are unique in the input
\r
68 stream are represented as a Run Length of 1 (ie 81 which includes high bit)
\r
69 followed by the data byte.
\r
71 If your original uncompressed data contains few consecutive bytes and most
\r
72 have high bit set (ie have values > 127) then your so called
\r
73 compressed data would require up to 2x the space of the uncompressed data,
\r
74 so be aware that the compression ratio is extremely variable depending on the
\r
75 type of data being compressed.
\r
77 Apologies for this poor attempt at a description, but you can look up
\r
78 RLE in any good text. Alternatively, any text that describes the PCX file
\r
79 structure in any depth should have a section on RLE compression.
\r
89 include xrletool.inc
\r
93 _RLE_last_buff_offs dw (0)
\r
94 RLEbuff db 2 dup (?)
\r
98 ;****************************************************************
\r
100 ;* NAME: x_buff_RLEncode
\r
103 ;* RLE Compresses a source buffer to a destination buffer and returns
\r
104 ;* the size of the resultant compressed data.
\r
108 ;* extern unsigned int x_buff_RLEncode(char far * source_buff,
\r
109 ;* char far * dest_buff,unsigned int count);
\r
111 ;* source_buff - The buffer to compress
\r
112 ;* dest_buff - The destination buffer
\r
113 ;* count - The size of the source data in bytes
\r
115 ;* WARNING: buffers must be pre allocated.
\r
117 proc _x_buff_RLEncode
\r
118 ARG src:dword,dest:dword,count:word
\r
131 lodsb ; Load first byte into BL
\r
133 xor cx,cx ; Set number characters packed to zero
\r
134 cld ; All moves are forward
\r
137 lodsb ; Get byte into AL
\r
138 inc cx ; Increment compressed byte count
\r
139 sub dx,1 ; Decrement bytes left
\r
140 je @@LastByte ; Finished when dx = 1
\r
141 cmp cx,7fh ; Filled block yet
\r
142 jne @@NotFilled ; Nope!
\r
144 or cl,80h ; Set bit to indicate value is repeat count
\r
145 mov es:[di],cl ; store it
\r
147 xor cx,cx ; clear compressed byte count
\r
148 mov es:[di],bl ; store byte to be repeated
\r
152 cmp al,bl ; hase there been a byte transition ?
\r
153 je @@RepeatByte ; No!
\r
155 cmp cl,1 ; do we have a unique byte ?
\r
156 jne @@NotUnique ; No
\r
158 test bl,80h ; Can this byte be mistaken for repeat count
\r
159 jz @@Unambiguous ; No ! Dont bother with repeat count
\r
162 or cl,80h ; Set bit to indicate value is repeat count
\r
163 mov es:[di],cl ; store it
\r
166 xor cx,cx ; clear compressed byte count
\r
167 mov es:[di],bl ; store byte to be repeated
\r
169 mov bl,al ; move latest byte into bl
\r
170 jmp short @@RepeatByte
\r
173 cmp cl,1 ; Is this a unique byte
\r
174 jne @@FinalCount ; No
\r
176 test bl,80h ; Can this byte be mistaken for repeat count
\r
177 jz @@FinalByte ; No, so dont bother with the repeat count
\r
179 @@FinalCount: ; Output the repeat count
\r
188 mov al,80h ; store terminating null length
\r
191 ; Calculate encoded length of buffer
\r
202 _x_buff_RLEncode endp
\r
206 ;****************************************************************
\r
208 ;* NAME: x_buff_RLE_size
\r
211 ;* Returns the size the input data would compress to.
\r
215 ;* extern unsigned int x_buff_RLE_size(char far * source_buff,
\r
216 ;* unsigned int count);
\r
218 ;* source_buff - The uncompressed data buffer
\r
219 ;* count - The size of the source data in bytes
\r
222 proc _x_buff_RLE_size
\r
223 ARG src:dword,count:word
\r
235 lodsb ; Load first byte into BL
\r
237 xor cx,cx ; Set number characters packed to zero
\r
238 cld ; All moves are forward
\r
241 lodsb ; Get byte into AL
\r
242 inc cx ; Increment compressed byte count
\r
243 sub dx,1 ; Decrement bytes left
\r
244 je @@LastByte ; Finished when dx = 1
\r
245 cmp cx,7fh ; Filled block yet
\r
246 jne @@NotFilled ; Nope!
\r
248 add di,2 ; RL/BYTE pair stub
\r
251 cmp al,bl ; hase there been a byte transition ?
\r
252 je @@RepeatByte ; No!
\r
254 cmp cl,1 ; do we have a unique byte ?
\r
255 jne @@NotUnique ; No
\r
257 test bl,80h ; Can this byte be mistaken for repeat count
\r
258 jz @@Unambiguous ; No ! Dont bother with repeat count
\r
264 xor cx,cx ; clear compressed byte count
\r
266 mov bl,al ; move latest byte into bl
\r
267 jmp short @@RepeatByte
\r
270 cmp cl,1 ; Is this a unique byte
\r
271 jne @@FinalCount ; No
\r
273 test bl,80h ; Can this byte be mistaken for repeat count
\r
274 jz @@FinalByte ; No, so dont bother with the repeat count
\r
276 @@FinalCount: ; Output the repeat count
\r
281 inc di ; RL stub - Account for termiating null
\r
289 _x_buff_RLE_size endp
\r
291 ;****************************************************************
\r
293 ;* NAME: x_buff_RLDecode
\r
296 ;* Expands an RLE compresses source buffer to a destination buffer.
\r
297 ;* returns the size of the resultant uncompressed data.
\r
301 ;* extern unsigned int x_buff_RLDecode(char far * source_buff,
\r
302 ;* char far * dest_buff);
\r
304 ;* source_buff - The buffer to compress
\r
305 ;* dest_buff - The destination buffer
\r
307 ;* WARNING: buffers must be pre allocated.
\r
309 proc _x_buff_RLDecode
\r
310 ARG src:dword,dest:dword
\r
311 LOCAL si_ini:word=LocalStk
\r
319 mov dx,-1 ; zero output data buffer size - 1 (compensate for
\r
320 ; terminating null RL)
\r
321 xor cx,cx ; clear CX
\r
324 lds si,[src] ; point ds:si -> RLE source
\r
325 les di,[dest] ; point es:di -> uncompressed buffer
\r
329 lodsb ; load a byte into AL
\r
330 cmp al,80h ; is it terminating null RL code
\r
331 je @@done ; if so jump
\r
333 test al,80h ; is AL a RL code (is high bit set ?)
\r
334 jz @@NoRepeats ; if not the no RL encoding for this byte, jump
\r
336 mov cl,al ; set CL to RL (run length) taking care
\r
337 xor cl,80h ; to remove the bit identifying it as a RL
\r
338 add dx,cx ; increment buffer size
\r
340 lodsb ; get the next byte which should be a data byte
\r
342 shr cx,1 ; divide RL by 2 to use word stos
\r
343 jcxz @@NoRepeats ; result is zero, jump
\r
345 mov ah,al ; copy data byte to AH since going to use stosw
\r
346 rep stosw ; copy AX to outbut buffer RL times
\r
347 jnb @@UnpackLoop ; when we shifted the RL if we had a carry =>
\r
348 ; we had an odd number of repeats so store the
\r
349 ; last BYTE if carry was set otherwise jump
\r
350 stosb ; store AL in destination buffer
\r
351 jmp short @@UnpackLoop
\r
354 inc dx ; increment buffer size
\r
355 stosb ; store AL in destination buffer
\r
356 jmp short @@UnpackLoop
\r
366 mov [_RLE_last_buff_offs],bx
\r
370 _x_buff_RLDecode endp
\r
372 ;==========================================================================
\r
373 ;==========================================================================
\r
374 ; RLEncode to file / RLDecode from file
\r
375 ; WARNING the following functions are *MUCH* slower than the above
\r
376 ; Its best to use the above functions with intermediate buffers where
\r
377 ; disk i/o is concearned... See demo 4
\r
378 ;==========================================================================
\r
379 ;==========================================================================
\r
381 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\r
385 ; Local utility proc for x_file_RLEncode - write cx to file
\r
388 ; es:dx -> output buffer
\r
389 ; cx = word to write
\r
393 push ds ; preserve critical registers
\r
396 mov ax,ds ; set up DS to output buffers segment
\r
398 mov word ptr [RLEbuff],cx ; copy CX to output buffer
\r
399 mov ah,40h ; select "write to file or device" DOS service
\r
400 mov bx,[handle] ; select handle of file to write
\r
401 mov cx,2 ; sending 2 bytes
\r
402 int 21h ; call DOS service
\r
403 pop bx ; recover registers
\r
409 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\r
413 ; Local utility proc for x_file_RLEncode - write cx to file
\r
416 ; es:dx -> output buffer
\r
417 ; cx = word to write
\r
421 push ds ; preserve critical registers
\r
424 mov ax,ds ; set up DS to output buffers segment
\r
426 mov byte ptr [RLEbuff],cl
\r
427 mov ah,40h ; select "write to file or device" DOS service
\r
428 mov bx,[handle] ; select handle of file to write
\r
429 mov cx,1 ; sending 1 byte
\r
430 int 21h ; call DOS service
\r
431 pop bx ; recover registers
\r
438 ;****************************************************************
\r
440 ;* NAME: x_file_RLEncode
\r
443 ;* RLE Compresses a source buffer to an output file returning
\r
444 ;* the size of the resultant compressed data or 0 if it fails.
\r
448 ;* extern unsigned int x_file_RLEncode(int handle,
\r
449 ;* char far * source_buff,unsigned int count);
\r
451 ;* source_buff - The buffer to compress
\r
452 ;* handle - The file handler
\r
453 ;* count - The size of the source data in bytes
\r
456 proc _x_file_RLEncode
\r
457 ARG handle:word,src:dword,count:word
\r
458 LOCAL filesize:word=LocalStk
\r
467 mov dx,offset [RLEbuff]
\r
473 lodsb ; Load first byte into BL
\r
475 xor cx,cx ; Set number characters packed to zero
\r
476 cld ; All moves are forward
\r
479 lodsb ; Get byte into AL
\r
480 inc cx ; Increment compressed byte count
\r
481 sub di,1 ; Decrement bytes left
\r
482 je @@LastByte ; Finished when di = 1
\r
483 cmp cx,7fh ; Filled block yet
\r
484 jne @@NotFilled ; Nope!
\r
486 or cl,80h ; Set bit to indicate value is repeat count
\r
490 jb @@FileError ; if carry set then file I/O error
\r
491 xor cx,cx ; clear compressed byte count
\r
494 cmp al,bl ; hase there been a byte transition ?
\r
495 je @@RepeatByte ; No!
\r
497 cmp cl,1 ; do we have a unique byte ?
\r
498 jne @@NotUnique ; No
\r
500 test bl,80h ; Can this byte be mistaken for repeat count
\r
501 jz @@Unambiguous ; No ! Dont bother with repeat count
\r
504 or cl,80h ; Set bit to indicate value is repeat count
\r
506 call put_cl ; store it
\r
507 jb @@FileError ; if carry set then file I/O error
\r
510 mov cl,bl ; store byte to be repeated
\r
513 jb @@FileError ; if carry set then file I/O error
\r
514 mov bl,al ; move latest byte into bl
\r
515 xor cx,cx ; clear compressed byte count
\r
516 jmp short @@RepeatByte
\r
523 cmp cl,1 ; Is this a unique byte
\r
524 jne @@FinalCount ; No
\r
526 test bl,80h ; Can this byte be mistaken for repeat count
\r
527 jz @@FinalByte ; No, so dont bother with the repeat count
\r
529 @@FinalCount: ; Output the repeat count
\r
533 jb @@FileError ; if carry set then file I/O error
\r
539 call put_cx ; store terminating null length
\r
540 jb @@FileError ; if carry set then file I/O error
\r
552 _x_file_RLEncode endp
\r
557 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\r
561 ; macro to read a byte from the input file into al
\r
565 mov ah,3fh ; select "read from file or device" DOS service
\r
566 mov bx,[handle] ; Select handle of file to close
\r
567 mov cx,1 ; Want to read 1 byte
\r
568 int 21h ; call DOS service
\r
570 jb @@FileError ; failed if carry flag set
\r
575 ;****************************************************************
\r
577 ;* NAME: x_file_RLDecode
\r
580 ;* Expands an RLE compresses file to a destination RAM buffer.
\r
581 ;* returns the size of the resultant uncompressed data.
\r
585 ;* extern unsigned int x_buff_RLDecode(int handle,
\r
586 ;* char far * dest_buff);
\r
588 ;* handle - Input file handle
\r
589 ;* dest_buff - The destination buffer
\r
592 proc _x_file_RLDecode
\r
593 ARG handle:word,dest:dword
\r
600 mov bx,-1 ; zero output data buffer size - 1 (compensate for
\r
601 ; terminating null RL)
\r
602 mov dx,offset [RLEbuff] ; setup DS:DX -> RLEBuffer
\r
603 xor cx,cx ; clear CX
\r
606 les di,[dest] ; point es:di -> uncompressed buffer
\r
610 GET_BYTE ; Load a byte from file into AL
\r
612 cmp al,80h ; is it terminating null RL code
\r
613 je @@done ; if so jump
\r
615 test al,80h ; is AL a RL code (is high bit set ?)
\r
616 jz @@NoRepeats ; if not the no RL encoding for this byte, jump
\r
618 mov cl,al ; set CL to RL (run length) taking care
\r
619 xor cl,80h ; to remove the bit identifying it as a RL
\r
620 add bx,cx ; increment buffer size
\r
621 mov si,cx ; save the CX value
\r
622 GET_BYTE ; Load a byte from file into AL
\r
623 mov cx,si ; restore CX value
\r
624 shr cx,1 ; divide RL by 2 to use word stos
\r
625 jcxz @@NoRepeats ; result is zero, jump
\r
627 mov ah,al ; copy data byte to AH since going to use stosw
\r
628 rep stosw ; copy AX to outbut buffer RL times
\r
629 jnb @@UnpackLoop ; when we shifted the RL if we had a carry =>
\r
630 ; we had an odd number of repeats so store the
\r
631 ; last BYTE if carry was set otherwise jump
\r
632 stosb ; store AL in destination buffer
\r
633 jmp short @@UnpackLoop
\r
637 stosb ; store AL in destination buffer
\r
638 jmp short @@UnpackLoop
\r
651 _x_file_RLDecode endp
\r