Coverage Report

Created: 2025-06-15 00:57

/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
}