Category : C Source Code
Archive   : XLIB06.ZIP
Filename : XRLETOOL.ASM

 
Output of file : XRLETOOL.ASM contained in archive : XLIB06.ZIP
;-----------------------------------------------------------------------
; MODULE XRLETOOL
;
; Hardware detection module
;
; Compile with Tasm.
; C callable.
;
;
; ****** XLIB - Mode X graphics library ****************
; ****** ****************
; ****** Written By Themie Gouthas ****************
;
; [email protected]
; [email protected]
;-----------------------------------------------------------------------

COMMENT $

Firstly, please note that this module has been built from the ground up
in a rush so although I'm confident all the functions work, I have'nt
extensively checked them. If any should surface please let me know.


This module implements a number of functions comprising an RLE encoding
decoding system.

RLE stands for RUN LENGTH ENCODING. It is a quick simple data compression
scheme which is commonly used for image data compression or compression
of any data. Although not the most efficient system, it is fast, which is
why it is used in image storage systems like PCX. This implementation is
more efficient than the one used in PCX files because it uses 1 bit to
identify a Run Length byte as opposed to two in PCX files, but more on this
later.

This set of functions can be used to implement your own compressed image
file format or for example compress game mapse for various levels etc.
The uses are limited by your imagination.

I opted for trading off PCX RLE compatibility for the improved compression
efficiency.

Here is how the data is un-compressed to give an idea of its structure.


STEP 1 read a byte from the RLE compressed source buffer.

STEP 2 if has its high bit then the lower 7 bits represent the number of
times the next byte is to be repeated in the destination buffer.
if the count (lower 7 bits) is zero then
we have finished decoding goto STEP 5
else goto STEP 4

STEP 3 Read a data from the source buffer and copy it directly to the
destination buffer.
goto STEP 1

STEP 4 Read a data from the source buffer and copy it to the destination
buffer the number of times specified by step 2.
goto STEP 1

STEP 5 Stop, decoding done.

If the byte does not have the high bit set then the byte itself is transfered
to the destination buffer.

Data bytes that have the high bit already set and are unique in the input
stream are represented as a Run Length of 1 (ie 81 which includes high bit)
followed by the data byte.

If your original uncompressed data contains few consecutive bytes and most
have high bit set (ie have values > 127) then your so called
compressed data would require up to 2x the space of the uncompressed data,
so be aware that the compression ratio is extremely variable depending on the
type of data being compressed.

Apologies for this poor attempt at a description, but you can look up
RLE in any good text. Alternatively, any text that describes the PCX file
structure in any depth should have a section on RLE compression.



$

LOCALS
.286

include model.inc
include xrletool.inc

.data

_RLE_last_buff_offs dw (0)
RLEbuff db 2 dup (?)

.code

;****************************************************************
;*
;* NAME: x_buff_RLEncode
;*
;*
;* RLE Compresses a source buffer to a destination buffer and returns
;* the size of the resultant compressed data.
;*
;* C PROTOTYPE:
;*
;* extern unsigned int x_buff_RLEncode(char far * source_buff,
;* char far * dest_buff,unsigned int count);
;*
;* source_buff - The buffer to compress
;* dest_buff - The destination buffer
;* count - The size of the source data in bytes
;*
;* WARNING: buffers must be pre allocated.
;*
proc _x_buff_RLEncode
ARG src:dword,dest:dword,count:word
push bp
mov bp,sp
push ds
push si
push di

lds si,[src]
les di,[dest]
mov dx,[count]

push di

lodsb ; Load first byte into BL
mov bl,al
xor cx,cx ; Set number characters packed to zero
cld ; All moves are forward

@@RepeatByte:
lodsb ; Get byte into AL
inc cx ; Increment compressed byte count
sub dx,1 ; Decrement bytes left
je @@LastByte ; Finished when dx = 1
cmp cx,7fh ; Filled block yet
jne @@NotFilled ; Nope!

or cl,80h ; Set bit to indicate value is repeat count
mov es:[di],cl ; store it
inc di
xor cx,cx ; clear compressed byte count
mov es:[di],bl ; store byte to be repeated
inc di

@@NotFilled:
cmp al,bl ; hase there been a byte transition ?
je @@RepeatByte ; No!

