ugBASIC 1.18
An isomorphic BASIC language compiler for retrocomputers
Loading...
Searching...
No Matches
rle.c
Go to the documentation of this file.
1/*****************************************************************************
2 * ugBASIC - an isomorphic BASIC language compiler for retrocomputers *
3 *****************************************************************************
4 * Copyright 2021-2026 Marco Spedaletti (asimov@mclink.it)
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *----------------------------------------------------------------------------
18 * Concesso in licenza secondo i termini della Licenza Apache, versione 2.0
19 * (la "Licenza"); è proibito usare questo file se non in conformità alla
20 * Licenza. Una copia della Licenza è disponibile all'indirizzo:
21 *
22 * http://www.apache.org/licenses/LICENSE-2.0
23 *
24 * Se non richiesto dalla legislazione vigente o concordato per iscritto,
25 * il software distribuito nei termini della Licenza è distribuito
26 * "COSÌ COM'È", SENZA GARANZIE O CONDIZIONI DI ALCUN TIPO, esplicite o
27 * implicite. Consultare la Licenza per il testo specifico che regola le
28 * autorizzazioni e le limitazioni previste dalla medesima.
29 ****************************************************************************/
30
31/****************************************************************************
32 * INCLUDE SECTION
33 ****************************************************************************/
34
35#include "rle.h"
36
37/****************************************************************************
38 * CODE SECTION
39 ****************************************************************************/
40
42
43 RLECompressor * rle = malloc( sizeof( RLECompressor ) );
44
45 memset( rle, 0, sizeof( RLECompressor ) );
46
47 return rle;
48
49}
50
51void rle_echo_state( RLECompressor * _rle, char _current, int _count ) {
52
53 switch( _rle->state ) {
54
55 // STARTING STATE
56 case RLE_CS_READY:
57
58 printf( "RLE_CS_READY:");
59
60 break;
61
62 // COUNTING THE CHARS
63 case RLE_CS_COUNTING:
64
65 printf( "RLE_CS_COUNTING:");
66
67 break;
68
69 case RLE_CS_EMIT:
70
71 printf( "RLE_CS_EMIT:");
72
73 break;
74
75 // EMIT LITERALS INSIDE THE STAGE AREA
77
78 printf( "RLE_CS_EMIT_CONTINUE:");
79
80 break;
81
82 }
83
84 printf( "current = 0x%2.2x, count = %d\n", (unsigned char) _current, (unsigned char) _count );
85
86}
87
88MemoryBlock * rle_compress( RLECompressor * _rle, MemoryBlock * _input, int _size, int * _output_size ) {
89
90 // Read pointer, move to the start of the area to compress.
91 MemoryBlock * pointer = _input, * endPointer = pointer + _size;
92
93 // Write pointer to a cleared area.
94 MemoryBlock * output = malloc( 3 * _size + 1 ), * wpointer = output;
95 memset( output, 0, _size );
96
97 char current = 0;
98 int count = 0;
99
100 // Loop until the ASF is finished.
101 while( _rle->state != RLE_CS_END_OF_BLOCK ) {
102
103 // printf( "INPUT: 0x%4.4x:0x%2.2x\n", (int) (pointer - _input), (unsigned char) *pointer );
104
105 switch( _rle->state ) {
106
107 // STARTING STATE
108 case RLE_CS_READY:
109
110 // First of all, if we reach the end of memory
111 // to be compressed, we pass into the final
112 // state and the compression will end.
113 if ( pointer == endPointer ) {
115 }
116 // Copy the literal pointed by the read pointer
117 // into the stage area, to be able to be used
118 // to detect frequent patterns.
119 else {
120 current = *pointer;
121 count = 1;
122 _rle->state = RLE_CS_COUNTING;
123 }
124
125 break;
126
127 // COUNTING THE CHARS
128 case RLE_CS_COUNTING:
129
130 // Move forward by 1 byte.
131 ++pointer;
132
133 // If the end of the memory is reached,
134 // we must emit the literal up to now.
135 if ( pointer == endPointer ) {
136 _rle->state = RLE_CS_EMIT;
137 break;
138 }
139
140 // If the character is different from the
141 // actual, we have to emit the element.
142 if ( *pointer != current ) {
143 _rle->state = RLE_CS_EMIT;
144 break;
145 }
146
147 ++count;
148
149 // If we reached the limit of the duplicate
150 // representation, we have to emit the
151 // element and to continue,
152 // Note: we use 254 since 255 is used as
153 // control character.
154 if ( count == 254 ) {
156 break;
157 }
158
159 break;
160
161 case RLE_CS_EMIT:
162
163 // We emit the element and return to initial state.
164
165 if ( count > 3 ) {
166 *wpointer = 0xff;
167 ++wpointer;
168 *wpointer = count;
169 ++wpointer;
170 *wpointer = current;
171 ++wpointer;
172 // printf( "OUTPUT: 0x%4.4x:0xff 0x%2.2x 0x%2.2x\n", (int) ( wpointer - output ), (unsigned char) count, (unsigned char) current );
173 } else {
174 while( count ) {
175 if ( (unsigned char) current == 0xff ) {
176 *wpointer = 0xff;
177 ++wpointer;
178 // printf( "OUTPUT: 0x%4.4x:0xff (escape)\n", (int) ( wpointer - output ) );
179 }
180 *wpointer = current;
181 ++wpointer;
182 // printf( "OUTPUT: 0x%4.4x:0x%2.2x\n", (int) ( wpointer - output ), (unsigned char) current );
183 --count;
184 }
185 }
186 count = 0;
187 _rle->state = RLE_CS_READY;
188 break;
189
190 // EMIT LITERALS INSIDE THE STAGE AREA
192
193 // We emit the element and return to counting.
194 *wpointer = 0xff;
195 ++wpointer;
196 *wpointer = count;
197 ++wpointer;
198 *wpointer = current;
199 ++wpointer;
200
201 // printf( "OUTPUT: 0x%4.4x:0xff 0x%2.2x 0x%2.2x\n", (int) ( wpointer - output ), (unsigned char) count, (unsigned char) current );
202
203 count = 0;
204 _rle->state = RLE_CS_COUNTING;
205 break;
206
207 }
208
209 // rle_echo_state( _rle, current, count );
210
211 }
212
213 *wpointer = 0xfe;
214 ++wpointer;
215
216 *_output_size = (wpointer - output);
217
218 // printf( "\n\n" );
219
220 return output;
221
222}
223
224void rle_free( RLECompressor * _rle ) {
225
226 free( _rle );
227
228}
229
230MemoryBlock * rle_uncompress( RLECompressor * _rle, MemoryBlock * _input, int _size, int * _output_size ) {
231
232 // We allocate (precautiously) a memory block of 200
233 // times the input buffer.
234 *_output_size = 200 * _size;
235 MemoryBlock * output = malloc( *_output_size );
236
237 // This is the currently token examinated from
238 // the input stream.
239 MemoryBlock token;
240
241 // Read pointer .
242 MemoryBlock * pointer = _input;
243
244 // Write pointer.
245 MemoryBlock * wpointer = output;
246
247 int done = 0;
248
249 // Loop through the entire input stream.
250 do {
251
252 // Take the current token from the input stream
253 // and move to the next element of the stream.
254 token = *pointer;
255 ++pointer;
256
257 // A token of zero (0xfe) means "end of block".
258 // Nothing must be done.
259 if (token == 0xfe) {
260 // printf( "EOB\n");
261 done = 1;
262 }
263
264 // If the value of token is 0xff...
265 else if (token == 0xff) {
266
267 // Read the next.
268 token = *pointer;
269 ++pointer;
270
271 // If it is 0xff, it means that is 0xff, actually!
272 if ( token == 0xff ) {
273 *wpointer = 0xff;
274 ++wpointer;
275 // printf( "0xff (literal, 2 bytes)\n");
276 }
277
278 // Otherwise, we will output the duplications.
279 else {
280
281 int count = token;
282 // Read the next.
283 token = *pointer;
284 ++pointer;
285
286 // printf( "%d x 0x%2.2x (literal)\n", (unsigned char) count, (unsigned char) token);
287 while( count ) {
288 *wpointer = token;
289 ++wpointer;
290 --count;
291 }
292
293 }
294
295 }
296
297 // Output the token "as is"
298 else {
299 *wpointer = token;
300 ++wpointer;
301 // printf( "0x%2.2x (literal, 1 byte)\n", (unsigned char) token);
302 }
303
304 } while (!done);
305
306 *_output_size = (wpointer - output);
307
308 return output;
309}
unsigned char MemoryBlock
Definition msc1.h:90
MemoryBlock * rle_compress(RLECompressor *_rle, MemoryBlock *_input, int _size, int *_output_size)
Definition rle.c:88
void rle_echo_state(RLECompressor *_rle, char _current, int _count)
Definition rle.c:51
RLECompressor * rle_create()
Definition rle.c:41
MemoryBlock * rle_uncompress(RLECompressor *_rle, MemoryBlock *_input, int _size, int *_output_size)
Definition rle.c:230
void rle_free(RLECompressor *_rle)
Definition rle.c:224
struct _RLECompressor RLECompressor
@ RLE_CS_COUNTING
Definition rle.h:54
@ RLE_CS_END_OF_BLOCK
Definition rle.h:63
@ RLE_CS_EMIT
Definition rle.h:57
@ RLE_CS_EMIT_CONTINUE
Definition rle.h:60
@ RLE_CS_READY
Definition rle.h:51
RLECompressorState state
Definition rle.h:69
void * malloc(YYSIZE_T)
void free(void *)
#define done()
Definition ugbc.h:4389