File: | compress.c |
Warning: | line 353, column 35 Result of 'calloc' is converted to a pointer of type 'uint8_t', which is incompatible with sizeof operand type 'uint8_t *' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | ============================================================================ |
3 | Name : compress.c |
4 | Author : nanash1 |
5 | Version : 0.9 |
6 | Description : Compresses Grandia Saturn graphics |
7 | ============================================================================ |
8 | */ |
9 | |
10 | /** |
11 | * This software is supplied "AS IS" without any warranties of |
12 | * any kind. The author, nanash1, assumes no responsibility |
13 | * or liability for the use of the software, conveys no license or rights under any |
14 | * patent, copyright, mask work right, or any other intellectual property rights in |
15 | * or to any products. The author also makes no |
16 | * representation or warranty that such application will be suitable for the |
17 | * specified use without further testing or modification. |
18 | * |
19 | * Permission to use, copy, modify, and distribute this software and its |
20 | * documentation is hereby granted. This copyright, permission, and disclaimer |
21 | * notice must appear in all copies of this code. |
22 | */ |
23 | |
24 | #include <stdio.h> |
25 | #include <stdlib.h> |
26 | #include <stdint.h> |
27 | #include <string.h> |
28 | #include <byteswap.h> |
29 | #include "compression.h" |
30 | |
31 | static uint8_t compr_lut_shifts[16]; |
32 | static uint8_t compr_lut_offset[16]; |
33 | static uint8_t compr_shifts_stop; |
34 | static uint8_t compr_offset_stop; |
35 | |
36 | /** |
37 | * @brief Generates the decompression lut |
38 | * @param p_comp_lut Pointer to the memory the table is written at |
39 | * @return Status 0:Success 1:Error |
40 | */ |
41 | static uint8_t generate_lut(uint8_t* p_comp_lut) |
42 | { |
43 | uint8_t rtn = 0; |
44 | uint8_t bit_num; |
45 | uint8_t max_bit_num; |
46 | uint8_t decode_char; |
47 | uint16_t offset = 0; |
48 | |
49 | for(uint_fast8_t j = 0; j < 17; j++){ |
50 | max_bit_num = 0; |
51 | for(uint_fast8_t i = 0; i < 17; i++){ |
52 | if (i%2){ |
53 | bit_num = *(p_comp_lut + (i/2)) & 0xf; |
54 | } else { |
55 | bit_num = *(p_comp_lut + (i/2)) >> 4; |
56 | } |
57 | |
58 | if (bit_num > max_bit_num){ |
59 | max_bit_num = bit_num; |
60 | decode_char = i; |
61 | } |
62 | } |
63 | |
64 | if (max_bit_num > 8){ |
65 | rtn = 1; |
66 | break; |
67 | } else if (max_bit_num == 0){ |
68 | rtn = 0; |
69 | break; |
70 | } |
71 | |
72 | if (decode_char%2){ |
73 | *(p_comp_lut + (decode_char/2)) &= 0xf0; |
74 | } else { |
75 | *(p_comp_lut + (decode_char/2)) &= 0xf; |
76 | } |
77 | |
78 | if (decode_char == 16){ |
79 | compr_offset_stop = offset; |
80 | compr_shifts_stop = max_bit_num; |
81 | } else { |
82 | compr_lut_offset[decode_char] = offset; |
83 | compr_lut_shifts[decode_char] = max_bit_num; |
84 | } |
85 | offset += lut_seed[max_bit_num]; |
86 | } |
87 | |
88 | /* check if the table is within bounds */ |
89 | if (offset != 256){ |
90 | rtn = 1; |
91 | } |
92 | return rtn; |
93 | |
94 | } |
95 | |
96 | /* input data variables */ |
97 | uint8_t* p_input_data; |
98 | uint_fast8_t input_bit_pos = 0; |
99 | |
100 | /* RLE output variables */ |
101 | uint8_t* p_rle_data; |
102 | uint_fast8_t rle_bit_pos = 1; |
103 | |
104 | /* table output variables */ |
105 | uint8_t* p_delta_data; |
106 | uint_fast8_t delta_bit_pos = 0; |
107 | |
108 | uint8_t* p_end_of_file; |
109 | uint8_t end_of_file = 0; |
110 | |
111 | /** |
112 | * @brief Stores or restores the current position in the input stream |
113 | * @param restore_flag If set, position is restored |
114 | * @return Nothing |
115 | */ |
116 | static inline void store_input_pos(uint8_t restore_flag) |
117 | { |
118 | static uint8_t* last_p_input_data; |
119 | static uint_fast8_t last_input_bit_pos; |
120 | |
121 | if (restore_flag){ |
122 | p_input_data = last_p_input_data; |
123 | input_bit_pos = last_input_bit_pos; |
124 | } else { |
125 | last_p_input_data = p_input_data; |
126 | last_input_bit_pos = input_bit_pos; |
127 | } |
128 | } |
129 | |
130 | /** |
131 | * @brief Retrieves the next 4 bits of data from the input stream |
132 | * @return Next 4 bits of input stream data |
133 | */ |
134 | static uint8_t get_next_input_bits(void) |
135 | { |
136 | uint8_t rtn; |
137 | |
138 | if (p_input_data > p_end_of_file){ |
139 | end_of_file = 1; |
140 | return 0; |
141 | } |
142 | |
143 | rtn = (*p_input_data >> (4 - input_bit_pos)) & 0xf; |
144 | input_bit_pos += 4; |
145 | if (input_bit_pos > 4){ |
146 | input_bit_pos = 0; |
147 | p_input_data++; |
148 | } |
149 | return rtn; |
150 | } |
151 | |
152 | /** |
153 | * @brief Tests the next bits for zero groups |
154 | * @param p_num_bits Pointer is set to the length of the next group of bits |
155 | * @param rle_limit Minimum number of zeros before the stop condition is set |
156 | * @return 1: if the next group is zero, 0: if the next group is not zero |
157 | */ |
158 | static uint8_t test_next_bits(uint_fast16_t* p_num_bits, uint8_t rle_limit) |
159 | { |
160 | *p_num_bits = 0; |
161 | |
162 | uint8_t ref; |
163 | uint8_t test_bits; |
164 | uint8_t* _p_input_data; |
165 | uint_fast8_t _input_bit_pos; |
166 | uint8_t zero_cntr; |
167 | |
168 | ref = get_next_input_bits() == 0; |
169 | do { |
170 | _p_input_data = p_input_data; |
171 | _input_bit_pos = input_bit_pos; |
172 | test_bits = get_next_input_bits() == 0; |
173 | (*p_num_bits)++; |
174 | |
175 | /* look ahead for zeros */ |
176 | zero_cntr = rle_limit - 1; |
177 | while ((!ref && test_bits) && zero_cntr--){ |
178 | test_bits = get_next_input_bits() == 0; |
179 | (*p_num_bits)++; |
180 | } |
181 | |
182 | } while ( ref == test_bits && !end_of_file); |
183 | |
184 | zero_cntr++; |
185 | if (!zero_cntr){ |
186 | *p_num_bits -= rle_limit - 1; |
187 | } |
188 | |
189 | if (ref){ |
190 | p_input_data = _p_input_data; |
191 | input_bit_pos = _input_bit_pos; |
192 | } |
193 | |
194 | return ref; |
195 | } |
196 | |
197 | /** |
198 | * @brief Writes a new zeros block to the rle data stream |
199 | * @param num_zeros Number of zeros |
200 | * @return Nothing |
201 | */ |
202 | static void encode_zeros(uint16_t num_zeros) |
203 | { |
204 | static uint16_t prev_num_zeros = 0; |
205 | |
206 | uint32_t new_data; |
207 | uint_fast8_t new_data_len; |
208 | |
209 | uint16_t zero_blocks = num_zeros / 8; |
210 | uint8_t zeros = num_zeros % 8; |
211 | |
212 | if ( (num_zeros - prev_num_zeros) > -7 && (num_zeros - prev_num_zeros) < 7){ |
213 | new_data = (num_zeros - prev_num_zeros) + 6; |
214 | new_data_len = 1; |
215 | } else if ( (num_zeros - prev_num_zeros) > -15 && (num_zeros - prev_num_zeros) < 15){ |
216 | new_data = 0xd << 4; |
217 | if ((num_zeros - prev_num_zeros) >= 7 ){ |
218 | new_data |= (num_zeros - prev_num_zeros) + 1; |
219 | } else { |
220 | new_data |= (num_zeros - prev_num_zeros) + 14; |
221 | } |
222 | new_data_len = 2; |
223 | } else if (zero_blocks < 32){ |
224 | new_data = 0xe << 8; |
225 | new_data |= zero_blocks << 3 | zeros; |
226 | new_data_len = 3; |
227 | } else { |
228 | new_data = 0xf << 16; |
229 | new_data |= zero_blocks << 3 | zeros; |
230 | new_data_len = 5; |
231 | } |
232 | |
233 | uint8_t next_bits; |
234 | while(new_data_len--){ |
235 | next_bits = (new_data >> (new_data_len * 4)) & 0xf; |
236 | *p_rle_data |= next_bits << ((rle_bit_pos % 2) * 4); |
237 | if (!(rle_bit_pos % 2)){ |
238 | p_rle_data++; |
239 | *p_rle_data = 0; |
240 | } |
241 | rle_bit_pos++; |
242 | } |
243 | |
244 | prev_num_zeros = num_zeros; |
245 | } |
246 | |
247 | /** |
248 | * @brief Writes table encoded data to the stream |
249 | * @param mode Compression mode |
250 | * @param num_bits Size of the input data |
251 | * @return Nothing |
252 | */ |
253 | static void encode_data(enum comp_mode mode, uint16_t num_bits) |
254 | { |
255 | static uint8_t val = 0; |
256 | uint8_t next_val; |
257 | uint8_t diff; |
258 | uint8_t shifts; |
259 | |
260 | while(num_bits--){ |
261 | next_val = get_next_input_bits(); |
262 | switch (mode){ |
263 | case SUB_MODE: |
264 | diff = (val - next_val) & 0xf; |
265 | break; |
266 | case MOV_MODE: |
267 | diff = next_val & 0xf; |
268 | break; |
269 | case XOR_MODE: |
270 | diff = (val ^ next_val) & 0xf; |
271 | break; |
272 | } |
273 | shifts = compr_lut_shifts[diff]; |
274 | val = next_val; |
275 | |
276 | /* write the lut data to the current bit position */ |
277 | if (delta_bit_pos == 0){ |
278 | *p_delta_data = compr_lut_offset[diff]; |
279 | } else { |
280 | *p_delta_data |= compr_lut_offset[diff] >> delta_bit_pos; |
281 | *(p_delta_data + 1) |= compr_lut_offset[diff] << ( 8 - delta_bit_pos); |
282 | } |
283 | |
284 | /* advance the pointer if the shift leaves the boundaries */ |
285 | delta_bit_pos += shifts; |
286 | if (delta_bit_pos >= 8){ |
287 | delta_bit_pos -= 8; |
288 | p_delta_data++; |
289 | } |
290 | } |
291 | |
292 | if (delta_bit_pos == 0){ |
293 | *p_delta_data = compr_offset_stop; |
294 | } else { |
295 | *p_delta_data |= compr_offset_stop >> delta_bit_pos; |
296 | *(p_delta_data + 1) |= compr_offset_stop << ( 8 - delta_bit_pos); |
297 | } |
298 | |
299 | delta_bit_pos += compr_shifts_stop; |
300 | if (delta_bit_pos >= 8){ |
301 | delta_bit_pos -= 8; |
302 | p_delta_data++; |
303 | } |
304 | |
305 | } |
306 | |
307 | /** |
308 | * @brief Compresses images for Grandia |
309 | * @param mode Compression mode to use |
310 | * @param input Input file name as string |
311 | * @param output Output file name as string |
312 | * @param p_table Pointer to compression table |
313 | * @param rle_limit RLE limit parameter |
314 | * @return Status |
315 | */ |
316 | compression_status_t compress( |
317 | enum comp_mode mode, |
318 | const char* input, |
319 | const char* output, |
320 | uint8_t* p_table, |
321 | uint8_t rle_limit) |
322 | { |
323 | int size = 0; |
324 | int rsize = 0; |
325 | FILE *f = fopen(input, "rb"); |
326 | |
327 | uint8_t table[9]; |
328 | memcpy(table, p_table, 9); |
329 | |
330 | if (f == NULL((void*)0)){ |
331 | return FILE_NOT_FOUND; |
332 | } |
333 | |
334 | fseek(f, 0, SEEK_END2); |
335 | size = ftell(f); |
336 | fseek(f, 0, SEEK_SET0); |
337 | |
338 | p_input_data = (uint8_t *) malloc(size); |
339 | p_end_of_file = p_input_data + size -1; |
340 | rsize = fread(p_input_data, sizeof(uint8_t), size, f); |
341 | |
342 | if (size != rsize) |
343 | { |
344 | free(p_input_data); |
345 | return INSUFFICIENT_MEM; |
346 | } |
347 | fclose(f); |
348 | |
349 | |
350 | /* allocate memory for compressed data */ |
351 | uint8_t* p_delta_data_start; |
352 | uint8_t* p_rle_data_start; |
353 | p_delta_data_start = (uint8_t *) calloc(32000, sizeof(uint8_t*)); |
Result of 'calloc' is converted to a pointer of type 'uint8_t', which is incompatible with sizeof operand type 'uint8_t *' | |
354 | p_rle_data_start = (uint8_t *) malloc(16000); |
355 | p_delta_data = p_delta_data_start; |
356 | p_rle_data = p_rle_data_start; |
357 | |
358 | /* generate look up table */ |
359 | if (generate_lut(p_table)){ |
360 | free(p_delta_data_start); |
361 | free(p_rle_data_start); |
362 | free(p_input_data); |
363 | return INVALID_TABLE; |
364 | } |
365 | |
366 | uint_fast16_t bit_cntr = 0; |
367 | uint8_t is_zeros; |
368 | *p_rle_data = 0; |
369 | uint_fast32_t run_cntr = 0; |
370 | while(!end_of_file){ |
371 | |
372 | run_cntr++; |
373 | if (run_cntr > MAX_COMP_LEN(5000)){ |
374 | free(p_delta_data_start); |
375 | free(p_rle_data_start); |
376 | free(p_input_data); |
377 | return RUNAWAY_DATA; |
378 | } |
379 | |
380 | store_input_pos(0); |
381 | is_zeros = test_next_bits(&bit_cntr, rle_limit); |
382 | |
383 | if (is_zeros){ |
384 | encode_zeros(bit_cntr); |
385 | } else { |
386 | store_input_pos(1); |
387 | encode_data(mode, bit_cntr); |
388 | } |
389 | } |
390 | |
391 | /* write remaining rle data and stop condition */ |
392 | uint32_t new_data = 0xe00; |
393 | uint8_t new_data_len = 3; |
394 | uint8_t next_bits; |
395 | while(new_data_len--){ |
396 | next_bits = (new_data >> (new_data_len * 4)) & 0xf; |
397 | *p_rle_data |= next_bits << ((rle_bit_pos % 2) * 4); |
398 | if (!(rle_bit_pos % 2)){ |
399 | p_rle_data++; |
400 | *p_rle_data = 0; |
401 | } |
402 | rle_bit_pos++; |
403 | } |
404 | if (!(rle_bit_pos % 2)){ |
405 | p_rle_data++; |
406 | } |
407 | |
408 | /* write lut data stop condition if there is a trailing rle block */ |
409 | if (is_zeros){ |
410 | if (delta_bit_pos == 0){ |
411 | *p_delta_data = compr_offset_stop; |
412 | } else { |
413 | *p_delta_data |= compr_offset_stop >> delta_bit_pos; |
414 | *(p_delta_data + 1) |= compr_offset_stop << ( 8 - delta_bit_pos); |
415 | } |
416 | |
417 | delta_bit_pos += compr_shifts_stop; |
418 | if (delta_bit_pos >= 8){ |
419 | delta_bit_pos -= 8; |
420 | p_delta_data++; |
421 | } |
422 | } |
423 | |
424 | /* write remaining lut data */ |
425 | if (delta_bit_pos != 0){ |
426 | p_delta_data++; |
427 | } |
428 | |
429 | /* write the header */ |
430 | uint16_t head; |
431 | switch (mode){ |
432 | case SUB_MODE: |
433 | head = 0b10 << 14; |
434 | break; |
435 | case MOV_MODE: |
436 | head = 0b00 << 14; |
437 | break; |
438 | case XOR_MODE: |
439 | head = 0b01 << 14; |
440 | break; |
441 | } |
442 | head |= (uint16_t) (p_rle_data - p_rle_data_start); |
443 | head = __bswap_16(head); |
444 | |
445 | f = fopen(output, "wb"); |
446 | fwrite(&head, sizeof(int16_t), 1, f); |
447 | fwrite(p_rle_data_start, sizeof(int8_t), (int32_t) (p_rle_data - p_rle_data_start), f); |
448 | fwrite(table, sizeof(int8_t), 9, f); |
449 | fwrite(p_delta_data_start, sizeof(int8_t), (int32_t) (p_delta_data - p_delta_data_start), f); |
450 | fclose(f); |
451 | |
452 | free(p_delta_data_start); |
453 | free(p_rle_data_start); |
454 | free(p_input_data); |
455 | |
456 | return SUCCESS; |
457 | } |