cmp cl,1 ; do we have a unique byte ?
jne @@NotUnique ; No

test bl,80h ; Can this byte be mistaken for repeat count
jz @@Unambiguous ; No ! Dont bother with repeat count

@@NotUnique:
or cl,80h ; Set bit to indicate value is repeat count
mov es:[di],cl ; store it
inc di
@@Unambiguous:
xor cx,cx ; clear compressed byte count
mov es:[di],bl ; store byte to be repeated
inc di
mov bl,al ; move latest byte into bl
jmp short @@RepeatByte

@@LastByte:
cmp cl,1 ; Is this a unique byte
jne @@FinalCount ; No

test bl,80h ; Can this byte be mistaken for repeat count
jz @@FinalByte ; No, so dont bother with the repeat count

@@FinalCount: ; Output the repeat count
or cl,80h
mov al,cl
stosb

@@FinalByte:
mov al,bl
stosb

mov al,80h ; store terminating null length
stosb

; Calculate encoded length of buffer

mov ax,di
pop di
sub ax,di

pop di
pop si
pop ds
pop bp
ret
_x_buff_RLEncode endp



;****************************************************************
;*
;* NAME: x_buff_RLE_size
;*
;*
;* Returns the size the input data would compress to.
;*
;* C PROTOTYPE:
;*
;* extern unsigned int x_buff_RLE_size(char far * source_buff,
;* unsigned int count);
;*
;* source_buff - The uncompressed data buffer
;* count - The size of the source data in bytes
;*
;*
proc _x_buff_RLE_size
ARG src:dword,count:word
push bp
mov bp,sp
push ds
push si
push di

lds si,[src]
mov dx,[count]

xor di,di

lodsb ; Load first byte into BL
mov bl,al
xor cx,cx ; Set number characters packed to zero
cld ; All moves are forward

@@RepeatByte:
lodsb ; Get byte into AL
inc cx ; Increment compressed byte count
sub dx,1 ; Decrement bytes left
je @@LastByte ; Finished when dx = 1
cmp cx,7fh ; Filled block yet
jne @@NotFilled ; Nope!

add di,2 ; RL/BYTE pair stub

@@NotFilled:
cmp al,bl ; hase there been a byte transition ?
je @@RepeatByte ; No!

cmp cl,1 ; do we have a unique byte ?
jne @@NotUnique ; No

test bl,80h ; Can this byte be mistaken for repeat count
jz @@Unambiguous ; No ! Dont bother with repeat count

@@NotUnique:
inc di ; RL stub

@@Unambiguous:
xor cx,cx ; clear compressed byte count
inc di ; BYTE stub
mov bl,al ; move latest byte into bl
jmp short @@RepeatByte

@@LastByte:
cmp cl,1 ; Is this a unique byte
jne @@FinalCount ; No

test bl,80h ; Can this byte be mistaken for repeat count
jz @@FinalByte ; No, so dont bother with the repeat count

@@FinalCount: ; Output the repeat count
inc di ; RL stub

@@FinalByte:
inc di ; BYTE stub
inc di ; RL stub - Account for termiating null
mov ax,di

pop di
pop si
pop ds
pop bp
ret
_x_buff_RLE_size endp

;****************************************************************
;*
;* NAME: x_buff_RLDecode
;*
;*
;* Expands an RLE compresses source buffer to a destination buffer.
;* returns the size of the resultant uncompressed data.
;*
;* C PROTOTYPE:
;*
;* extern unsigned int x_buff_RLDecode(char far * source_buff,
;* char far * dest_buff);
;*
;* source_buff - The buffer to compress
;* dest_buff - The destination buffer
;*
;* WARNING: buffers must be pre allocated.
;*
proc _x_buff_RLDecode
ARG src:dword,dest:dword
LOCAL si_ini:word=LocalStk
push bp
mov bp,sp
sub sp,LocalStk
push ds
push si
push di

mov dx,-1 ; zero output data buffer size - 1 (compensate for
; terminating null RL)
xor cx,cx ; clear CX
cld ; Move forward

lds si,[src] ; point ds:si -> RLE source
les di,[dest] ; point es:di -> uncompressed buffer
mov [si_ini],si

