Bug Summary

File:compress.c
Warning:line 344, column 3
Opened File never closed. Potential Resource leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name compress.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -mrelocation-model pic -pic-level 2 -pic-is-pie -mthread-model posix -mframe-pointer=all -fmath-errno -masm-verbose -mconstructor-aliases -munwind-tables -fuse-init-array -target-cpu x86-64 -dwarf-column-info -debugger-tuning=gdb -resource-dir /usr/lib/clang/10.0.0 -I ./src -I ./src/inc -internal-isystem /usr/local/include -internal-isystem /usr/lib/clang/10.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-sign-compare -std=c11 -fdebug-compilation-dir /tmp/ssgctv09 -ferror-limit 19 -fmessage-length 0 -stack-protector 2 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-checker alpha.core.CallAndMessageUnInitRefArg -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.Conversion -analyzer-checker alpha.core.FixedAddr -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.core.PointerArithm -analyzer-checker alpha.core.SizeofPtr -analyzer-checker alpha.core.TestAfterDivZero -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.BlockInCriticalSection -analyzer-checker alpha.unix.Chroot -analyzer-checker alpha.unix.PthreadLock -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.Stream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker valist.CopyToSelf -analyzer-checker valist.Uninitialized -analyzer-checker valist.Unterminated -analyzer-checker security.FloatLoopCounter -analyzer-checker security.insecureAPI.strcpy -analyzer-max-loop 1536 -analyzer-output=html -faddrsig -o /tmp/scan-build-2019-10-07-120410-3045-1 -x c src/compress.c
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
31static uint8_t compr_lut_shifts[16];
32static uint8_t compr_lut_offset[16];
33static uint8_t compr_shifts_stop;
34static 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 */
41static 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 */
97uint8_t* p_input_data;
98uint_fast8_t input_bit_pos = 0;
99
100/* RLE output variables */
101uint8_t* p_rle_data;
102uint_fast8_t rle_bit_pos = 1;
103
104/* table output variables */
105uint8_t* p_delta_data;
106uint_fast8_t delta_bit_pos = 0;
107
108uint8_t* p_end_of_file;
109uint8_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 */
116static 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 */
134static 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 */
158static 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 */
202static 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 */
253static 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 */
316compression_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
0.1
'f' is not equal to NULL
== NULL((void*)0)){
1
Taking false branch
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)
2
Assuming 'size' is not equal to 'rsize'
3
Taking true branch
343 {
344 free(p_input_data);
4
Opened File never closed. Potential Resource leak
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*));
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}