]> 4ch.mooo.com Git - 16.git/blob - 16/xlib/xrletool.asm
16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / 16 / xlib / xrletool.asm
1 ;-----------------------------------------------------------------------\r
2 ; MODULE XRLETOOL\r
3 ;\r
4 ; Hardware detection module\r
5 ;\r
6 ; Compile with Tasm.\r
7 ; C callable.\r
8 ;\r
9 ;\r
10 ; ****** XLIB - Mode X graphics library                ****************\r
11 ; ******                                               ****************\r
12 ; ****** Written By Themie Gouthas                     ****************\r
13 ;\r
14 ; egg@dstos3.dsto.gov.au\r
15 ; teg@bart.dsto.gov.au\r
16 ;-----------------------------------------------------------------------\r
17 \r
18 COMMENT $\r
19 \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
23 \r
24 \r
25 This module implements a number of functions comprising an RLE encoding\r
26 decoding system.\r
27 \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
34 later.\r
35 \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
39 \r
40 I opted for trading off PCX RLE compatibility for the improved compression\r
41 efficiency.\r
42 \r
43 Here is how the data is un-compressed to give an idea of its structure.\r
44 \r
45 \r
46 STEP 1 read a byte from the RLE compressed source buffer.\r
47 \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
52        else goto STEP 4\r
53 \r
54 STEP 3 Read a data from the source buffer and copy it directly to the\r
55        destination buffer.\r
56        goto STEP 1\r
57 \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
60        goto STEP 1\r
61 \r
62 STEP 5 Stop, decoding done.\r
63 \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
66 \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
70 \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
76 \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
80 \r
81 \r
82 \r
83 $\r
84 \r
85 LOCALS\r
86 .8086\r
87 \r
88 include model.inc\r
89 include xrletool.inc\r
90 \r
91         .data\r
92 \r
93 _RLE_last_buff_offs dw (0)\r
94 RLEbuff db 2 dup (?)\r
95 \r
96         .code\r
97 \r
98 ;****************************************************************\r
99 ;*\r
100 ;* NAME: x_buff_RLEncode\r
101 ;*\r
102 ;*\r
103 ;* RLE Compresses a source buffer to a destination buffer and returns\r
104 ;* the size of the resultant compressed data.\r
105 ;*\r
106 ;* C PROTOTYPE:\r
107 ;*\r
108 ;*  extern unsigned int x_buff_RLEncode(char far * source_buff,\r
109 ;*               char far * dest_buff,unsigned int count);\r
110 ;*\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
114 ;*\r
115 ;* WARNING: buffers must be pre allocated.\r
116 ;*\r
117 proc _x_buff_RLEncode\r
118 ARG   src:dword,dest:dword,count:word\r
119         push bp\r
120         mov  bp,sp\r
121         push ds\r
122         push si\r
123         push di\r
124 \r
125         lds  si,[src]\r
126         les  di,[dest]\r
127         mov  dx,[count]\r
128 \r
129         push di\r
130 \r
131         lodsb              ; Load first byte into BL\r
132         mov  bl,al\r
133         xor  cx,cx         ; Set number characters packed to zero\r
134         cld                ; All moves are forward\r
135 \r
136 @@RepeatByte:\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
143 \r
144         or   cl,80h        ; Set bit to indicate value is repeat count\r
145         mov  es:[di],cl    ; store it\r
146         inc  di\r
147         xor  cx,cx         ; clear compressed byte count\r
148         mov  es:[di],bl    ; store byte to be repeated\r
149         inc  di\r
150 \r
151 @@NotFilled:\r
152         cmp  al,bl         ; hase there been a byte transition ?\r
153         je   @@RepeatByte  ; No!\r
154 \r
155         cmp  cl,1          ; do we have a unique byte ?\r
156         jne  @@NotUnique   ; No\r
157 \r
158         test bl,80h        ; Can this byte be mistaken for repeat count\r
159         jz   @@Unambiguous ; No ! Dont bother with repeat count\r
160 \r
161 @@NotUnique:\r
162         or   cl,80h        ; Set bit to indicate value is repeat count\r
163         mov  es:[di],cl    ; store it\r
164         inc  di\r
165 @@Unambiguous:\r
166         xor  cx,cx         ; clear compressed byte count\r
167         mov  es:[di],bl    ; store byte to be repeated\r
168         inc  di\r
169         mov  bl,al         ; move latest byte into bl\r
170         jmp  short @@RepeatByte\r
171 \r
172 @@LastByte:\r
173         cmp  cl,1          ; Is this a unique byte\r
174         jne  @@FinalCount  ; No\r
175 \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
178 \r
179 @@FinalCount:              ; Output the repeat count\r
180         or   cl,80h\r
181         mov  al,cl\r
182         stosb\r
183 \r
184 @@FinalByte:\r
185         mov  al,bl\r
186         stosb\r
187 \r
188         mov  al,80h       ; store terminating null length\r
189         stosb\r
190 \r
191         ; Calculate encoded length of buffer\r
192 \r
193         mov  ax,di\r
194         pop  di\r
195         sub  ax,di\r
196 \r
197         pop  di\r
198         pop  si\r
199         pop  ds\r
200         pop  bp\r
201         ret\r
202 _x_buff_RLEncode endp\r
203 \r
204 \r
205 \r
206 ;****************************************************************\r
207 ;*\r
208 ;* NAME: x_buff_RLE_size\r
209 ;*\r
210 ;*\r
211 ;* Returns the size the input data would compress to.\r
212 ;*\r
213 ;* C PROTOTYPE:\r
214 ;*\r
215 ;*  extern unsigned int x_buff_RLE_size(char far * source_buff,\r
216 ;*               unsigned int count);\r
217 ;*\r
218 ;* source_buff   - The uncompressed data buffer\r
219 ;* count         - The size of the source data in bytes\r
220 ;*\r
221 ;*\r
222 proc _x_buff_RLE_size\r
223 ARG   src:dword,count:word\r
224         push bp\r
225         mov  bp,sp\r
226         push ds\r
227         push si\r
228         push di\r
229 \r
230         lds  si,[src]\r
231         mov  dx,[count]\r
232 \r
233         xor  di,di\r
234 \r
235         lodsb              ; Load first byte into BL\r
236         mov  bl,al\r
237         xor  cx,cx         ; Set number characters packed to zero\r
238         cld                ; All moves are forward\r
239 \r
240 @@RepeatByte:\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
247 \r
248         add  di,2          ; RL/BYTE pair stub\r
249 \r
250 @@NotFilled:\r
251         cmp  al,bl         ; hase there been a byte transition ?\r
252         je   @@RepeatByte  ; No!\r
253 \r
254         cmp  cl,1          ; do we have a unique byte ?\r
255         jne  @@NotUnique   ; No\r
256 \r
257         test bl,80h        ; Can this byte be mistaken for repeat count\r
258         jz   @@Unambiguous ; No ! Dont bother with repeat count\r
259 \r
260 @@NotUnique:\r
261         inc  di            ; RL stub\r
262 \r
263 @@Unambiguous:\r
264         xor  cx,cx         ; clear compressed byte count\r
265         inc  di            ; BYTE stub\r
266         mov  bl,al         ; move latest byte into bl\r
267         jmp  short @@RepeatByte\r
268 \r
269 @@LastByte:\r
270         cmp  cl,1          ; Is this a unique byte\r
271         jne  @@FinalCount  ; No\r
272 \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
275 \r
276 @@FinalCount:              ; Output the repeat count\r
277         inc  di            ; RL stub\r
278 \r
279 @@FinalByte:\r
280         inc  di            ; BYTE stub\r
281         inc  di            ; RL stub - Account for termiating null\r
282         mov  ax,di\r
283 \r
284         pop  di\r
285         pop  si\r
286         pop  ds\r
287         pop  bp\r
288         ret\r
289 _x_buff_RLE_size endp\r
290 \r
291 ;****************************************************************\r
292 ;*\r
293 ;* NAME: x_buff_RLDecode\r
294 ;*\r
295 ;*\r
296 ;* Expands an RLE compresses source buffer to a destination buffer.\r
297 ;* returns the size of the resultant uncompressed data.\r
298 ;*\r
299 ;* C PROTOTYPE:\r
300 ;*\r
301 ;*  extern unsigned int x_buff_RLDecode(char far * source_buff,\r
302 ;*               char far * dest_buff);\r
303 ;*\r
304 ;* source_buff   - The buffer to compress\r
305 ;* dest_buff     - The destination buffer\r
306 ;*\r
307 ;* WARNING: buffers must be pre allocated.\r
308 ;*\r
309 proc _x_buff_RLDecode\r
310 ARG   src:dword,dest:dword\r
311 LOCAL si_ini:word=LocalStk\r
312         push bp\r
313         mov  bp,sp\r
314         sub  sp,LocalStk\r
315         push ds\r
316         push si\r
317         push di\r
318 \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
322         cld               ; Move forward\r
323 \r
324         lds  si,[src]     ; point ds:si -> RLE source\r
325         les  di,[dest]    ; point es:di -> uncompressed buffer\r
326         mov  [si_ini],si\r
327 \r
328 @@UnpackLoop:\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
332 \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
335 \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
339 \r
340         lodsb             ; get the next byte which should be a data byte\r
341 \r
342         shr  cx,1         ; divide RL by 2 to use word stos\r
343         jcxz @@NoRepeats  ; result is zero, jump\r
344 \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
352 \r
353 @@NoRepeats:\r
354         inc  dx           ; increment buffer size\r
355         stosb             ; store AL in destination buffer\r
356         jmp  short @@UnpackLoop\r
357 \r
358 @@done:\r
359 \r
360         mov  bx,si\r
361         sub  bx,[si_ini]\r
362         mov  ax,dx\r
363         pop  di\r
364         pop  si\r
365         pop  ds\r
366         mov  [_RLE_last_buff_offs],bx\r
367         mov  sp,bp\r
368         pop  bp\r
369         ret\r
370 _x_buff_RLDecode endp\r
371 \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
380 \r
381 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
382 ;\r
383 ; put_cx\r
384 ;\r
385 ;   Local utility proc for x_file_RLEncode - write cx to file\r
386 ;\r
387 ; Entry:\r
388 ;       es:dx -> output buffer\r
389 ;       cx = word to write\r
390 ;\r
391 ;\r
392 put_cx proc near\r
393         push ds             ; preserve critical registers\r
394         push ax\r
395         push bx\r
396         mov  ax,ds          ; set up DS to output buffers segment\r
397         mov  ds,ax\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
404         pop  ax\r
405         pop  ds\r
406         ret\r
407 put_cx endp\r
408 \r
409 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
410 ;\r
411 ; put_cx\r
412 ;\r
413 ;   Local utility proc for x_file_RLEncode - write cx to file\r
414 ;\r
415 ; Entry:\r
416 ;       es:dx -> output buffer\r
417 ;       cx = word to write\r
418 ;\r
419 ;\r
420 put_cl proc near\r
421         push ds             ; preserve critical registers\r
422         push ax\r
423         push bx\r
424         mov  ax,ds          ; set up DS to output buffers segment\r
425         mov  ds,ax\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
432         pop  ax\r
433         pop  ds\r
434         ret\r
435 put_cl endp\r
436 \r
437 \r
438 ;****************************************************************\r
439 ;*\r
440 ;* NAME: x_file_RLEncode\r
441 ;*\r
442 ;*\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
445 ;*\r
446 ;* C PROTOTYPE:\r
447 ;*\r
448 ;*  extern unsigned int x_file_RLEncode(int handle,\r
449 ;*               char far * source_buff,unsigned int count);\r
450 ;*\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
454 ;*\r
455 ;*\r
456 proc _x_file_RLEncode\r
457 ARG   handle:word,src:dword,count:word\r
458 LOCAL filesize:word=LocalStk\r
459         push bp\r
460         mov  bp,sp\r
461         sub  sp,LocalStk\r
462         push ds\r
463         push si\r
464         push di\r
465 \r
466         mov  [filesize],0\r
467         mov  dx,offset [RLEbuff]\r
468         mov  ax,ds\r
469         mov  es,ax\r
470         lds  si,[src]\r
471         mov  di,[count]\r
472 \r
473         lodsb              ; Load first byte into BL\r
474         mov  bl,al\r
475         xor  cx,cx         ; Set number characters packed to zero\r
476         cld                ; All moves are forward\r
477 \r
478 @@RepeatByte:\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
485 \r
486         or   cl,80h        ; Set bit to indicate value is repeat count\r
487         mov  ch,bl\r
488         add  [filesize],2\r
489         call put_cx\r
490         jb   @@FileError   ; if carry set then file I/O error\r
491         xor  cx,cx         ; clear compressed byte count\r
492 \r
493 @@NotFilled:\r
494         cmp  al,bl         ; hase there been a byte transition ?\r
495         je   @@RepeatByte  ; No!\r
496 \r
497         cmp  cl,1          ; do we have a unique byte ?\r
498         jne  @@NotUnique   ; No\r
499 \r
500         test bl,80h        ; Can this byte be mistaken for repeat count\r
501         jz   @@Unambiguous ; No ! Dont bother with repeat count\r
502 \r
503 @@NotUnique:\r
504         or   cl,80h        ; Set bit to indicate value is repeat count\r
505         inc  [filesize]\r
506         call put_cl        ; store it\r
507         jb   @@FileError   ; if carry set then file I/O error\r
508 @@Unambiguous:\r
509 \r
510         mov  cl,bl         ; store byte to be repeated\r
511         inc  [filesize]\r
512         call put_cl\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
517 \r
518 @@FileError:\r
519         mov  ax,0\r
520         jmp  short @@exit\r
521 \r
522 @@LastByte:\r
523         cmp  cl,1          ; Is this a unique byte\r
524         jne  @@FinalCount  ; No\r
525 \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
528 \r
529 @@FinalCount:              ; Output the repeat count\r
530         or   cl,80h\r
531         inc  [filesize]\r
532         call put_cl\r
533         jb   @@FileError   ; if carry set then file I/O error\r
534 \r
535 @@FinalByte:\r
536         mov  cl,bl\r
537         mov  ch,80h\r
538         add  [filesize],2\r
539         call put_cx        ; store terminating null length\r
540         jb   @@FileError   ; if carry set then file I/O error\r
541 \r
542         mov  ax,[filesize]\r
543         jmp  short @@exit\r
544 \r
545 @@exit:\r
546         pop  di\r
547         pop  si\r
548         pop  ds\r
549         mov  sp,bp\r
550         pop  bp\r
551         ret\r
552 _x_file_RLEncode endp\r
553 \r
554 \r
555 \r
556 \r
557 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\r
558 ;\r
559 ; GET_BYTE\r
560 ;\r
561 ;   macro to read a byte from the input file into al\r
562 ;\r
563 GET_BYTE macro\r
564         push bx\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
569         pop  bx\r
570         jb   @@FileError    ; failed if carry flag set\r
571         mov  al,[RLEbuff]\r
572         endm\r
573 \r
574 \r
575 ;****************************************************************\r
576 ;*\r
577 ;* NAME: x_file_RLDecode\r
578 ;*\r
579 ;*\r
580 ;* Expands an RLE compresses file to a destination RAM buffer.\r
581 ;* returns the size of the resultant uncompressed data.\r
582 ;*\r
583 ;* C PROTOTYPE:\r
584 ;*\r
585 ;*  extern unsigned int x_buff_RLDecode(int handle,\r
586 ;*               char far * dest_buff);\r
587 ;*\r
588 ;* handle        - Input file handle\r
589 ;* dest_buff     - The destination buffer\r
590 ;*\r
591 ;*\r
592 proc _x_file_RLDecode\r
593 ARG   handle:word,dest:dword\r
594         push bp\r
595         mov  bp,sp\r
596         push si\r
597         push di\r
598 \r
599 \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
604         cld               ; Move forward\r
605 \r
606         les  di,[dest]    ; point es:di -> uncompressed buffer\r
607 \r
608 @@UnpackLoop:\r
609 \r
610         GET_BYTE          ; Load a byte from file into AL\r
611 \r
612         cmp  al,80h       ; is it terminating null RL code\r
613         je   @@done       ; if so jump\r
614 \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
617 \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
626 \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
634 \r
635 @@NoRepeats:\r
636         inc  bx\r
637         stosb             ; store AL in destination buffer\r
638         jmp  short @@UnpackLoop\r
639 \r
640 @@FileError:\r
641         mov  ax,0\r
642         jmp  short @@exit\r
643 \r
644 @@done:\r
645         mov  ax,bx\r
646 @@exit:\r
647         pop  di\r
648         pop  si\r
649         pop  bp\r
650         ret\r
651 _x_file_RLDecode endp\r
652 \r
653         end\r
654 \r
655 \1a\r