@@UnpackLoop:
lodsb ; load a byte into AL
cmp al,80h ; is it terminating null RL code
je @@done ; if so jump

test al,80h ; is AL a RL code (is high bit set ?)
jz @@NoRepeats ; if not the no RL encoding for this byte, jump

mov cl,al ; set CL to RL (run length) taking care
xor cl,80h ; to remove the bit identifying it as a RL
add dx,cx ; increment buffer size

lodsb ; get the next byte which should be a data byte

shr cx,1 ; divide RL by 2 to use word stos
jcxz @@NoRepeats ; result is zero, jump

mov ah,al ; copy data byte to AH since going to use stosw
rep stosw ; copy AX to outbut buffer RL times
jnb @@UnpackLoop ; when we shifted the RL if we had a carry =>
; we had an odd number of repeats so store the
; last BYTE if carry was set otherwise jump
stosb ; store AL in destination buffer
jmp short @@UnpackLoop

@@NoRepeats:
inc dx ; increment buffer size
stosb ; store AL in destination buffer
jmp short @@UnpackLoop

@@done:

mov bx,si
sub bx,[si_ini]
mov ax,dx
pop di
pop si
pop ds
mov [_RLE_last_buff_offs],bx
mov sp,bp
pop bp
ret
_x_buff_RLDecode endp

;==========================================================================
;==========================================================================
; RLEncode to file / RLDecode from file
; WARNING the following functions are *MUCH* slower than the above
; Its best to use the above functions with intermediate buffers where
; disk i/o is concearned... See demo 4
;==========================================================================
;==========================================================================

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; put_cx
;
; Local utility proc for x_file_RLEncode - write cx to file
;
; Entry:
; es:dx -> output buffer
; cx = word to write
;
;
put_cx proc near
push ds ; preserve critical registers
push ax
push bx
mov ax,ds ; set up DS to output buffers segment
mov ds,ax
mov word ptr [RLEbuff],cx ; copy CX to output buffer
mov ah,40h ; select "write to file or device" DOS service
mov bx,[handle] ; select handle of file to write
mov cx,2 ; sending 2 bytes
int 21h ; call DOS service
pop bx ; recover registers
pop ax
pop ds
ret
put_cx endp

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; put_cx
;
; Local utility proc for x_file_RLEncode - write cx to file
;
; Entry:
; es:dx -> output buffer
; cx = word to write
;
;
put_cl proc near
push ds ; preserve critical registers
push ax
push bx
mov ax,ds ; set up DS to output buffers segment
mov ds,ax
mov byte ptr [RLEbuff],cl
mov ah,40h ; select "write to file or device" DOS service
mov bx,[handle] ; select handle of file to write
mov cx,1 ; sending 1 byte
int 21h ; call DOS service
pop bx ; recover registers
pop ax
pop ds
ret
put_cl endp


;****************************************************************
;*
;* NAME: x_file_RLEncode
;*
;*
;* RLE Compresses a source buffer to an output file returning
;* the size of the resultant compressed data or 0 if it fails.
;*
;* C PROTOTYPE:
;*
;* extern unsigned int x_file_RLEncode(int handle,
;* char far * source_buff,unsigned int count);
;*
;* source_buff - The buffer to compress
;* handle - The file handler
;* count - The size of the source data in bytes
;*
;*
proc _x_file_RLEncode
ARG handle:word,src:dword,count:word
LOCAL filesize:word=LocalStk
push bp
mov bp,sp
sub sp,LocalStk
push ds
push si
push di

mov [filesize],0
mov dx,offset [RLEbuff]
mov ax,ds
mov es,ax
lds si,[src]
mov di,[count]

lodsb ; Load first byte into BL
mov bl,al
xor cx,cx ; Set number characters packed to zero
cld ; All moves are forward

@@RepeatByte:
lodsb ; Get byte into AL
inc cx ; Increment compressed byte count
sub di,1 ; Decrement bytes left
je @@LastByte ; Finished when di = 1
cmp cx,7fh ; Filled block yet
jne @@NotFilled ; Nope!

or cl,80h ; Set bit to indicate value is repeat count
mov ch,bl
add [filesize],2
call put_cx
jb @@FileError ; if carry set then file I/O error
xor cx,cx ; clear compressed byte count

