/src/cmp_tool/programs/cmp_io.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file cmp_io.c |
3 | | * @author Dominik Loidolt (dominik.loidolt@univie.ac.at) |
4 | | * @author Johannes Seelig (johannes.seelig@univie.ac.at) |
5 | | * @date 2020 |
6 | | * |
7 | | * @copyright GPLv2 |
8 | | * This program is free software; you can redistribute it and/or modify it |
9 | | * under the terms and conditions of the GNU General Public License, |
10 | | * version 2, as published by the Free Software Foundation. |
11 | | * |
12 | | * This program is distributed in the hope it will be useful, but WITHOUT |
13 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
15 | | * more details. |
16 | | * |
17 | | * @brief compression tool input/output library |
18 | | * @warning this part of the software is not intended to run on-board on the ICU. |
19 | | */ |
20 | | |
21 | | #include <stdint.h> |
22 | | #include <stdio.h> |
23 | | #include <stdlib.h> |
24 | | #include <string.h> |
25 | | #include <errno.h> |
26 | | #include <ctype.h> |
27 | | #include <sys/stat.h> |
28 | | |
29 | | |
30 | | #include <cmp_tool-config.h> |
31 | | #include <compiler.h> |
32 | | |
33 | | #include "cmp_io.h" |
34 | | #include <cmp_support.h> |
35 | | #include <cmp_chunk.h> |
36 | | #include <rdcu_cmd.h> |
37 | | #include <byteorder.h> |
38 | | #include <cmp_data_types.h> |
39 | | #include <leon_inttypes.h> |
40 | | |
41 | | |
42 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
43 | | /* Redefine (f)printf to do nothing */ |
44 | | __extension__ |
45 | 5.39k | #define printf(...) do {} while (0) |
46 | 7.16k | #define fprintf(...) do {} while (0) |
47 | | #endif |
48 | | |
49 | | |
50 | | /* directory to convert from data_type to string */ |
51 | | static const struct { |
52 | | enum cmp_data_type data_type; |
53 | | const char *str; |
54 | | } data_type_string_table[] = { |
55 | | {DATA_TYPE_IMAGETTE, "DATA_TYPE_IMAGETTE"}, |
56 | | {DATA_TYPE_IMAGETTE_ADAPTIVE, "DATA_TYPE_IMAGETTE_ADAPTIVE"}, |
57 | | {DATA_TYPE_SAT_IMAGETTE, "DATA_TYPE_SAT_IMAGETTE"}, |
58 | | {DATA_TYPE_SAT_IMAGETTE_ADAPTIVE, "DATA_TYPE_SAT_IMAGETTE_ADAPTIVE"}, |
59 | | {DATA_TYPE_OFFSET, "DATA_TYPE_OFFSET"}, |
60 | | {DATA_TYPE_BACKGROUND, "DATA_TYPE_BACKGROUND"}, |
61 | | {DATA_TYPE_SMEARING, "DATA_TYPE_SMEARING"}, |
62 | | {DATA_TYPE_S_FX, "DATA_TYPE_S_FX"}, |
63 | | {DATA_TYPE_S_FX_EFX, "DATA_TYPE_S_FX_EFX"}, |
64 | | {DATA_TYPE_S_FX_NCOB, "DATA_TYPE_S_FX_NCOB"}, |
65 | | {DATA_TYPE_S_FX_EFX_NCOB_ECOB, "DATA_TYPE_S_FX_EFX_NCOB_ECOB"}, |
66 | | {DATA_TYPE_L_FX, "DATA_TYPE_L_FX"}, |
67 | | {DATA_TYPE_L_FX_EFX, "DATA_TYPE_L_FX_EFX"}, |
68 | | {DATA_TYPE_L_FX_NCOB, "DATA_TYPE_L_FX_NCOB"}, |
69 | | {DATA_TYPE_L_FX_EFX_NCOB_ECOB, "DATA_TYPE_L_FX_EFX_NCOB_ECOB"}, |
70 | | {DATA_TYPE_F_FX, "DATA_TYPE_F_FX"}, |
71 | | {DATA_TYPE_F_FX_EFX, "DATA_TYPE_F_FX_EFX"}, |
72 | | {DATA_TYPE_F_FX_NCOB, "DATA_TYPE_F_FX_NCOB"}, |
73 | | {DATA_TYPE_F_FX_EFX_NCOB_ECOB, "DATA_TYPE_F_FX_EFX_NCOB_ECOB"}, |
74 | | {DATA_TYPE_F_CAM_IMAGETTE, "DATA_TYPE_F_CAM_IMAGETTE"}, |
75 | | {DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE, "DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE"}, |
76 | | {DATA_TYPE_F_CAM_OFFSET, "DATA_TYPE_F_CAM_OFFSET"}, |
77 | | {DATA_TYPE_F_CAM_BACKGROUND, "DATA_TYPE_F_CAM_BACKGROUND"}, |
78 | | {DATA_TYPE_CHUNK, "DATA_TYPE_CHUNK"}, |
79 | | {DATA_TYPE_UNKNOWN, "DATA_TYPE_UNKNOWN"} |
80 | | }; |
81 | | |
82 | | |
83 | | /** |
84 | | * @brief print help information |
85 | | * |
86 | | * @param program_name name of the program |
87 | | */ |
88 | | |
89 | | void print_help(const char *program_name MAYBE_UNUSED) |
90 | 207 | { |
91 | 207 | printf("usage: %s [options] [<argument>]\n", program_name); |
92 | 207 | printf("General Options:\n"); |
93 | 207 | printf(" -h, --help Print this help text and exit\n"); |
94 | 207 | printf(" -o <prefix> Use the <prefix> for output files\n"); |
95 | 207 | printf(" -n, --model_cfg Print a default model configuration and exit\n"); |
96 | 207 | printf(" --diff_cfg Print a default 1d-differencing configuration and exit\n"); |
97 | 207 | printf(" -b, --binary Read and write files in binary format\n"); |
98 | 207 | printf(" -a, --rdcu_par Add additional RDCU control parameters\n"); |
99 | 207 | printf(" -V, --version Print program version and exit\n"); |
100 | 207 | printf(" -v, -vv, --verbose Print various debugging information, -vv is extra verbose\n"); |
101 | 207 | printf("Compression Options:\n"); |
102 | 207 | printf(" -c <file> File containing the compressing configuration\n"); |
103 | 207 | printf(" -d <file> File containing the data to be compressed\n"); |
104 | 207 | printf(" -m <file> File containing the model of the data to be compressed\n"); |
105 | 207 | printf(" --no_header Do not add a compression entity header in front of the compressed data\n"); |
106 | 207 | printf(" --rdcu_pkt Generate RMAP packets for an RDCU compression\n"); |
107 | 207 | printf(" --last_info <.info file> Generate RMAP packets for an RDCU compression with parallel read of the last results\n"); |
108 | 207 | printf("Decompression Options:\n"); |
109 | 207 | printf(" -d <file> File containing the compressed data\n"); |
110 | 207 | printf(" -m <file> File containing the model of the compressed data\n"); |
111 | 207 | printf(" -i <file> File containing the decompression information (required if --no_header was used)\n"); |
112 | 207 | printf("Guessing Options:\n"); |
113 | 207 | printf(" --guess <mode> Search for a good configuration for compression <mode>\n"); |
114 | 207 | printf(" -d <file> File containing the data to be compressed\n"); |
115 | 207 | printf(" -m <file> File containing the model of the data to be compressed\n"); |
116 | 207 | printf(" --guess_level <level> Set guess level to <level> (optional)\n"); |
117 | 207 | } |
118 | | |
119 | | |
120 | | /** |
121 | | * @brief opens a file with a name that is a concatenation of directory and file |
122 | | * name. |
123 | | * |
124 | | * @param dirname first string of concatenation |
125 | | * @param filename security string of concatenation |
126 | | * |
127 | | * @return a pointer to the opened file |
128 | | * |
129 | | * @see https://developers.redhat.com/blog/2018/05/24/detecting-string-truncation-with-gcc-8/ |
130 | | */ |
131 | | |
132 | | static FILE *open_file(const char *dirname, const char *filename) |
133 | 333 | { |
134 | 333 | char *pathname; |
135 | 333 | int n; |
136 | | |
137 | 333 | if (!dirname) |
138 | 0 | return NULL; |
139 | | |
140 | 333 | if (!filename) |
141 | 0 | return NULL; |
142 | | |
143 | 333 | errno = 0; |
144 | 333 | n = snprintf(0, 0, "%s%s", dirname, filename); |
145 | | |
146 | 333 | if (n < 0) { |
147 | 0 | perror("snprintf failed"); |
148 | 0 | abort(); |
149 | 0 | } |
150 | | |
151 | 333 | errno = 0; |
152 | 333 | pathname = (char *)alloca((size_t)n + 1); |
153 | | |
154 | 333 | errno = 0; |
155 | 333 | n = snprintf(pathname, (size_t)n + 1, "%s%s", dirname, filename); |
156 | 333 | if (n < 0) { |
157 | 0 | perror("snprintf failed"); |
158 | 0 | abort(); |
159 | 0 | } |
160 | | |
161 | 333 | return fopen(pathname, "wb"); |
162 | 333 | } |
163 | | |
164 | | |
165 | | /** |
166 | | * @brief write uncompressed input data in big-endian to an output file |
167 | | * |
168 | | * @param data the data to write a file |
169 | | * @param data_size size of the data in bytes |
170 | | * @param cmp_type RDCU or chunk compression? |
171 | | * @param output_prefix file name without file extension |
172 | | * @param name_extension extension (with leading point character) |
173 | | * @param flags CMP_IO_VERBOSE_EXTRA print verbose output if set |
174 | | * CMP_IO_BINARY write the file in binary format if set |
175 | | * |
176 | | * @returns 0 on success, error otherwise |
177 | | */ |
178 | | |
179 | | int write_input_data_to_file(const void *data, uint32_t data_size, enum cmp_type cmp_type, |
180 | | const char *output_prefix, const char *name_extension, int flags) |
181 | 18 | { |
182 | 18 | uint8_t *tmp_buf; |
183 | 18 | int return_value; |
184 | | |
185 | 18 | if (!data) |
186 | 0 | abort(); |
187 | | |
188 | 18 | if (data_size == 0) |
189 | 2 | return 0; |
190 | | |
191 | 16 | tmp_buf = malloc(data_size); |
192 | 16 | if (!tmp_buf) |
193 | 0 | return -1; |
194 | | |
195 | 16 | memcpy(tmp_buf, data, data_size); |
196 | | |
197 | 16 | switch (cmp_type) { |
198 | 3 | case CMP_TYPE_CHUNK: |
199 | 3 | return_value = cpu_to_be_chunk(tmp_buf, data_size); |
200 | 3 | break; |
201 | 13 | case CMP_TYPE_RDCU: |
202 | 13 | return_value = be_to_cpu_data_type(tmp_buf, data_size, DATA_TYPE_IMAGETTE); |
203 | 13 | break; |
204 | 0 | case CMP_TYPE_ERROR: |
205 | 0 | default: |
206 | 0 | return_value = -1; |
207 | 0 | break; |
208 | 16 | } |
209 | | |
210 | 16 | if (!return_value) |
211 | 16 | return_value = write_data_to_file(tmp_buf, data_size, output_prefix, |
212 | 16 | name_extension, flags); |
213 | | |
214 | 16 | free(tmp_buf); |
215 | | |
216 | 16 | return return_value; |
217 | 16 | } |
218 | | |
219 | | |
220 | | /** |
221 | | * @brief write a buffer to an output file |
222 | | * |
223 | | * @param buf the buffer to write a file |
224 | | * @param buf_size size of the buffer in bytes |
225 | | * |
226 | | * @param output_prefix file name without file extension |
227 | | * @param name_extension file extension (with leading point character) |
228 | | * |
229 | | * @param flags CMP_IO_VERBOSE_EXTRA print verbose output if set |
230 | | * CMP_IO_BINARY write the file in binary format if set |
231 | | * |
232 | | * @returns 0 on success, error otherwise |
233 | | */ |
234 | | |
235 | | int write_data_to_file(const void *buf, uint32_t buf_size, const char *output_prefix, |
236 | | const char *name_extension, int flags) |
237 | 232 | { |
238 | 232 | FILE *fp; |
239 | 232 | const uint8_t *p = (const uint8_t *)buf; |
240 | 232 | const uint8_t *output_file_data; |
241 | 232 | uint8_t *tmp_buf = NULL; |
242 | 232 | size_t output_file_size; |
243 | | |
244 | 232 | if (!buf) |
245 | 0 | abort(); |
246 | | |
247 | 232 | if (buf_size == 0) |
248 | 0 | return 0; |
249 | | |
250 | 232 | fp = open_file(output_prefix, name_extension); |
251 | 232 | if (fp == NULL) { |
252 | 0 | fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix, |
253 | 0 | name_extension, strerror(errno)); |
254 | 0 | return -1; |
255 | 0 | } |
256 | | |
257 | 232 | if (flags & CMP_IO_BINARY) { |
258 | 0 | output_file_size = buf_size; |
259 | 0 | output_file_data = buf; |
260 | 232 | } else { |
261 | 232 | size_t i, j; |
262 | 232 | const uint8_t lut[0x10] = "0123456789abcdef"; |
263 | | |
264 | | /* convert data to ASCII */ |
265 | 232 | output_file_size = buf_size*3 + 1; |
266 | 232 | tmp_buf = malloc(output_file_size); |
267 | 232 | if (!tmp_buf) { |
268 | 0 | fclose(fp); |
269 | 0 | return -1; |
270 | 0 | } |
271 | | |
272 | 24.2k | for (i = 0, j = 0; i < buf_size; i++) { |
273 | 23.9k | tmp_buf[j++] = lut[(p[i] >> 4)]; |
274 | 23.9k | tmp_buf[j++] = lut[(p[i] & 0xF)]; |
275 | | |
276 | 23.9k | if ((i + 1) % 16 == 0) |
277 | 1.39k | tmp_buf[j++] = '\n'; |
278 | 22.5k | else |
279 | 22.5k | tmp_buf[j++] = ' '; |
280 | 23.9k | } |
281 | 232 | tmp_buf[j] = '\n'; |
282 | 232 | output_file_data = tmp_buf; |
283 | 232 | } |
284 | 232 | { |
285 | 232 | size_t const size_check = fwrite(output_file_data, sizeof(uint8_t), |
286 | 232 | output_file_size, fp); |
287 | 232 | fclose(fp); |
288 | 232 | if (size_check != output_file_size) { |
289 | 0 | free(tmp_buf); |
290 | 0 | return -1; |
291 | 0 | } |
292 | 232 | } |
293 | | |
294 | 232 | if (flags & CMP_IO_VERBOSE_EXTRA && !(flags & CMP_IO_BINARY)) { |
295 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
296 | | printf("\n"); |
297 | | fwrite(output_file_data, 1, output_file_size, stdout); |
298 | | printf("\n"); |
299 | | #endif |
300 | 0 | } |
301 | | |
302 | 232 | free(tmp_buf); |
303 | 232 | return 0; |
304 | 232 | } |
305 | | |
306 | | |
307 | | /** |
308 | | * @brief remove white spaces and tabs |
309 | | * |
310 | | * @param s input string |
311 | | */ |
312 | | |
313 | | static void remove_spaces(char *s) |
314 | 23.1k | { |
315 | 23.1k | const char *d = s; |
316 | | |
317 | 23.1k | if (!s) |
318 | 0 | return; |
319 | | |
320 | 271k | do { |
321 | 271k | while (isspace(*d)) |
322 | 5.39k | d++; |
323 | 271k | } while ((*s++ = *d++) != '\0'); |
324 | 23.1k | } |
325 | | |
326 | | |
327 | | /** |
328 | | * @brief remove comments (starting with # or /) and \n |
329 | | * |
330 | | * @param s input string |
331 | | */ |
332 | | |
333 | | static void remove_comments(char *s) |
334 | 23.1k | { |
335 | 23.1k | if (!s) |
336 | 0 | return; |
337 | | |
338 | 276k | while (*s) { |
339 | 276k | if (*s == '#' || *s == '/' || *s == '\n') { |
340 | 23.1k | *s = '\0'; |
341 | 23.1k | break; |
342 | 23.1k | } |
343 | 253k | s++; |
344 | 253k | } |
345 | | |
346 | 23.1k | } |
347 | | |
348 | | |
349 | | /** |
350 | | * @brief convert RDCU SRAM Address string to integer |
351 | | * |
352 | | * @param addr string of the address |
353 | | * |
354 | | * @returns the value of the address, < 0 on error |
355 | | */ |
356 | | |
357 | | static int sram_addr_to_int(const char *addr) |
358 | 493 | { |
359 | 493 | unsigned long i; |
360 | 493 | char *end = NULL; |
361 | | |
362 | 493 | if (addr == NULL) |
363 | 0 | return -1; |
364 | | |
365 | 493 | i = strtoul(addr, &end, 0); |
366 | | |
367 | 493 | if (end == addr || errno == ERANGE) { |
368 | 3 | printf("range error, got\n"); |
369 | 3 | errno = 0; |
370 | 3 | return -1; |
371 | 3 | } |
372 | | |
373 | 490 | if (i > RDCU_SRAM_END) { |
374 | 2 | printf("%s: The SRAM address is out of the rdcu range\n", |
375 | 2 | PROGRAM_NAME); |
376 | 2 | return -1; |
377 | 2 | } |
378 | | |
379 | 488 | if (i & 0x3) { |
380 | 4 | printf("The SRAM address is not 32 bit aligned\n"); |
381 | 4 | return -1; |
382 | 4 | } |
383 | | |
384 | 484 | return (int) i; |
385 | 488 | } |
386 | | |
387 | | |
388 | | /** |
389 | | * @brief Interprets an uint32_t integer value in a byte string |
390 | | * |
391 | | * @param dep_str description string of the read in value |
392 | | * @param val_str value string contains the value to convert in uint32_t |
393 | | * @param red_val address for storing the converted result |
394 | | * |
395 | | * @returns 0 on success, error otherwise |
396 | | * |
397 | | * @see https://eternallyconfuzzled.com/atoi-is-evil-c-learn-why-atoi-is-awful |
398 | | */ |
399 | | |
400 | | int atoui32(const char *dep_str, const char *val_str, uint32_t *red_val) |
401 | 5.92k | { |
402 | 5.92k | unsigned long temp; |
403 | 5.92k | char *end = NULL; |
404 | | |
405 | 5.92k | if (!dep_str) |
406 | 0 | return -1; |
407 | | |
408 | 5.92k | if (!val_str) |
409 | 0 | return -1; |
410 | | |
411 | 5.92k | if (!red_val) |
412 | 0 | return -1; |
413 | | |
414 | 5.92k | errno = 0; |
415 | 5.92k | temp = strtoul(val_str, &end, 0); |
416 | 5.92k | if (end != val_str && errno != ERANGE && temp <= UINT32_MAX) { |
417 | 5.83k | *red_val = (uint32_t)temp; |
418 | 5.83k | } else { |
419 | 85 | fprintf(stderr, "%s: Error read in %s.\n", PROGRAM_NAME, dep_str); |
420 | 85 | *red_val = 0; |
421 | 85 | return -1; |
422 | 85 | } |
423 | 5.83k | return 0; |
424 | 5.92k | } |
425 | | |
426 | | |
427 | | /** |
428 | | * @brief parse a compression data_type string to a data_type |
429 | | * @note string can be either a number or the name of the compression data type |
430 | | * |
431 | | * @param data_type_str string containing the compression data type to parse |
432 | | * |
433 | | * @returns data type on success, DATA_TYPE_UNKNOWN on error |
434 | | */ |
435 | | |
436 | | enum cmp_data_type string2data_type(const char *data_type_str) |
437 | 0 | { |
438 | 0 | enum cmp_data_type data_type = DATA_TYPE_UNKNOWN; |
439 | |
|
440 | 0 | if (data_type_str) { |
441 | 0 | if (isalpha(data_type_str[0])) { /* check if mode is given as text */ |
442 | 0 | size_t j; |
443 | |
|
444 | 0 | for (j = 0; j < ARRAY_SIZE(data_type_string_table); j++) { |
445 | 0 | if (!strcmp(data_type_str, data_type_string_table[j].str)) { |
446 | 0 | data_type = data_type_string_table[j].data_type; |
447 | 0 | break; |
448 | 0 | } |
449 | 0 | } |
450 | 0 | } else { |
451 | 0 | uint32_t read_val; |
452 | |
|
453 | 0 | if (!atoui32("Compression Data Type", data_type_str, &read_val)) { |
454 | 0 | data_type = read_val; |
455 | 0 | if (cmp_data_type_is_invalid(data_type)) |
456 | 0 | data_type = DATA_TYPE_UNKNOWN; |
457 | 0 | } |
458 | 0 | } |
459 | 0 | } |
460 | 0 | return data_type; |
461 | 0 | } |
462 | | |
463 | | /** |
464 | | * @brief parse a compression data_type string to a data_type |
465 | | * @note string can be either a number or the name of the compression data type |
466 | | * |
467 | | * @param data_type compression data type to convert in string |
468 | | * |
469 | | * @returns data type on success, DATA_TYPE_UNKNOWN on error |
470 | | */ |
471 | | |
472 | | const char *data_type2string(enum cmp_data_type data_type) |
473 | 0 | { |
474 | 0 | size_t j; |
475 | 0 | const char *string = "DATA_TYPE_UNKNOWN"; |
476 | |
|
477 | 0 | for (j = 0; j < ARRAY_SIZE(data_type_string_table); j++) { |
478 | 0 | if (data_type == data_type_string_table[j].data_type) { |
479 | 0 | string = data_type_string_table[j].str; |
480 | 0 | break; |
481 | 0 | } |
482 | 0 | } |
483 | |
|
484 | 0 | return string; |
485 | 0 | } |
486 | | |
487 | | |
488 | | /** |
489 | | * @brief compares two strings case-insensitively |
490 | | * |
491 | | * @param s1 the first string to compare |
492 | | * @param s2 the second string to compare |
493 | | * |
494 | | * @returns an integer greater than, equal to, or less than 0, according as s1 |
495 | | * is lexicographically greater than, equal to, or less than s2 after |
496 | | * translation of each corresponding character to lower-case. The strings |
497 | | * themselves are not modified. |
498 | | */ |
499 | | |
500 | | int case_insensitive_compare(const char *s1, const char *s2) |
501 | 1.83k | { |
502 | 1.83k | size_t i; |
503 | | |
504 | 1.83k | if(s1 == NULL) |
505 | 0 | abort(); |
506 | | |
507 | 1.83k | if(s2 == NULL) |
508 | 0 | abort(); |
509 | | |
510 | 15.3k | for (i = 0; ; ++i) { |
511 | 15.3k | unsigned int x1 = (unsigned char)s1[i]; |
512 | 15.3k | unsigned int x2 = (unsigned char)s2[i]; |
513 | 15.3k | int r; |
514 | | |
515 | 15.3k | if (x1 - 'A' < 26U) |
516 | 12.4k | x1 += 32; /* tolower */ |
517 | 15.3k | if (x2 - 'A' < 26U) |
518 | 12.5k | x2 += 32; /* tolower */ |
519 | | |
520 | 15.3k | r = (int)x1 - (int)x2; |
521 | 15.3k | if (r) |
522 | 1.47k | return r; |
523 | | |
524 | 13.8k | if (!x1) |
525 | 360 | return 0; |
526 | 13.8k | } |
527 | 1.83k | } |
528 | | |
529 | | |
530 | | /** |
531 | | * @brief parse a compression mode value string to an integer |
532 | | * @note string can be either a number or the name of the compression mode |
533 | | * |
534 | | * @param cmp_mode_str string containing the compression mode value to parse |
535 | | * @param cmp_mode address where the parsed result is written |
536 | | * |
537 | | * @returns 0 on success, error otherwise |
538 | | */ |
539 | | |
540 | | int cmp_mode_parse(const char *cmp_mode_str, enum cmp_mode *cmp_mode) |
541 | 822 | { |
542 | 822 | static const struct { |
543 | 822 | uint32_t cmp_mode; |
544 | 822 | const char *str; |
545 | 822 | } conversion[] = { |
546 | 822 | {CMP_MODE_RAW, "MODE_RAW"}, |
547 | 822 | {CMP_MODE_MODEL_ZERO, "MODE_MODEL_ZERO"}, |
548 | 822 | {CMP_MODE_DIFF_ZERO, "MODE_DIFF_ZERO"}, |
549 | 822 | {CMP_MODE_MODEL_MULTI, "MODE_MODEL_MULTI"}, |
550 | 822 | {CMP_MODE_DIFF_MULTI, "MODE_DIFF_MULTI"}, |
551 | 822 | {CMP_MODE_RAW, "CMP_MODE_RAW"}, |
552 | 822 | {CMP_MODE_MODEL_ZERO, "CMP_MODE_MODEL_ZERO"}, |
553 | 822 | {CMP_MODE_DIFF_ZERO, "CMP_MODE_DIFF_ZERO"}, |
554 | 822 | {CMP_MODE_MODEL_MULTI, "CMP_MODE_MODEL_MULTI"}, |
555 | 822 | {CMP_MODE_DIFF_MULTI, "CMP_MODE_DIFF_MULTI"}, |
556 | 822 | }; |
557 | | |
558 | 822 | if (!cmp_mode_str) |
559 | 0 | return -1; |
560 | 822 | if (!cmp_mode) |
561 | 0 | return -1; |
562 | | |
563 | 822 | if (isalpha(cmp_mode_str[0])) { /* check if mode is given as text */ |
564 | 377 | size_t j; |
565 | | |
566 | 1.69k | for (j = 0; j < ARRAY_SIZE(conversion); j++) { |
567 | 1.67k | if (!case_insensitive_compare(cmp_mode_str, conversion[j].str)) { |
568 | 350 | *cmp_mode = conversion[j].cmp_mode; |
569 | 350 | return 0; |
570 | 350 | } |
571 | 1.67k | } |
572 | 27 | return -1; |
573 | 377 | } |
574 | 445 | { |
575 | 445 | uint32_t read_val; |
576 | | |
577 | 445 | if (atoui32(cmp_mode_str, cmp_mode_str, &read_val)) |
578 | 4 | return -1; |
579 | 441 | *cmp_mode = read_val; |
580 | 441 | } |
581 | | |
582 | 441 | if (!cmp_mode_is_supported(*cmp_mode)) |
583 | 1 | return -1; |
584 | | |
585 | 440 | return 0; |
586 | 441 | } |
587 | | |
588 | | |
589 | | /** |
590 | | * @brief parse a file containing a compressing configuration |
591 | | * @note internal use only! |
592 | | * |
593 | | * @param fp FILE pointer |
594 | | * @param rcfg RDCU compression configuration structure holding the read in |
595 | | * configuration |
596 | | * @param par chunk compression parameters structure holding the read in |
597 | | * chunk configuration |
598 | | * |
599 | | * @returns CMP_TYPE_CHUNK if a chunk configuration is detected (stored in par), |
600 | | * CMP_TYPE_RDCU if an RDCU configuration is detected (stored in cfg) or |
601 | | * CMP_TYPE_ERROR on error |
602 | | */ |
603 | | |
604 | | static enum cmp_type parse_cfg(FILE *fp, struct rdcu_cfg *rcfg, struct cmp_par *par) |
605 | 1.01k | { |
606 | 1.01k | #define chunk_parse_uint32_parameter(parameter) \ |
607 | 94.7k | if (!strcmp(token1, #parameter)) { \ |
608 | 2.86k | if (atoui32(token1, token2, &par->parameter)) \ |
609 | 2.86k | return CMP_TYPE_ERROR; \ |
610 | 2.86k | cmp_type = CMP_TYPE_CHUNK; \ |
611 | 2.83k | continue; \ |
612 | 2.86k | } |
613 | 1.01k | enum cmp_type cmp_type = CMP_TYPE_RDCU; |
614 | 1.01k | char *token1, *token2; |
615 | 1.01k | char line[MAX_CONFIG_LINE]; |
616 | 1.01k | enum {CMP_MODE, SAMPLES, BUFFER_LENGTH, LAST_ITEM}; |
617 | 1.01k | int j, must_read_items[LAST_ITEM] = {0}; |
618 | | |
619 | 1.01k | if (!fp) |
620 | 0 | abort(); |
621 | 1.01k | if (!rcfg) |
622 | 0 | abort(); |
623 | 1.01k | if (!par) |
624 | 0 | abort(); |
625 | | |
626 | 32.5k | while (fgets(line, sizeof(line), fp) != NULL) { |
627 | 31.8k | if (line[0] == '#' || line[0] == '\n') |
628 | 12.6k | continue; /* skip #'ed or empty lines */ |
629 | | |
630 | 19.2k | if (!strchr(line, '\n')) { /* detect a to long line */ |
631 | 229 | fprintf(stderr, "%s: Error read in line to long. Maximal line length is %d characters.\n", |
632 | 229 | PROGRAM_NAME, MAX_CONFIG_LINE-1); |
633 | 229 | return CMP_TYPE_ERROR; |
634 | 229 | } |
635 | | |
636 | 18.9k | remove_comments(line); |
637 | 18.9k | remove_spaces(line); |
638 | | |
639 | 18.9k | token1 = strtok(line, "="); |
640 | 18.9k | token2 = strtok(NULL, "="); |
641 | 18.9k | if (token1 == NULL) |
642 | 1.11k | continue; |
643 | 17.8k | if (token2 == NULL) |
644 | 9.86k | continue; |
645 | | |
646 | | |
647 | 8.01k | if (!strcmp(token1, "cmp_mode")) { |
648 | 776 | must_read_items[CMP_MODE] = 1; |
649 | 776 | if (cmp_mode_parse(token2, &rcfg->cmp_mode)) |
650 | 26 | return CMP_TYPE_ERROR; |
651 | 750 | par->cmp_mode = rcfg->cmp_mode; |
652 | 750 | continue; |
653 | 776 | } |
654 | 7.23k | if (!strcmp(token1, "golomb_par")) { |
655 | 204 | if (atoui32(token1, token2, &rcfg->golomb_par)) |
656 | 3 | return CMP_TYPE_ERROR; |
657 | 201 | continue; |
658 | 204 | } |
659 | 7.03k | if (!strcmp(token1, "spill")) { |
660 | 398 | if (atoui32(token1, token2, &rcfg->spill)) |
661 | 4 | return CMP_TYPE_ERROR; |
662 | 394 | continue; |
663 | 398 | } |
664 | 6.63k | if (!strcmp(token1, "model_value")) { |
665 | 98 | if (atoui32(token1, token2, &rcfg->model_value)) |
666 | 3 | return CMP_TYPE_ERROR; |
667 | 95 | par->model_value = rcfg->model_value; |
668 | 95 | continue; |
669 | 98 | } |
670 | 6.53k | if (!strcmp(token1, "round")) { |
671 | 128 | if (atoui32(token1, token2, &rcfg->round)) |
672 | 4 | return CMP_TYPE_ERROR; |
673 | 124 | continue; |
674 | 128 | } |
675 | 6.41k | if (!strcmp(token1, "ap1_golomb_par")) { |
676 | 101 | if (atoui32(token1, token2, &rcfg->ap1_golomb_par)) |
677 | 3 | return CMP_TYPE_ERROR; |
678 | 98 | continue; |
679 | 101 | } |
680 | 6.30k | if (!strcmp(token1, "ap1_spill")) { |
681 | 80 | if (atoui32(token1, token2, &rcfg->ap1_spill)) |
682 | 3 | return CMP_TYPE_ERROR; |
683 | 77 | continue; |
684 | 80 | } |
685 | 6.22k | if (!strcmp(token1, "ap2_golomb_par")) { |
686 | 119 | if (atoui32(token1, token2, &rcfg->ap2_golomb_par)) |
687 | 3 | return CMP_TYPE_ERROR; |
688 | 116 | continue; |
689 | 119 | } |
690 | 6.11k | if (!strcmp(token1, "ap2_spill")) { |
691 | 182 | if (atoui32(token1, token2, &rcfg->ap2_spill)) |
692 | 1 | return CMP_TYPE_ERROR; |
693 | 181 | continue; |
694 | 182 | } |
695 | | |
696 | 5.92k | if (!strcmp(token1, "rdcu_data_adr")) { |
697 | 210 | int i = sram_addr_to_int(token2); |
698 | | |
699 | 210 | if (i < 0) { |
700 | 1 | printf("%s: Error read in rdcu_data_adr_par\n", |
701 | 1 | PROGRAM_NAME); |
702 | 1 | return CMP_TYPE_ERROR; |
703 | 1 | } |
704 | 209 | rcfg->rdcu_data_adr = (uint32_t)i; |
705 | 209 | continue; |
706 | 210 | } |
707 | 5.71k | if (!strcmp(token1, "rdcu_model_adr")) { |
708 | 95 | int i = sram_addr_to_int(token2); |
709 | | |
710 | 95 | if (i < 0) { |
711 | 1 | printf("%s: Error read in rdcu_model_adr_par\n", |
712 | 1 | PROGRAM_NAME); |
713 | 1 | return CMP_TYPE_ERROR; |
714 | 1 | } |
715 | 94 | rcfg->rdcu_model_adr = (uint32_t)i; |
716 | 94 | continue; |
717 | 95 | } |
718 | 5.62k | if (!strcmp(token1, "rdcu_new_model_adr")) { |
719 | 88 | int i = sram_addr_to_int(token2); |
720 | | |
721 | 88 | if (i < 0) { |
722 | 1 | printf("%s: Error read in rdcu_new_model_adr_par\n", |
723 | 1 | PROGRAM_NAME); |
724 | 1 | return CMP_TYPE_ERROR; |
725 | 1 | } |
726 | 87 | rcfg->rdcu_new_model_adr = (uint32_t)i; |
727 | 87 | continue; |
728 | 88 | } |
729 | 5.53k | if (!strcmp(token1, "samples")) { |
730 | 290 | if (atoui32(token1, token2, &rcfg->samples)) |
731 | 1 | return CMP_TYPE_ERROR; |
732 | 289 | must_read_items[SAMPLES] = 1; |
733 | 289 | continue; |
734 | 290 | } |
735 | 5.24k | if (!strcmp(token1, "rdcu_buffer_adr")) { |
736 | 13 | int i = sram_addr_to_int(token2); |
737 | | |
738 | 13 | if (i < 0) { |
739 | 1 | printf("%s: Error read in rdcu_buffer_adr_par\n", |
740 | 1 | PROGRAM_NAME); |
741 | 1 | return CMP_TYPE_ERROR; |
742 | 1 | } |
743 | 12 | rcfg->rdcu_buffer_adr = (uint32_t)i; |
744 | 12 | continue; |
745 | 13 | } |
746 | 5.23k | if (!strcmp(token1, "buffer_length")) { |
747 | 299 | if (atoui32(token1, token2, &rcfg->buffer_length)) |
748 | 1 | return CMP_TYPE_ERROR; |
749 | 298 | must_read_items[BUFFER_LENGTH] = 1; |
750 | 298 | continue; |
751 | 299 | } |
752 | | |
753 | | /* chunk_parse_uint32_parameter(model_value); */ |
754 | 4.93k | chunk_parse_uint32_parameter(lossy_par); |
755 | | |
756 | 4.88k | chunk_parse_uint32_parameter(nc_imagette); |
757 | | |
758 | 4.85k | chunk_parse_uint32_parameter(s_exp_flags); |
759 | 4.70k | chunk_parse_uint32_parameter(s_fx); |
760 | 4.55k | chunk_parse_uint32_parameter(s_ncob); |
761 | 4.46k | chunk_parse_uint32_parameter(s_efx); |
762 | 4.27k | chunk_parse_uint32_parameter(s_ecob); |
763 | | |
764 | 4.18k | chunk_parse_uint32_parameter(l_exp_flags); |
765 | 4.11k | chunk_parse_uint32_parameter(l_fx); |
766 | 3.53k | chunk_parse_uint32_parameter(l_ncob); |
767 | 3.44k | chunk_parse_uint32_parameter(l_efx); |
768 | 3.35k | chunk_parse_uint32_parameter(l_ecob); |
769 | 3.28k | chunk_parse_uint32_parameter(l_fx_cob_variance); |
770 | | |
771 | 3.21k | chunk_parse_uint32_parameter(saturated_imagette); |
772 | | |
773 | 3.13k | chunk_parse_uint32_parameter(nc_offset_mean); |
774 | 3.07k | chunk_parse_uint32_parameter(nc_offset_variance); |
775 | 3.00k | chunk_parse_uint32_parameter(nc_background_mean); |
776 | 2.93k | chunk_parse_uint32_parameter(nc_background_variance); |
777 | 2.82k | chunk_parse_uint32_parameter(nc_background_outlier_pixels); |
778 | | |
779 | 2.75k | chunk_parse_uint32_parameter(smearing_mean); |
780 | 2.67k | chunk_parse_uint32_parameter(smearing_variance_mean); |
781 | 2.60k | chunk_parse_uint32_parameter(smearing_outlier_pixels); |
782 | | |
783 | 2.53k | chunk_parse_uint32_parameter(fc_imagette); |
784 | 2.43k | chunk_parse_uint32_parameter(fc_offset_mean); |
785 | 2.36k | chunk_parse_uint32_parameter(fc_offset_variance); |
786 | 2.28k | chunk_parse_uint32_parameter(fc_background_mean); |
787 | 2.20k | chunk_parse_uint32_parameter(fc_background_variance); |
788 | 2.15k | chunk_parse_uint32_parameter(fc_background_outlier_pixels); |
789 | 2.06k | } |
790 | | |
791 | 696 | if (cmp_type == CMP_TYPE_RDCU) { |
792 | 274 | if (raw_mode_is_used(rcfg->cmp_mode)) |
793 | 104 | if (must_read_items[CMP_MODE] == 1 && |
794 | 104 | must_read_items[BUFFER_LENGTH] == 1) |
795 | 14 | return cmp_type; |
796 | | |
797 | 769 | for (j = 0; j < LAST_ITEM; j++) { |
798 | 600 | if (must_read_items[j] < 1) { |
799 | 91 | fprintf(stderr, "%s: Some parameters are missing. Check if the following parameters: cmp_mode, golomb_par, spill, samples and buffer_length are all set in the configuration file.\n", |
800 | 91 | PROGRAM_NAME); |
801 | 91 | return CMP_TYPE_ERROR; |
802 | 91 | } |
803 | 600 | } |
804 | 260 | } |
805 | | |
806 | 591 | return cmp_type; |
807 | 696 | } |
808 | | |
809 | | |
810 | | /** |
811 | | * @brief reading a compressor configuration file |
812 | | * |
813 | | * @param file_name file containing the compression configuration file |
814 | | * @param rcfg RDCU compression configuration structure holding the read in |
815 | | * configuration |
816 | | * @param par chunk compression parameters structure holding the read |
817 | | * in chunk configuration |
818 | | * @param verbose_en print verbose output if not zero |
819 | | * |
820 | | * @returns CMP_TYPE_CHUNK if a chunk configuration is detected (stored in par), |
821 | | * CMP_TYPE_RDCU if an RDCU configuration is detected (stored in cfg) or |
822 | | * CMP_TYPE_ERROR on error |
823 | | */ |
824 | | |
825 | | enum cmp_type cmp_cfg_read(const char *file_name, struct rdcu_cfg *rcfg, |
826 | | struct cmp_par *par, int verbose_en) |
827 | 1.02k | { |
828 | 1.02k | enum cmp_type cmp_type; |
829 | 1.02k | FILE *fp; |
830 | | |
831 | 1.02k | if (!file_name) |
832 | 0 | abort(); |
833 | | |
834 | 1.02k | if (!rcfg) |
835 | 0 | abort(); |
836 | | |
837 | 1.02k | if (strstr(file_name, ".info")) { |
838 | 0 | fprintf(stderr, "%s: %s: .info file extension found on configuration file. You may have selected the wrong file.\n", |
839 | 0 | PROGRAM_NAME, file_name); |
840 | 0 | } |
841 | | |
842 | 1.02k | fp = fopen(file_name, "r"); |
843 | | |
844 | 1.02k | if (fp == NULL) { |
845 | 13 | fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name, |
846 | 13 | strerror(errno)); |
847 | 13 | return -1; |
848 | 13 | } |
849 | | |
850 | 1.01k | cmp_type = parse_cfg(fp, rcfg, par); |
851 | 1.01k | fclose(fp); |
852 | | |
853 | 1.01k | if (verbose_en && cmp_type == CMP_TYPE_RDCU) { |
854 | 0 | printf("\n\n"); |
855 | 0 | cmp_cfg_print(rcfg, 1); |
856 | 0 | printf("\n"); |
857 | 0 | } |
858 | | |
859 | 1.01k | return cmp_type; |
860 | 1.02k | } |
861 | | |
862 | | |
863 | | /** |
864 | | * @brief parse a file containing a decompression information |
865 | | * @note internal use only! |
866 | | * |
867 | | * @param fp FILE pointer |
868 | | * @param info decompression information structure holding the read in |
869 | | * information |
870 | | * |
871 | | * @returns 0 on success, error otherwise |
872 | | */ |
873 | | |
874 | | static int parse_info(FILE *fp, struct cmp_info *info) |
875 | 207 | { |
876 | 207 | char *token1, *token2; |
877 | 207 | char line[MAX_CONFIG_LINE]; |
878 | 207 | enum {CMP_MODE_USED, GOLOMB_PAR_USED, SPILL_USED, SAMPLES_USED, |
879 | 207 | CMP_SIZE, LAST_ITEM}; |
880 | 207 | int j, must_read_items[LAST_ITEM] = {0}; |
881 | | |
882 | 207 | if (!fp) |
883 | 0 | return -1; |
884 | | |
885 | 207 | if (!info) |
886 | 0 | return -1; |
887 | | |
888 | 6.78k | while (fgets(line, sizeof(line), fp) != NULL) { |
889 | 6.72k | if (line[0] == '#' || line[0] == '\n') |
890 | 2.44k | continue; /* skip #'ed or empty lines */ |
891 | | |
892 | 4.27k | if (!strchr(line, '\n')) { /* detect a to long line */ |
893 | 112 | fprintf(stderr, "%s: Error read in line to long. Maximal line length is %d characters.\n", |
894 | 112 | PROGRAM_NAME, MAX_CONFIG_LINE-1); |
895 | 112 | return -1; |
896 | 112 | } |
897 | | |
898 | 4.16k | remove_comments(line); |
899 | 4.16k | remove_spaces(line); |
900 | | |
901 | | /* Token will point to the part before the search-var. */ |
902 | 4.16k | token1 = strtok(line, "="); |
903 | 4.16k | token2 = strtok(NULL, "="); |
904 | 4.16k | if (token1 == NULL) |
905 | 597 | continue; |
906 | 3.56k | if (token2 == NULL) |
907 | 1.87k | continue; |
908 | | |
909 | | |
910 | 1.69k | if (!strcmp(token1, "cmp_mode_used")) { |
911 | 359 | must_read_items[CMP_MODE_USED] = 1; |
912 | 359 | if (isalpha(*token2)) { /* check if mode is given as text or val*/ |
913 | | /* TODO: use conversion function for this: */ |
914 | 268 | if (!strcmp(token2, "MODE_RAW")) { |
915 | 66 | info->cmp_mode_used = 0; |
916 | 66 | continue; |
917 | 66 | } |
918 | 202 | if (!strcmp(token2, "MODE_MODEL_ZERO")) { |
919 | 34 | info->cmp_mode_used = 1; |
920 | 34 | continue; |
921 | 34 | } |
922 | 168 | if (!strcmp(token2, "MODE_DIFF_ZERO")) { |
923 | 34 | info->cmp_mode_used = 2; |
924 | 34 | continue; |
925 | 34 | } |
926 | 134 | if (!strcmp(token2, "MODE_MODEL_MULTI")) { |
927 | 66 | info->cmp_mode_used = 3; |
928 | 66 | continue; |
929 | 66 | } |
930 | 68 | if (!strcmp(token2, "MODE_DIFF_MULTI")) { |
931 | 66 | info->cmp_mode_used = 4; |
932 | 66 | continue; |
933 | 66 | } |
934 | 2 | fprintf(stderr, "%s: Error read in cmp_mode_used.\n", |
935 | 2 | PROGRAM_NAME); |
936 | 2 | return -1; |
937 | 68 | } |
938 | 91 | { |
939 | 91 | uint32_t tmp; |
940 | | |
941 | 91 | if (atoui32(token1, token2, &tmp)) |
942 | 3 | return -1; |
943 | 88 | info->cmp_mode_used = tmp; |
944 | 88 | } |
945 | 0 | continue; |
946 | 91 | } |
947 | 1.33k | if (!strcmp(token1, "model_value_used")) { |
948 | 75 | uint32_t tmp; |
949 | | |
950 | 75 | if (atoui32(token1, token2, &tmp)) |
951 | 3 | return -1; |
952 | 72 | if (tmp <= UINT8_MAX) { |
953 | 71 | info->model_value_used = (uint8_t)tmp; |
954 | 71 | } else { |
955 | 1 | fprintf(stderr, "%s: Error read in %s.\n", |
956 | 1 | PROGRAM_NAME, token1); |
957 | 1 | return -1; |
958 | 1 | } |
959 | 71 | continue; |
960 | 72 | } |
961 | 1.26k | if (!strcmp(token1, "round_used")) { |
962 | 71 | uint32_t tmp; |
963 | | |
964 | 71 | if (atoui32(token1, token2, &tmp)) |
965 | 3 | return -1; |
966 | 68 | if (tmp <= 0xF) { /* max value of 4 bits */ |
967 | 67 | info->round_used = (uint8_t)tmp; |
968 | 67 | } else { |
969 | 1 | fprintf(stderr, "%s: Error read in %s.\n", |
970 | 1 | PROGRAM_NAME, token1); |
971 | 1 | return -1; |
972 | 1 | } |
973 | 67 | continue; |
974 | 68 | } |
975 | 1.19k | if (!strcmp(token1, "spill_used")) { |
976 | 71 | uint32_t tmp; |
977 | | |
978 | 71 | if (atoui32(token1, token2, &tmp)) |
979 | 3 | return -1; |
980 | 68 | info->spill_used = (unsigned char)tmp; |
981 | 68 | must_read_items[SPILL_USED] = 1; |
982 | 68 | continue; |
983 | 71 | } |
984 | 1.12k | if (!strcmp(token1, "golomb_par_used")) { |
985 | 23 | uint32_t tmp; |
986 | | |
987 | 23 | if (atoui32(token1, token2, &tmp)) |
988 | 3 | return -1; |
989 | 20 | info->golomb_par_used = tmp; |
990 | 20 | must_read_items[GOLOMB_PAR_USED] = 1; |
991 | 20 | continue; |
992 | 23 | } |
993 | 1.09k | if (!strcmp(token1, "samples_used")) { |
994 | 75 | if (atoui32(token1, token2, &info->samples_used)) |
995 | 3 | return -1; |
996 | 72 | must_read_items[SAMPLES_USED] = 1; |
997 | 72 | continue; |
998 | 75 | } |
999 | 1.02k | if (!strcmp(token1, "cmp_size")) { |
1000 | 77 | if (atoui32(token1, token2, &info->cmp_size)) |
1001 | 1 | return -1; |
1002 | 76 | must_read_items[CMP_SIZE] = 1; |
1003 | 76 | continue; |
1004 | 77 | } |
1005 | | |
1006 | 947 | if (!strcmp(token1, "ap1_cmp_size")) { |
1007 | 71 | if (atoui32(token1, token2, &info->ap1_cmp_size)) |
1008 | 1 | return -1; |
1009 | 70 | continue; |
1010 | 71 | } |
1011 | 876 | if (!strcmp(token1, "ap2_cmp_size")) { |
1012 | 68 | if (atoui32(token1, token2, &info->ap2_cmp_size)) |
1013 | 1 | return -1; |
1014 | 67 | continue; |
1015 | 68 | } |
1016 | | |
1017 | 808 | if (!strcmp(token1, "rdcu_new_model_adr_used")) { |
1018 | 11 | int i = sram_addr_to_int(token2); |
1019 | | |
1020 | 11 | if (i < 0) { |
1021 | 1 | fprintf(stderr, "%s: Error read in rdcu_new_model_adr_used\n", |
1022 | 1 | PROGRAM_NAME); |
1023 | 1 | return -1; |
1024 | 1 | } |
1025 | 10 | info->rdcu_new_model_adr_used = (uint32_t)i; |
1026 | 10 | continue; |
1027 | 11 | } |
1028 | 797 | if (!strcmp(token1, "rdcu_cmp_adr_used")) { |
1029 | 76 | int i = sram_addr_to_int(token2); |
1030 | | |
1031 | 76 | if (i < 0) { |
1032 | 4 | fprintf(stderr, "%s: Error read in rdcu_cmp_adr_used\n", |
1033 | 4 | PROGRAM_NAME); |
1034 | 4 | return -1; |
1035 | 4 | } |
1036 | 72 | info->rdcu_cmp_adr_used = (uint32_t)i; |
1037 | 72 | continue; |
1038 | 76 | } |
1039 | 721 | if (!strcmp(token1, "cmp_err")) { |
1040 | 69 | uint32_t tmp; |
1041 | | |
1042 | 69 | if (atoui32(token1, token2, &tmp)) |
1043 | 1 | return -1; |
1044 | 68 | if (tmp <= UINT16_MAX) { |
1045 | 67 | info->cmp_err = (uint16_t)tmp; |
1046 | 67 | } else { |
1047 | 1 | fprintf(stderr, "%s: Error read in %s.\n", |
1048 | 1 | PROGRAM_NAME, token1); |
1049 | 1 | return -1; |
1050 | 1 | } |
1051 | 67 | continue; |
1052 | 68 | } |
1053 | 721 | } |
1054 | | |
1055 | 63 | if (raw_mode_is_used(info->cmp_mode_used)) |
1056 | 58 | if (must_read_items[CMP_MODE_USED] == 1 && |
1057 | 58 | must_read_items[SAMPLES_USED] == 1 && |
1058 | 58 | must_read_items[CMP_SIZE] == 1) |
1059 | 4 | return 0; |
1060 | | |
1061 | 71 | for (j = 0; j < LAST_ITEM; j++) { |
1062 | 71 | if (must_read_items[j] < 1) { |
1063 | 59 | fprintf(stderr, "%s: Some parameters are missing. Check if the following parameters: cmp_mode_used, golomb_par_used, spill_used and samples_used are all set in the information file.\n", |
1064 | 59 | PROGRAM_NAME); |
1065 | 59 | return -1; |
1066 | 59 | } |
1067 | 71 | } |
1068 | | |
1069 | 0 | return 0; |
1070 | 59 | } |
1071 | | |
1072 | | |
1073 | | /** |
1074 | | * @brief reading a compressor decompression information file |
1075 | | * |
1076 | | * @param file_name file containing the compression configuration file |
1077 | | * @param info decompression information structure holding the read in |
1078 | | * information |
1079 | | * @param verbose_en print verbose output if not zero |
1080 | | * |
1081 | | * @returns 0 on success, error otherwise |
1082 | | */ |
1083 | | |
1084 | | int cmp_info_read(const char *file_name, struct cmp_info *info, int verbose_en) |
1085 | 217 | { |
1086 | 217 | int err; |
1087 | 217 | FILE *fp; |
1088 | | |
1089 | 217 | if (!file_name) |
1090 | 0 | abort(); |
1091 | | |
1092 | 217 | if (!info) |
1093 | 0 | abort(); |
1094 | | |
1095 | 217 | if (strstr(file_name, ".cfg")) |
1096 | 0 | fprintf(stderr, "%s: %s: .cfg file extension found on decompression information file. You may have selected the wrong file.\n", |
1097 | 217 | PROGRAM_NAME, file_name); |
1098 | | |
1099 | 217 | fp = fopen(file_name, "r"); |
1100 | 217 | if (fp == NULL) { |
1101 | 10 | fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name, |
1102 | 10 | strerror(errno)); |
1103 | 10 | return -1; |
1104 | 10 | } |
1105 | | |
1106 | 207 | err = parse_info(fp, info); |
1107 | 207 | fclose(fp); |
1108 | 207 | if (err) |
1109 | 203 | return -1; |
1110 | | |
1111 | | |
1112 | 4 | if (verbose_en) { |
1113 | 0 | printf("\n\n"); |
1114 | 0 | print_cmp_info(info); |
1115 | 0 | printf("\n"); |
1116 | 0 | } |
1117 | | |
1118 | 4 | return 0; |
1119 | 207 | } |
1120 | | |
1121 | | |
1122 | | /** |
1123 | | * @brief skip a sequence of spaces (as identified by calling isspace) |
1124 | | * |
1125 | | * @param str pointer to the null-terminated byte string to be interpreted |
1126 | | * |
1127 | | * @returns a pointer to the character after the spaces |
1128 | | */ |
1129 | | |
1130 | | static const char *skip_space(const char *str) |
1131 | 93.4k | { |
1132 | 93.4k | while (isspace(*str)) |
1133 | 7.38k | str++; |
1134 | 93.4k | return str; |
1135 | 93.4k | } |
1136 | | |
1137 | | |
1138 | | /** |
1139 | | * @brief skip a comment starting with '#' symbol ending with '\n' or '\0' |
1140 | | * |
1141 | | * @param str pointer to the null-terminated byte string to be interpreted |
1142 | | * |
1143 | | * @returns a pointer to the character after the comment |
1144 | | */ |
1145 | | |
1146 | | static const char *skip_comment(const char *str) |
1147 | 684 | { |
1148 | 684 | char c = *str; |
1149 | | |
1150 | 684 | if (c == '#') { |
1151 | 4.12k | do { |
1152 | 4.12k | str++; |
1153 | 4.12k | c = *str; |
1154 | 4.12k | } while (c != '\0' && c != '\n'); |
1155 | 684 | if (c != '\0') |
1156 | 601 | str++; |
1157 | 684 | } |
1158 | 684 | return str; |
1159 | 684 | } |
1160 | | |
1161 | | |
1162 | | /** |
1163 | | * @brief Interprets a hex-encoded 8-bit integer value in a byte string pointed |
1164 | | * to by str. |
1165 | | * @details Discards any whitespace characters (as identified by calling isspace) |
1166 | | * until the first non-whitespace character is found, then takes a maximum |
1167 | | * of 2 characters (with base 16) unsigned integer number representation |
1168 | | * and converts them to an uint8_t value. The function sets the pointer |
1169 | | * pointed to by str_end to point to the character past the last character |
1170 | | * interpreted. If str_end is a null pointer, it is ignored. |
1171 | | * |
1172 | | * @param str pointer to the null-terminated byte string to be interpreted |
1173 | | * @param str_end point to the character past the last numeric character |
1174 | | * interpreted (can be NULL) |
1175 | | * |
1176 | | * @returns Integer value corresponding to the contents of str on success. If no |
1177 | | * conversion can be performed, 0 is returned (errno is set to EINVAL)). |
1178 | | */ |
1179 | | |
1180 | | static uint8_t str_to_uint8(const char *str, char const **str_end) |
1181 | 86.8k | { |
1182 | 86.8k | const int BASE = 16; |
1183 | 86.8k | int i; |
1184 | 86.8k | uint8_t res = 0; |
1185 | 86.8k | const char *orig; |
1186 | | |
1187 | 86.8k | str = skip_space(str); |
1188 | | |
1189 | 86.8k | orig = str; |
1190 | | |
1191 | 255k | for (i = 0; i < 2; i++) { |
1192 | 173k | unsigned char c = (unsigned char)*str; |
1193 | | |
1194 | 173k | if (c >= 'a') |
1195 | 46.8k | c = c - 'a' + 10; |
1196 | 126k | else if (c >= 'A') |
1197 | 1.58k | c = c - 'A' + 10; |
1198 | 125k | else if (c <= '9') |
1199 | 125k | c = c - '0'; |
1200 | 3 | else |
1201 | 3 | c = 0xff; |
1202 | | |
1203 | 173k | if (unlikely(c >= BASE)) |
1204 | 4.48k | break; |
1205 | | |
1206 | 169k | res = res * BASE + c; |
1207 | | |
1208 | 169k | str++; |
1209 | 169k | } |
1210 | | |
1211 | 86.8k | if (str_end) |
1212 | 86.8k | *str_end = str; |
1213 | | |
1214 | 86.8k | if (unlikely(str == orig)) { /* no value read in */ |
1215 | 25 | errno = EINVAL; |
1216 | 25 | res = 0; |
1217 | 25 | } |
1218 | | |
1219 | 86.8k | return res; |
1220 | 86.8k | } |
1221 | | |
1222 | | |
1223 | | /** |
1224 | | * @brief reads buf_size words of a hex-encoded string to a uint8_t buffer |
1225 | | * |
1226 | | * @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage |
1227 | | * return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a |
1228 | | * sequence are used as separators. If a string contains more than three hexadecimal |
1229 | | * numeric characters (0123456789abcdefABCDEF) in a row without separators, a |
1230 | | * separator is added after every second hexadecimal numeric character. |
1231 | | * Comments after a '#' symbol until the end of the line are ignored. |
1232 | | * E.g. "# comment\n ABCD 1 2\n34B 12\n" are interpreted as {0xAB, 0xCD, |
1233 | | * 0x01, 0x02, 0x34, 0x0B, 0x12}. |
1234 | | * |
1235 | | * @param str pointer to the null-terminated byte string to be interpreted |
1236 | | * @param data buffer to write the interpreted content (can be NULL) |
1237 | | * @param buf_size number of uint8_t data words to read in |
1238 | | * @param file_name file name for better error output (can be NULL) |
1239 | | * @param verbose_en print verbose output if not zero |
1240 | | * |
1241 | | * @returns the size in bytes to store the string content; negative on error |
1242 | | */ |
1243 | | |
1244 | | static __inline ssize_t str2uint8_arr(const char *str, uint8_t *data, uint32_t buf_size, |
1245 | | const char *file_name, int verbose_en) |
1246 | 1.24k | { |
1247 | 1.24k | const char *nptr = str; |
1248 | 1.24k | const char *eptr = NULL; |
1249 | 1.24k | uint32_t i = 0; |
1250 | | |
1251 | 1.24k | errno = 0; |
1252 | | |
1253 | 1.24k | if (!data) |
1254 | 581 | buf_size = ~0U; |
1255 | | |
1256 | 1.24k | if (!file_name) |
1257 | 0 | file_name = "unknown file name"; |
1258 | | |
1259 | 95.1k | for (i = 0; i < buf_size; ) { |
1260 | 94.5k | uint8_t read_val; |
1261 | 94.5k | char c = *nptr; |
1262 | | |
1263 | 94.5k | if (c == '\0') { |
1264 | 551 | if (!data) /* finished counting the sample */ |
1265 | 550 | break; |
1266 | | |
1267 | 1 | fprintf(stderr, "%s: %s: Error: The files do not contain enough data. Expected: 0x%x, has 0x%x.\n", |
1268 | 1 | PROGRAM_NAME, file_name, buf_size, i); |
1269 | 1 | return -1; |
1270 | 551 | } |
1271 | | |
1272 | 93.9k | if (isspace(c)) { |
1273 | 6.59k | nptr = skip_space(nptr); |
1274 | 6.59k | continue; |
1275 | 6.59k | } |
1276 | 87.3k | if (c == '#') { |
1277 | 567 | nptr = skip_comment(nptr); |
1278 | 567 | continue; |
1279 | 567 | } |
1280 | | |
1281 | 86.8k | read_val = str_to_uint8(nptr, &eptr); |
1282 | 86.8k | if (eptr < nptr) /* end pointer must be bigger or equal than the start pointer */ |
1283 | 0 | abort(); |
1284 | 86.8k | c = *eptr; |
1285 | 86.8k | if (c != '\0' && !isxdigit(c) && !isspace(c) && c != '#') { |
1286 | 32 | if (isprint(c)) |
1287 | 17 | fprintf(stderr, "%s: %s: Error read in '%.*s'. The data are not correctly formatted.\n", |
1288 | 32 | PROGRAM_NAME, file_name, (int)(eptr-nptr+1), nptr); |
1289 | 15 | else |
1290 | 15 | fprintf(stderr, "%s: %s: Error: Non printable character found. If you want to read binary files, use the --binary option.\n", |
1291 | 32 | PROGRAM_NAME, file_name); |
1292 | 32 | return -1; |
1293 | 32 | } |
1294 | 86.7k | if (errno == EINVAL) { |
1295 | 0 | fprintf(stderr, "%s: %s: Error converting the data to integers.\n", |
1296 | 0 | PROGRAM_NAME, file_name); |
1297 | 0 | return -1; |
1298 | 0 | } |
1299 | 86.7k | if (data) { |
1300 | 43.9k | data[i] = read_val; |
1301 | 43.9k | if (verbose_en) { /* print data read in */ |
1302 | 0 | if (i == 0) |
1303 | 0 | printf("\n\n"); |
1304 | 0 | printf("%02X", data[i]); |
1305 | 0 | if (i && !((i + 1) % 32)) |
1306 | 0 | printf("\n"); |
1307 | 0 | else |
1308 | 0 | printf(" "); |
1309 | 0 | } |
1310 | 43.9k | } |
1311 | | |
1312 | 86.7k | i++; |
1313 | 86.7k | nptr = eptr; |
1314 | 86.7k | } |
1315 | | |
1316 | | /* did we read all data in the string? 0 at the end are ignored */ |
1317 | 1.94k | while (isspace(*nptr) || *nptr == '0' || *nptr == '#') { |
1318 | 734 | if (*nptr == '#') |
1319 | 117 | nptr = skip_comment(nptr); |
1320 | 617 | else |
1321 | 617 | nptr++; |
1322 | 734 | } |
1323 | 1.21k | if (*nptr != '\0') { |
1324 | 139 | fprintf(stderr, "%s: %s: Warning: The file may contain more data than read from it.\n", |
1325 | 139 | PROGRAM_NAME, file_name); |
1326 | 139 | } |
1327 | | |
1328 | 1.21k | return (ssize_t)i; |
1329 | 1.24k | } |
1330 | | |
1331 | | |
1332 | | /** |
1333 | | * @brief reads hex-encoded uint8_t data form a file to a buffer |
1334 | | * |
1335 | | * @note A whitespace (space (0x20), form feed (0x0c), line feed (0x0a), carriage |
1336 | | * return (0x0d), horizontal tab (0x09), or vertical tab (0x0b) or several in a |
1337 | | * sequence are used as separators. If a string contains more than three hexadecimal |
1338 | | * numeric characters (0123456789abcdefABCDEF) in a row without separators, a |
1339 | | * separator is added after every second hexadecimal numeric character. |
1340 | | * Comments after a '#' symbol until the end of the line are ignored. |
1341 | | * E.g. "# comment\n ABCD 1 2\n34B 12\n" are interpreted as {0xAB, 0xCD, |
1342 | | * 0x01, 0x02, 0x34, 0x0B, 0x12}. |
1343 | | * |
1344 | | * @param file_name data/model file name |
1345 | | * @param buf buffer to write the file content (can be NULL) |
1346 | | * @param buf_size number of uint8_t data words to read in |
1347 | | * @param flags CMP_IO_VERBOSE_EXTRA print verbose output if set |
1348 | | * CMP_IO_BINARY read in file in binary format if set |
1349 | | * |
1350 | | * @returns the size in bytes to store the file content; negative on error |
1351 | | */ |
1352 | | |
1353 | | ssize_t read_file8(const char *file_name, uint8_t *buf, uint32_t buf_size, int flags) |
1354 | 1.47k | { |
1355 | 1.47k | FILE *fp; |
1356 | 1.47k | char *file_cpy = NULL; |
1357 | 1.47k | long file_size; |
1358 | 1.47k | ssize_t size; |
1359 | 1.47k | size_t ret_code; |
1360 | | |
1361 | 1.47k | if (!file_name) |
1362 | 0 | abort(); |
1363 | | |
1364 | 1.47k | errno = 0; |
1365 | 1.47k | fp = fopen(file_name, "rb"); |
1366 | 1.47k | if (fp == NULL) |
1367 | 17 | goto fail; |
1368 | | |
1369 | | /* Get the number of bytes */ |
1370 | 1.45k | if (fseek(fp, 0L, SEEK_END) != 0) |
1371 | 0 | goto fail; |
1372 | 1.45k | file_size = ftell(fp); |
1373 | 1.45k | if (file_size < 0) |
1374 | 0 | goto fail; |
1375 | 1.45k | if (file_size == 0) { |
1376 | 61 | fprintf(stderr, "%s: %s: Error: The file is empty.\n", PROGRAM_NAME, file_name); |
1377 | 61 | goto fail; |
1378 | 61 | } |
1379 | 1.39k | if ((unsigned long)file_size < buf_size) { |
1380 | 1 | fprintf(stderr, "%s: %s: Error: The files do not contain enough data.\n", PROGRAM_NAME, file_name); |
1381 | 1 | goto fail; |
1382 | 1 | } |
1383 | | /* reset the file position indicator to the beginning of the file */ |
1384 | 1.39k | if (fseek(fp, 0L, SEEK_SET) != 0) |
1385 | 0 | goto fail; |
1386 | | |
1387 | 1.39k | if (flags & CMP_IO_BINARY) { |
1388 | 152 | if (buf) { |
1389 | 76 | ret_code = fread(buf, sizeof(uint8_t), buf_size, fp); |
1390 | 76 | if (ret_code != (size_t)buf_size) { |
1391 | 0 | if (feof(fp)) |
1392 | 0 | printf("%s: %s: Error: unexpected end of file.\n", PROGRAM_NAME, file_name); |
1393 | 0 | goto fail; |
1394 | 0 | } |
1395 | 76 | } |
1396 | 152 | fclose(fp); |
1397 | 152 | return file_size; |
1398 | 152 | } |
1399 | | |
1400 | 1.24k | file_cpy = calloc((size_t)file_size+1, sizeof(char)); |
1401 | 1.24k | if (file_cpy == NULL) { |
1402 | 0 | fprintf(stderr, "%s: %s: Error: allocating memory!\n", PROGRAM_NAME, file_name); |
1403 | 0 | goto fail; |
1404 | 0 | } |
1405 | | |
1406 | | /* copy all the text into the file_cpy buffer */ |
1407 | 1.24k | ret_code = fread(file_cpy, sizeof(uint8_t), (unsigned long)file_size, fp); |
1408 | 1.24k | if (ret_code != (size_t)file_size) { |
1409 | 0 | if (feof(fp)) |
1410 | 0 | printf("%s: %s: Error: unexpected end of file.\n", PROGRAM_NAME, file_name); |
1411 | 0 | goto fail; |
1412 | 0 | } |
1413 | | /* just to be safe we have a zero terminated string */ |
1414 | 1.24k | file_cpy[file_size] = '\0'; |
1415 | | |
1416 | 1.24k | fclose(fp); |
1417 | 1.24k | fp = NULL; |
1418 | | |
1419 | 1.24k | size = str2uint8_arr(file_cpy, buf, buf_size, file_name, flags & CMP_IO_VERBOSE_EXTRA); |
1420 | | |
1421 | 1.24k | free(file_cpy); |
1422 | 1.24k | file_cpy = NULL; |
1423 | | |
1424 | 1.24k | return size; |
1425 | 79 | fail: |
1426 | 79 | if (errno) |
1427 | 17 | fprintf(stderr, "%s: %s: %s\n", PROGRAM_NAME, file_name, |
1428 | 79 | strerror(errno)); |
1429 | 79 | if (fp) |
1430 | 62 | fclose(fp); |
1431 | 79 | free(file_cpy); |
1432 | 79 | return -1; |
1433 | 1.24k | } |
1434 | | |
1435 | | |
1436 | | /** |
1437 | | * @brief reads hex-encoded data from a file into a buffer |
1438 | | * |
1439 | | * @param file_name data/model file name |
1440 | | * @param cmp_type RDCU or chunk compression? |
1441 | | * @param buf buffer to write the file content (can be NULL) |
1442 | | * @param buf_size size in bytes of the buffer |
1443 | | * @param flags CMP_IO_VERBOSE_EXTRA print verbose output if set |
1444 | | * CMP_IO_BINARY read in file in binary format if set |
1445 | | * |
1446 | | * @returns the size in bytes to store the file content; negative on error |
1447 | | */ |
1448 | | |
1449 | | ssize_t read_file_data(const char *file_name, enum cmp_type cmp_type, |
1450 | | void *buf, uint32_t buf_size, int flags) |
1451 | 1.29k | { |
1452 | 1.29k | ssize_t size; |
1453 | 1.29k | int err; |
1454 | | |
1455 | 1.29k | size = read_file8(file_name, (uint8_t *)buf, buf_size, flags); |
1456 | 1.29k | if (size > INT32_MAX) |
1457 | 0 | return -1; |
1458 | | |
1459 | 1.29k | if (size < 0) |
1460 | 63 | return size; |
1461 | | |
1462 | 1.23k | switch (cmp_type) { |
1463 | 431 | case CMP_TYPE_RDCU: |
1464 | 431 | err = be_to_cpu_data_type(buf, buf_size, DATA_TYPE_IMAGETTE); |
1465 | 431 | break; |
1466 | 800 | case CMP_TYPE_CHUNK: |
1467 | 800 | err = be_to_cpu_chunk(buf, buf_size); |
1468 | 800 | break; |
1469 | 0 | case CMP_TYPE_ERROR: |
1470 | 0 | default: |
1471 | 0 | err = -1; |
1472 | 1.23k | } |
1473 | | |
1474 | 1.23k | if (err) |
1475 | 89 | return -1; |
1476 | | |
1477 | 1.14k | return size; |
1478 | 1.23k | } |
1479 | | |
1480 | | |
1481 | | /** |
1482 | | * @brief reads a file containing a compression entity |
1483 | | * |
1484 | | * @param file_name file name of the file containing the compression entity |
1485 | | * @param ent pointer to the buffer where the content of the file is written (can be NULL) |
1486 | | * @param ent_size size in bytes of the compression entity to read in |
1487 | | * @param flags CMP_IO_VERBOSE print verbose output if set |
1488 | | * CMP_IO_BINARY read in file in binary format if set |
1489 | | * |
1490 | | * @returns the size in bytes to store the file content; negative on error |
1491 | | */ |
1492 | | |
1493 | | ssize_t read_file_cmp_entity(const char *file_name, struct cmp_entity *ent, |
1494 | | uint32_t ent_size, int flags) |
1495 | 177 | { |
1496 | 177 | ssize_t size; |
1497 | | |
1498 | 177 | size = read_file8(file_name, (uint8_t *)ent, ent_size, flags); |
1499 | 177 | if (size < 0) |
1500 | 48 | return size; |
1501 | | |
1502 | 129 | if (size < GENERIC_HEADER_SIZE) { |
1503 | 29 | fprintf(stderr, "%s: %s: Error: The file is too small to contain a compression entity header.\n", |
1504 | 29 | PROGRAM_NAME, file_name); |
1505 | 29 | return -1; |
1506 | 29 | } |
1507 | | |
1508 | 100 | if (ent) { |
1509 | 50 | enum cmp_data_type data_type = cmp_ent_get_data_type(ent); |
1510 | | |
1511 | 50 | if (flags & CMP_IO_VERBOSE) { |
1512 | 2 | printf("\n"); |
1513 | 2 | cmp_ent_parse(ent); |
1514 | 2 | } |
1515 | | |
1516 | 50 | if (data_type == DATA_TYPE_UNKNOWN) { |
1517 | 27 | fprintf(stderr, "%s: %s: Error: Compression data type is not supported. The header of the compression entity may be corrupted.\n", |
1518 | 27 | PROGRAM_NAME, file_name); |
1519 | 27 | return -1; |
1520 | 27 | } |
1521 | 23 | if (size != (ssize_t)cmp_ent_get_size(ent)) { |
1522 | 2 | fprintf(stderr, "%s: %s: The size of the compression entity set in the header of the compression entity is not the same size as the read-in file has. Expected: 0x%x, has 0x%lx.\n", |
1523 | 2 | PROGRAM_NAME, file_name, cmp_ent_get_size(ent), (unsigned long)size); |
1524 | 2 | return -1; |
1525 | 2 | } |
1526 | 23 | } |
1527 | | |
1528 | 71 | return size; |
1529 | 100 | } |
1530 | | |
1531 | | |
1532 | | /* |
1533 | | * @brief generate from the cmp_tool version string a version_id for the |
1534 | | * compression entity header |
1535 | | * |
1536 | | * @param version number string like: 1.04 |
1537 | | * |
1538 | | * @returns version_id for the compression header; 0 on error |
1539 | | */ |
1540 | | |
1541 | | uint32_t cmp_tool_gen_version_id(const char *version) |
1542 | 401 | { |
1543 | 401 | char *copy, *token; |
1544 | 401 | unsigned int n; |
1545 | 401 | uint32_t version_id; |
1546 | | |
1547 | | /* |
1548 | | * version_id bits: msb |xxxx xxxx | xxxx xxxx| lsb |
1549 | | * ^^^ ^^^^ | ^^^^ ^^^^ |
1550 | | * mayor num| minor version number |
1551 | | * ^ |
1552 | | * CMP_TOOL_VERSION_ID_BIT |
1553 | | */ |
1554 | 401 | copy = strdup(version); |
1555 | 401 | token = strtok(copy, "."); |
1556 | 401 | n = (unsigned int)atoi(token); |
1557 | 401 | if (n > UINT16_MAX) { |
1558 | 0 | free(copy); |
1559 | 0 | return 0; |
1560 | 0 | } |
1561 | 401 | version_id = n << 16U; |
1562 | 401 | if (version_id & CMP_TOOL_VERSION_ID_BIT) { |
1563 | 0 | free(copy); |
1564 | 0 | return 0; |
1565 | 0 | } |
1566 | | |
1567 | 401 | token = strtok(NULL, "."); |
1568 | 401 | n = (unsigned int)atoi(token); |
1569 | 401 | free(copy); |
1570 | 401 | if (n > UINT16_MAX) |
1571 | 0 | return 0; |
1572 | | |
1573 | 401 | version_id |= n; |
1574 | | |
1575 | 401 | return version_id | CMP_TOOL_VERSION_ID_BIT; |
1576 | 401 | } |
1577 | | |
1578 | | |
1579 | | /** |
1580 | | * @brief write compression configuration to a stream |
1581 | | * @note internal use only! |
1582 | | * |
1583 | | * @param fp FILE pointer |
1584 | | * @param rcfg pointer to a RDCU configuration to print |
1585 | | * @param add_ap_pars if non-zero write the adaptive RDCU parameter in the |
1586 | | * file |
1587 | | */ |
1588 | | |
1589 | | static void write_cfg_internal(FILE *fp, const struct rdcu_cfg *rcfg, |
1590 | | int add_ap_pars) |
1591 | 64 | { |
1592 | 64 | if (!fp) |
1593 | 0 | return; |
1594 | | |
1595 | 64 | if (!rcfg) { |
1596 | 0 | fprintf(fp, "Pointer to the compressor configuration is NULL.\n"); |
1597 | 0 | return; |
1598 | 0 | } |
1599 | | |
1600 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1601 | 64 | fprintf(fp, "\n"); |
1602 | 64 | fprintf(fp, "# RDCU compression configuration\n"); |
1603 | 64 | fprintf(fp, "\n"); |
1604 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1605 | 64 | fprintf(fp, "# Selected compression mode\n"); |
1606 | 64 | fprintf(fp, "# 0: raw mode\n"); |
1607 | 64 | fprintf(fp, "# 1: model mode with zero escape symbol mechanism\n"); |
1608 | 64 | fprintf(fp, "# 2: 1d differencing mode without input model with zero escape symbol mechanism\n"); |
1609 | 64 | fprintf(fp, "# 3: model mode with multi escape symbol mechanism\n"); |
1610 | 64 | fprintf(fp, "# 4: 1d differencing mode without input model multi escape symbol mechanism\n"); |
1611 | 64 | fprintf(fp, "\n"); |
1612 | 64 | fprintf(fp, "cmp_mode = %d\n", rcfg->cmp_mode); |
1613 | 64 | fprintf(fp, "\n"); |
1614 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1615 | 64 | fprintf(fp, "# Number of samples to compress, length of the data and model buffer\n"); |
1616 | 64 | fprintf(fp, "\n"); |
1617 | 64 | fprintf(fp, "samples = %" PRIu32 "\n", rcfg->samples); |
1618 | 64 | fprintf(fp, "\n"); |
1619 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1620 | 64 | fprintf(fp, "# Length of the compressed data buffer in number of samples\n"); |
1621 | 64 | fprintf(fp, "\n"); |
1622 | 64 | fprintf(fp, "buffer_length = %" PRIu32 "\n", rcfg->buffer_length); |
1623 | 64 | fprintf(fp, "\n"); |
1624 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1625 | 64 | fprintf(fp, "# Model weighting parameter\n"); |
1626 | 64 | fprintf(fp, "\n"); |
1627 | 64 | fprintf(fp, "model_value = %" PRIu32 "\n", rcfg->model_value); |
1628 | 64 | fprintf(fp, "\n"); |
1629 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1630 | 64 | fprintf(fp, "# Number of noise bits to be rounded\n"); |
1631 | 64 | fprintf(fp, "\n"); |
1632 | 64 | fprintf(fp, "round = %" PRIu32 "\n", rcfg->round); |
1633 | 64 | fprintf(fp, "\n"); |
1634 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1635 | 64 | fprintf(fp, "# Golomb parameter for dictionary selection\n"); |
1636 | 64 | fprintf(fp, "\n"); |
1637 | 64 | fprintf(fp, "golomb_par = %" PRIu32 "\n", rcfg->golomb_par); |
1638 | 64 | fprintf(fp, "\n"); |
1639 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1640 | 64 | fprintf(fp, "# Spillover threshold for encoding outliers\n"); |
1641 | 64 | fprintf(fp, "\n"); |
1642 | 64 | fprintf(fp, "spill = %" PRIu32 "\n", rcfg->spill); |
1643 | 64 | fprintf(fp, "\n"); |
1644 | 64 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1645 | | |
1646 | 64 | if (add_ap_pars) { |
1647 | 3 | fprintf(fp, "# Adaptive 1 Golomb parameter\n"); |
1648 | 3 | fprintf(fp, "\n"); |
1649 | 3 | fprintf(fp, "ap1_golomb_par = %" PRIu32 "\n", rcfg->ap1_golomb_par); |
1650 | 3 | fprintf(fp, "\n"); |
1651 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1652 | 3 | fprintf(fp, "# Adaptive 1 spillover threshold\n"); |
1653 | 3 | fprintf(fp, "\n"); |
1654 | 3 | fprintf(fp, "ap1_spill = %" PRIu32 "\n", rcfg->ap1_spill); |
1655 | 3 | fprintf(fp, "\n"); |
1656 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1657 | 3 | fprintf(fp, "# Adaptive 2 Golomb parameter\n"); |
1658 | 3 | fprintf(fp, "\n"); |
1659 | 3 | fprintf(fp, "ap2_golomb_par = %" PRIu32 "\n", rcfg->ap2_golomb_par); |
1660 | 3 | fprintf(fp, "\n"); |
1661 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1662 | 3 | fprintf(fp, "# Adaptive 2 spillover threshold\n"); |
1663 | 3 | fprintf(fp, "\n"); |
1664 | 3 | fprintf(fp, "ap2_spill = %" PRIu32 "\n", rcfg->ap2_spill); |
1665 | 3 | fprintf(fp, "\n"); |
1666 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1667 | 3 | fprintf(fp, "# RDCU data to compress start address, the first data address in the RDCU SRAM\n"); |
1668 | 3 | fprintf(fp, "\n"); |
1669 | 3 | fprintf(fp, "rdcu_data_adr = 0x%06"PRIX32"\n", rcfg->rdcu_data_adr); |
1670 | 3 | fprintf(fp, "\n"); |
1671 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1672 | 3 | fprintf(fp, "# RDCU model start address, the first model address in the RDCU SRAM\n"); |
1673 | 3 | fprintf(fp, "\n"); |
1674 | 3 | fprintf(fp, "rdcu_model_adr = 0x%06"PRIX32"\n", rcfg->rdcu_model_adr); |
1675 | 3 | fprintf(fp, "\n"); |
1676 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1677 | 3 | fprintf(fp, "# RDCU updated model start address, the first address in the RDCU SRAM where the\n"); |
1678 | 3 | fprintf(fp, "# updated model is stored\n"); |
1679 | 3 | fprintf(fp, "\n"); |
1680 | 3 | fprintf(fp, "rdcu_new_model_adr = 0x%06"PRIX32"\n", rcfg->rdcu_new_model_adr); |
1681 | 3 | fprintf(fp, "\n"); |
1682 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1683 | 3 | fprintf(fp, "# RDCU compressed data start address, the first output data address in the SRAM\n"); |
1684 | 3 | fprintf(fp, "\n"); |
1685 | 3 | fprintf(fp, "rdcu_buffer_adr = 0x%06"PRIX32"\n", rcfg->rdcu_buffer_adr); |
1686 | 3 | fprintf(fp, "\n"); |
1687 | 3 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1688 | 3 | } |
1689 | 64 | } |
1690 | | |
1691 | | |
1692 | | /** |
1693 | | * @brief prints config struct |
1694 | | * |
1695 | | * @param rcfg pointer to a RDCU configuration to print |
1696 | | * @param add_ap_pars if non-zero write the adaptive RDCU parameter in the file |
1697 | | */ |
1698 | | |
1699 | | void cmp_cfg_print(const struct rdcu_cfg *rcfg, int add_ap_pars) |
1700 | 18 | { |
1701 | 18 | write_cfg_internal(stdout, rcfg, add_ap_pars); |
1702 | 18 | } |
1703 | | |
1704 | | |
1705 | | /** |
1706 | | * @brief write compression configuration to a file |
1707 | | * |
1708 | | * @param rcfg pointer to a RDCU configuration to print |
1709 | | * @param output_prefix prefix of the written file (.cfg is added to the prefix) |
1710 | | * @param verbose print verbose output if not zero |
1711 | | * @param add_ap_pars if non-zero write the adaptive RDCU parameter in the file |
1712 | | * |
1713 | | * @returns 0 on success, error otherwise |
1714 | | */ |
1715 | | |
1716 | | int cmp_cfg_fo_file(const struct rdcu_cfg *rcfg, const char *output_prefix, |
1717 | | int verbose, int add_ap_pars) |
1718 | 46 | { |
1719 | 46 | FILE *fp = open_file(output_prefix, ".cfg"); |
1720 | | |
1721 | 46 | if (fp == NULL) { |
1722 | 0 | fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix, |
1723 | 0 | ".cfg", strerror(errno)); |
1724 | 0 | return -1; |
1725 | 0 | } |
1726 | | |
1727 | 46 | write_cfg_internal(fp, rcfg, add_ap_pars); |
1728 | | |
1729 | 46 | fclose(fp); |
1730 | | |
1731 | 46 | if (verbose) |
1732 | 0 | cmp_cfg_print(rcfg, add_ap_pars); |
1733 | | |
1734 | 46 | return 0; |
1735 | 46 | } |
1736 | | |
1737 | | |
1738 | | /** |
1739 | | * @brief write a decompression information structure to a file |
1740 | | * |
1741 | | * @param info compressor information contains information of an |
1742 | | * executed compression |
1743 | | * @param output_prefix prefix of the written file (.info is added to the prefix) |
1744 | | * @param add_ap_pars if non-zero write the additional RDCU parameter in the |
1745 | | * file |
1746 | | * |
1747 | | * @returns 0 on success, error otherwise |
1748 | | */ |
1749 | | |
1750 | | int cmp_info_to_file(const struct cmp_info *info MAYBE_UNUSED, |
1751 | | const char *output_prefix, int add_ap_pars) |
1752 | 55 | { |
1753 | 55 | FILE *fp = open_file(output_prefix, ".info"); |
1754 | | |
1755 | 55 | if (fp == NULL) { |
1756 | 0 | fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix, |
1757 | 0 | ".info", strerror(errno)); |
1758 | 0 | return -1; |
1759 | 0 | } |
1760 | | |
1761 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1762 | 55 | fprintf(fp, "# Decompression Information File\n"); |
1763 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1764 | 55 | fprintf(fp, "# Compression mode used\n"); |
1765 | 55 | fprintf(fp, "# 0: raw mode\n"); |
1766 | 55 | fprintf(fp, "# 1: model mode with zero escape symbol mechanism\n"); |
1767 | 55 | fprintf(fp, "# 2: 1d differencing mode without input model with zero escape symbol mechanism\n"); |
1768 | 55 | fprintf(fp, "# 3: model mode with multi escape symbol mechanism\n"); |
1769 | 55 | fprintf(fp, "# 4: 1d differencing mode without input model multi escape symbol mechanism\n"); |
1770 | 55 | fprintf(fp, "\n"); |
1771 | 55 | fprintf(fp, "cmp_mode_used = %" PRIu32 "\n", info->cmp_mode_used); |
1772 | 55 | fprintf(fp, "\n"); |
1773 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1774 | 55 | fprintf(fp, "# Number of samples used, measured in 16 bit units, length of the data and model buffer\n"); |
1775 | 55 | fprintf(fp, "\n"); |
1776 | 55 | fprintf(fp, "samples_used = %" PRIu32 "\n", info->samples_used); |
1777 | 55 | fprintf(fp, "\n"); |
1778 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1779 | 55 | fprintf(fp, "# Compressed data size; measured in bits\n"); |
1780 | 55 | fprintf(fp, "\n"); |
1781 | 55 | fprintf(fp, "cmp_size = %" PRIu32 "\n", info->cmp_size); |
1782 | 55 | fprintf(fp, "\n"); |
1783 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1784 | 55 | fprintf(fp, "# Golomb parameter used\n"); |
1785 | 55 | fprintf(fp, "\n"); |
1786 | 55 | fprintf(fp, "golomb_par_used = %" PRIu32 "\n", info->golomb_par_used); |
1787 | 55 | fprintf(fp, "\n"); |
1788 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1789 | 55 | fprintf(fp, "# Spillover threshold used\n"); |
1790 | 55 | fprintf(fp, "\n"); |
1791 | 55 | fprintf(fp, "spill_used = %" PRIu32 "\n", info->spill_used); |
1792 | 55 | fprintf(fp, "\n"); |
1793 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1794 | 55 | fprintf(fp, "# Model weighting parameter used\n"); |
1795 | 55 | fprintf(fp, "\n"); |
1796 | 55 | fprintf(fp, "model_value_used = %u\n", info->model_value_used); |
1797 | 55 | fprintf(fp, "\n"); |
1798 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1799 | 55 | fprintf(fp, "# Number of noise bits to be rounded used\n"); |
1800 | 55 | fprintf(fp, "\n"); |
1801 | 55 | fprintf(fp, "round_used = %u\n", info->round_used); |
1802 | 55 | fprintf(fp, "\n"); |
1803 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1804 | | |
1805 | 55 | if (add_ap_pars) { |
1806 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1807 | 0 | fprintf(fp, "# Hardware Compressor Settings (not need for SW compression)\n"); |
1808 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1809 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1810 | 0 | fprintf(fp, "\n"); |
1811 | 0 | fprintf(fp, "# Adaptive compressed data size 1; measured in bits\n"); |
1812 | 0 | fprintf(fp, "\n"); |
1813 | 0 | fprintf(fp, "ap1_cmp_size = %" PRIu32 "\n", info->ap1_cmp_size); |
1814 | 0 | fprintf(fp, "\n"); |
1815 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1816 | 0 | fprintf(fp, "# Adaptive compressed data size 2; measured in bits\n"); |
1817 | 0 | fprintf(fp, "\n"); |
1818 | 0 | fprintf(fp, "ap2_cmp_size = %" PRIu32 "\n", info->ap2_cmp_size); |
1819 | 0 | fprintf(fp, "\n"); |
1820 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1821 | 0 | fprintf(fp, "# Updated model info start address used\n"); |
1822 | 0 | fprintf(fp, "\n"); |
1823 | 0 | fprintf(fp, "rdcu_new_model_adr_used = 0x%06"PRIX32"\n", info->rdcu_new_model_adr_used); |
1824 | 0 | fprintf(fp, "\n"); |
1825 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1826 | 0 | fprintf(fp, " #RDCU compressed data start address\n"); |
1827 | 0 | fprintf(fp, "\n"); |
1828 | 0 | fprintf(fp, "rdcu_cmp_adr_used = 0x%06"PRIX32"\n", info->rdcu_cmp_adr_used); |
1829 | 0 | fprintf(fp, "\n"); |
1830 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1831 | 0 | } |
1832 | 55 | fprintf(fp, "# Compressor errors\n"); |
1833 | 55 | fprintf(fp, "\n"); |
1834 | 55 | fprintf(fp, "# [bit 0] small_buffer_err; The length for the compressed data buffer is too small\n"); |
1835 | 55 | fprintf(fp, "# [bit 1] cmp_mode_err; The cmp_mode parameter is not set correctly\n"); |
1836 | 55 | fprintf(fp, "# [bit 2] model_value_err; The model_value parameter is not set correctly\n"); |
1837 | 55 | fprintf(fp, "# [bit 3] cmp_par_err; The spill, golomb_par combination is not set correctly\n"); |
1838 | 55 | fprintf(fp, "# [bit 4] ap1_cmp_par_err; The ap1_spill, ap1_golomb_par combination is not set correctly (only HW compression)\n"); |
1839 | 55 | fprintf(fp, "# [bit 5] ap2_cmp_par_err; The ap2_spill, ap2_golomb_par combination is not set correctly (only HW compression)\n"); |
1840 | 55 | fprintf(fp, "# [bit 6] mb_err; Multi bit error detected by the memory controller (only HW compression)\n"); |
1841 | 55 | fprintf(fp, "# [bit 7] slave_busy_err; The bus master has received the 'slave busy' status (only HW compression)\n"); |
1842 | 55 | fprintf(fp, "# [bit 8] slave_blocked_err; The bus master has received the “slave blocked” status (only HW compression)\n"); |
1843 | 55 | fprintf(fp, "# [bit 9] invalid address_err; The bus master has received the “invalid address” status (only HW compression)\n"); |
1844 | 55 | fprintf(fp, "\n"); |
1845 | 55 | fprintf(fp, "cmp_err = %x\n", info->cmp_err); |
1846 | 55 | fprintf(fp, "\n"); |
1847 | 55 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1848 | 55 | fclose(fp); |
1849 | | |
1850 | 55 | return 0; |
1851 | 55 | } |
1852 | | |
1853 | | |
1854 | | /** |
1855 | | * @brief write compression parameters to a stream |
1856 | | * @note internal use only! |
1857 | | * |
1858 | | * @param fp FILE pointer |
1859 | | * @param par pointer to a compression parameters struct to print |
1860 | | */ |
1861 | | |
1862 | | static void write_cmp_par_internal(FILE *fp, const struct cmp_par *par) |
1863 | 0 | { |
1864 | 0 | if (!fp) |
1865 | 0 | return; |
1866 | | |
1867 | 0 | if (!par) { |
1868 | 0 | fprintf(fp, "Pointer to the compression parameters is NULL.\n"); |
1869 | 0 | return; |
1870 | 0 | } |
1871 | | |
1872 | | |
1873 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1874 | 0 | fprintf(fp, "\n"); |
1875 | 0 | fprintf(fp, "# Chunk compression parameters\n"); |
1876 | 0 | fprintf(fp, "\n"); |
1877 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1878 | |
|
1879 | 0 | fprintf(fp, "cmp_mode = %d\n", par->cmp_mode); |
1880 | 0 | fprintf(fp, "model_value = %" PRIu32 "\n", par->model_value); |
1881 | 0 | fprintf(fp, "lossy_par = %" PRIu32 "\n", par->lossy_par); |
1882 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1883 | |
|
1884 | 0 | fprintf(fp, "nc_imagette = %" PRIu32 "\n", par->nc_imagette); |
1885 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1886 | |
|
1887 | 0 | fprintf(fp, "s_exp_flags = %" PRIu32 "\n", par->s_exp_flags); |
1888 | 0 | fprintf(fp, "s_fx = %" PRIu32 "\n", par->s_fx); |
1889 | 0 | fprintf(fp, "s_ncob = %" PRIu32 "\n", par->s_ncob); |
1890 | 0 | fprintf(fp, "s_efx = %" PRIu32 "\n", par->s_efx); |
1891 | 0 | fprintf(fp, "s_ecob = %" PRIu32 "\n", par->s_ecob); |
1892 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1893 | |
|
1894 | 0 | fprintf(fp, "l_exp_flags = %" PRIu32 "\n", par->l_exp_flags); |
1895 | 0 | fprintf(fp, "l_fx = %" PRIu32 "\n", par->l_fx); |
1896 | 0 | fprintf(fp, "l_ncob = %" PRIu32 "\n", par->l_ncob); |
1897 | 0 | fprintf(fp, "l_efx = %" PRIu32 "\n", par->l_efx); |
1898 | 0 | fprintf(fp, "l_ecob = %" PRIu32 "\n", par->l_ecob); |
1899 | 0 | fprintf(fp, "l_fx_cob_variance = %" PRIu32 "\n", par->l_fx_cob_variance); |
1900 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1901 | |
|
1902 | 0 | fprintf(fp, "saturated_imagette = %" PRIu32 "\n", par->saturated_imagette); |
1903 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1904 | |
|
1905 | 0 | fprintf(fp, "nc_offset_mean = %" PRIu32 "\n", par->nc_offset_mean); |
1906 | 0 | fprintf(fp, "nc_offset_variance = %" PRIu32 "\n", par->nc_offset_variance); |
1907 | 0 | fprintf(fp, "nc_background_mean = %" PRIu32 "\n", par->nc_background_mean); |
1908 | 0 | fprintf(fp, "nc_background_variance = %" PRIu32 "\n", par->nc_background_variance); |
1909 | 0 | fprintf(fp, "nc_background_outlier_pixels = %" PRIu32 "\n", par->nc_background_outlier_pixels); |
1910 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1911 | |
|
1912 | 0 | fprintf(fp, "smearing_mean = %" PRIu32 "\n", par->smearing_mean); |
1913 | 0 | fprintf(fp, "smearing_variance_mean = %" PRIu32 "\n", par->smearing_variance_mean); |
1914 | 0 | fprintf(fp, "smearing_outlier_pixels = %" PRIu32 "\n", par->smearing_outlier_pixels); |
1915 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1916 | |
|
1917 | 0 | fprintf(fp, "fc_imagette = %" PRIu32 "\n", par->fc_imagette); |
1918 | 0 | fprintf(fp, "fc_offset_mean = %" PRIu32 "\n", par->fc_offset_mean); |
1919 | 0 | fprintf(fp, "fc_offset_variance = %" PRIu32 "\n", par->fc_offset_variance); |
1920 | 0 | fprintf(fp, "fc_background_mean = %" PRIu32 "\n", par->fc_background_mean); |
1921 | 0 | fprintf(fp, "fc_background_variance = %" PRIu32 "\n", par->fc_background_variance); |
1922 | 0 | fprintf(fp, "fc_background_outlier_pixels = %" PRIu32 "\n", par->fc_background_outlier_pixels); |
1923 | 0 | fprintf(fp, "#-------------------------------------------------------------------------------\n"); |
1924 | 0 | } |
1925 | | |
1926 | | |
1927 | | /** |
1928 | | * @brief prints cmp_par struct |
1929 | | * |
1930 | | * @param par pointer to a compression parameters struct to print |
1931 | | */ |
1932 | | |
1933 | | void cmp_par_print(const struct cmp_par *par) |
1934 | 0 | { |
1935 | 0 | write_cmp_par_internal(stdout, par); |
1936 | 0 | } |
1937 | | |
1938 | | |
1939 | | /** |
1940 | | * @brief write the compression parameters to a file |
1941 | | * |
1942 | | * @param par pointer to a compression parameters struct |
1943 | | * @param output_prefix prefix of the written file (.par is added to the prefix) |
1944 | | * @param verbose print verbose output if not zero |
1945 | | * |
1946 | | * @returns 0 on success, error otherwise |
1947 | | */ |
1948 | | |
1949 | | int cmp_par_fo_file(const struct cmp_par *par, const char *output_prefix, |
1950 | | int verbose) |
1951 | 0 | { |
1952 | 0 | FILE *fp = open_file(output_prefix, ".par"); |
1953 | |
|
1954 | 0 | if (fp == NULL) { |
1955 | 0 | fprintf(stderr, "%s: %s%s: %s\n", PROGRAM_NAME, output_prefix, |
1956 | 0 | ".cfg", strerror(errno)); |
1957 | 0 | return -1; |
1958 | 0 | } |
1959 | | |
1960 | 0 | write_cmp_par_internal(fp, par); |
1961 | |
|
1962 | 0 | fclose(fp); |
1963 | |
|
1964 | 0 | if (verbose) |
1965 | 0 | cmp_par_print(par); |
1966 | |
|
1967 | 0 | return 0; |
1968 | 0 | } |