@@NotFilled:
cmp al,bl ; hase there been a byte transition ?
je @@RepeatByte ; No!

cmp cl,1 ; do we have a unique byte ?
jne @@NotUnique ; No

test bl,80h ; Can this byte be mistaken for repeat count
jz @@Unambiguous ; No ! Dont bother with repeat count

@@NotUnique:
or cl,80h ; Set bit to indicate value is repeat count
inc [filesize]
call put_cl ; store it
jb @@FileError ; if carry set then file I/O error
@@Unambiguous:

mov cl,bl ; store byte to be repeated
inc [filesize]
call put_cl
jb @@FileError ; if carry set then file I/O error
mov bl,al ; move latest byte into bl
xor cx,cx ; clear compressed byte count

jmp short @@RepeatByte

@@FileError:
mov ax,0
jmp short @@exit

@@LastByte:
cmp cl,1 ; Is this a unique byte
jne @@FinalCount ; No

test bl,80h ; Can this byte be mistaken for repeat count
jz @@FinalByte ; No, so dont bother with the repeat count

@@FinalCount: ; Output the repeat count
or cl,80h
inc [filesize]
call put_cl
jb @@FileError ; if carry set then file I/O error

@@FinalByte:
mov cl,bl
mov ch,80h
add [filesize],2
call put_cx ; store terminating null length
jb @@FileError ; if carry set then file I/O error

mov ax,[filesize]
jmp short @@exit

@@exit:
pop di
pop si
pop ds
mov sp,bp
pop bp
ret
_x_file_RLEncode endp




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; GET_BYTE
;
; macro to read a byte from the input file into al
;
GET_BYTE macro
push bx
mov ah,3fh ; select "read from file or device" DOS service
mov bx,[handle] ; Select handle of file to close
mov cx,1 ; Want to read 1 byte
int 21h ; call DOS service
pop bx
jb @@FileError ; failed if carry flag set
mov al,[RLEbuff]
endm


;****************************************************************
;*
;* NAME: x_file_RLDecode
;*
;*
;* Expands an RLE compresses file to a destination RAM buffer.
;* returns the size of the resultant uncompressed data.
;*
;* C PROTOTYPE:
;*
;* extern unsigned int x_buff_RLDecode(int handle,
;* char far * dest_buff);
;*
;* handle - Input file handle
;* dest_buff - The destination buffer
;*
;*
proc _x_file_RLDecode
ARG handle:word,dest:dword
push bp
mov bp,sp
push si
push di


mov bx,-1 ; zero output data buffer size - 1 (compensate for
; terminating null RL)
mov dx,offset [RLEbuff] ; setup DS:DX -> RLEBuffer
xor cx,cx ; clear CX
cld ; Move forward

les di,[dest] ; point es:di -> uncompressed buffer

@@UnpackLoop:

GET_BYTE ; Load a byte from file into AL

cmp al,80h ; is it terminating null RL code
je @@done ; if so jump

test al,80h ; is AL a RL code (is high bit set ?)
jz @@NoRepeats ; if not the no RL encoding for this byte, jump

mov cl,al ; set CL to RL (run length) taking care
xor cl,80h ; to remove the bit identifying it as a RL
add bx,cx ; increment buffer size
mov si,cx ; save the CX value
GET_BYTE ; Load a byte from file into AL
mov cx,si ; restore CX value
shr cx,1 ; divide RL by 2 to use word stos
jcxz @@NoRepeats ; result is zero, jump

mov ah,al ; copy data byte to AH since going to use stosw
rep stosw ; copy AX to outbut buffer RL times
jnb @@UnpackLoop ; when we shifted the RL if we had a carry =>
; we had an odd number of repeats so store the
; last BYTE if carry was set otherwise jump
stosb ; store AL in destination buffer
jmp short @@UnpackLoop

@@NoRepeats:
inc bx
stosb ; store AL in destination buffer
jmp short @@UnpackLoop

@@FileError:
mov ax,0
jmp short @@exit

@@done:
mov ax,bx
@@exit:
pop di
pop si
pop bp
ret
_x_file_RLDecode endp

end



  3 Responses to “Category : C Source Code
Archive   : XLIB06.ZIP
Filename : XRLETOOL.ASM

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/