Coverage Report

Created: 2025-08-26 06:06

/src/flex/src/tables.c
Line
Count
Source (jump to first uncovered line)
1
/*  tables.c - tables serialization code
2
 *
3
 *  Copyright (c) 1990 The Regents of the University of California.
4
 *  All rights reserved.
5
 *
6
 *  This code is derived from software contributed to Berkeley by
7
 *  Vern Paxson.
8
 *
9
 *  The United States Government has rights in this work pursuant
10
 *  to contract no. DE-AC03-76SF00098 between the United States
11
 *  Department of Energy and the University of California.
12
 *
13
 *  This file is part of flex.
14
 *
15
 *  Redistribution and use in source and binary forms, with or without
16
 *  modification, are permitted provided that the following conditions
17
 *  are met:
18
 *
19
 *  1. Redistributions of source code must retain the above copyright
20
 *     notice, this list of conditions and the following disclaimer.
21
 *  2. Redistributions in binary form must reproduce the above copyright
22
 *     notice, this list of conditions and the following disclaimer in the
23
 *     documentation and/or other materials provided with the distribution.
24
 *
25
 *  Neither the name of the University nor the names of its contributors
26
 *  may be used to endorse or promote products derived from this software
27
 *  without specific prior written permission.
28
 *
29
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
30
 *  IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
31
 *  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32
 *  PURPOSE.
33
 */
34

35
36
#include "flexdef.h"
37
#include "tables.h"
38
39
/** Convert size_t to t_flag.
40
 *  @param n in {1,2,4}
41
 *  @return YYTD_DATA*. 
42
 */
43
#define BYTES2TFLAG(n)\
44
0
    (((n) == sizeof(flex_int8_t))\
45
0
        ? YYTD_DATA8\
46
0
        :(((n)== sizeof(flex_int16_t))\
47
0
            ? YYTD_DATA16\
48
0
            : YYTD_DATA32))
49
50
/** Clear YYTD_DATA* bit flags
51
 * @return the flag with the YYTD_DATA* bits cleared
52
 */
53
0
#define TFLAGS_CLRDATA(flg) ((flg) & ~(YYTD_DATA8 | YYTD_DATA16 | YYTD_DATA32))
54
55
int     yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v);
56
int     yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v);
57
int     yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v);
58
int     yytbl_writen (struct yytbl_writer *wr, void *v, int len);
59
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i);
60
/* XXX Not used
61
static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
62
          int j, int k);
63
 */
64
65
66
/** Initialize the table writer.
67
 *  @param wr an uninitialized writer
68
 *  @param out the output file
69
 *  @return 0 on success
70
 */
71
int yytbl_writer_init (struct yytbl_writer *wr, FILE * out)
72
0
{
73
0
  wr->out = out;
74
0
  wr->total_written = 0;
75
0
  return 0;
76
0
}
77
78
/** Initialize a table header.
79
 *  @param th  The uninitialized structure
80
 *  @param version_str the  version string
81
 *  @param name the name of this table set
82
 */
83
int yytbl_hdr_init (struct yytbl_hdr *th, const char *version_str,
84
        const char *name)
85
0
{
86
0
  memset (th, 0, sizeof (struct yytbl_hdr));
87
88
0
  th->th_magic = YYTBL_MAGIC;
89
0
  th->th_hsize = (flex_uint32_t) (14 + strlen (version_str) + 1 + strlen (name) + 1);
90
0
  th->th_hsize += (8 - (th->th_hsize % 8)) % 8; // Pad to 64-bit boundary
91
0
  th->th_ssize = 0; // Not known at this point.
92
0
  th->th_flags = 0;
93
0
  th->th_version = xstrdup(version_str);
94
0
  th->th_name = xstrdup(name);
95
0
  return 0;
96
0
}
97
98
/** Allocate and initialize a table data structure.
99
 *  @param td a pointer to an uninitialized table
100
 *  @param id  the table identifier
101
 *  @return 0 on success
102
 */
103
int yytbl_data_init (struct yytbl_data *td, enum yytbl_id id)
104
0
{
105
106
0
  memset (td, 0, sizeof (struct yytbl_data));
107
0
  td->td_id = id;
108
0
  td->td_flags = YYTD_DATA32;
109
0
  return 0;
110
0
}
111
112
/** Clean up table and data array.
113
 *  @param td will be destroyed
114
 *  @return 0 on success
115
 */
116
int yytbl_data_destroy (struct yytbl_data *td)
117
0
{
118
0
  free(td->td_data);
119
0
  td->td_data = 0;
120
0
  free (td);
121
0
  return 0;
122
0
}
123
124
/** Write enough padding to bring the file pointer to a 64-bit boundary. */
125
static int yytbl_write_pad64 (struct yytbl_writer *wr)
126
0
{
127
0
  int bwritten = 0;
128
129
0
  while (wr->total_written % (8 * sizeof(flex_uint8_t)) > 0) {
130
0
    if (yytbl_write8 (wr, 0) < 0)
131
0
      return -1;
132
0
    else
133
0
      bwritten++;
134
0
  }
135
0
  return bwritten;
136
0
}
137
138
/** write the header.
139
 *  @param wr the output stream
140
 *  @param th table header to be written
141
 *  @return -1 on error, or bytes written on success.
142
 */
143
int yytbl_hdr_fwrite (struct yytbl_writer *wr, const struct yytbl_hdr *th)
144
0
{
145
0
  int  sz, rv;
146
0
  int     bwritten = 0;
147
148
0
  if (yytbl_write32 (wr, th->th_magic) < 0
149
0
      || yytbl_write32 (wr, th->th_hsize) < 0)
150
0
    flex_die (_("th_magic|th_hsize write32 failed"));
151
0
  bwritten += 8;
152
153
0
  if (fgetpos (wr->out, &(wr->th_ssize_pos)) != 0)
154
0
    flex_die (_("fgetpos failed"));
155
156
0
  if (yytbl_write32 (wr, th->th_ssize) < 0
157
0
      || yytbl_write16 (wr, th->th_flags) < 0)
158
0
    flex_die (_("th_ssize|th_flags write failed"));
159
0
  bwritten += 6;
160
161
0
  sz = (int) strlen (th->th_version) + 1;
162
0
  if ((rv = yytbl_writen (wr, th->th_version, sz)) != sz)
163
0
    flex_die (_("th_version written failed"));
164
0
  bwritten += rv;
165
166
0
  sz = (int) strlen (th->th_name) + 1;
167
0
  if ((rv = yytbl_writen (wr, th->th_name, sz)) != sz)
168
0
    flex_die (_("th_name written failed"));
169
0
  bwritten += rv;
170
171
  /* add padding */
172
0
  if ((rv = yytbl_write_pad64 (wr)) < 0)
173
0
    flex_die (_("pad64 failed"));
174
0
  bwritten += rv;
175
176
  /* Sanity check */
177
0
  if (bwritten != (int) th->th_hsize)
178
0
    flex_die (_("pad64 failed"));
179
180
0
  return bwritten;
181
0
}
182
183
184
/** Write this table.
185
 *  @param wr the file writer
186
 *  @param td table data to be written
187
 *  @return -1 on error, or bytes written on success.
188
 */
189
int yytbl_data_fwrite (struct yytbl_writer *wr, struct yytbl_data *td)
190
0
{
191
0
  int  rv;
192
0
  flex_int32_t bwritten = 0;
193
0
  flex_int32_t i, total_len;
194
0
  fpos_t  pos;
195
196
0
  if ((rv = yytbl_write16 (wr, td->td_id)) < 0)
197
0
    return -1;
198
0
  bwritten += rv;
199
200
0
  if ((rv = yytbl_write16 (wr, td->td_flags)) < 0)
201
0
    return -1;
202
0
  bwritten += rv;
203
204
0
  if ((rv = yytbl_write32 (wr, td->td_hilen)) < 0)
205
0
    return -1;
206
0
  bwritten += rv;
207
208
0
  if ((rv = yytbl_write32 (wr, td->td_lolen)) < 0)
209
0
    return -1;
210
0
  bwritten += rv;
211
212
0
  total_len = yytbl_calc_total_len (td);
213
0
  for (i = 0; i < total_len; i++) {
214
0
    switch (YYTDFLAGS2BYTES (td->td_flags)) {
215
0
    case sizeof (flex_int8_t):
216
0
      rv = yytbl_write8 (wr, (flex_uint8_t) yytbl_data_geti (td, i));
217
0
      break;
218
0
    case sizeof (flex_int16_t):
219
0
      rv = yytbl_write16 (wr, (flex_uint16_t) yytbl_data_geti (td, i));
220
0
      break;
221
0
    case sizeof (flex_int32_t):
222
0
      rv = yytbl_write32 (wr, (flex_uint32_t) yytbl_data_geti (td, i));
223
0
      break;
224
0
    default:
225
0
      flex_die (_("invalid td_flags detected"));
226
0
    }
227
0
    if (rv < 0) {
228
0
      flex_die (_("error while writing tables"));
229
0
      return -1;
230
0
    }
231
0
    bwritten += rv;
232
0
  }
233
234
  /* Sanity check */
235
0
  if (bwritten != (12 + total_len * (int) YYTDFLAGS2BYTES (td->td_flags))) {
236
0
    flex_die (_("insanity detected"));
237
0
    return -1;
238
0
  }
239
240
  /* add padding */
241
0
  if ((rv = yytbl_write_pad64 (wr)) < 0) {
242
0
    flex_die (_("pad64 failed"));
243
0
    return -1;
244
0
  }
245
0
  bwritten += rv;
246
247
  /* Now go back and update the th_hsize member */
248
0
  if (fgetpos (wr->out, &pos) != 0
249
0
      || fsetpos (wr->out, &(wr->th_ssize_pos)) != 0
250
0
      || yytbl_write32 (wr, (flex_uint32_t) wr->total_written) < 0
251
0
      || fsetpos (wr->out, &pos)) {
252
0
    flex_die (_("get|set|fwrite32 failed"));
253
0
    return -1;
254
0
  }
255
0
  else
256
    /* Don't count the int we just wrote. */
257
0
    wr->total_written -= (int) sizeof (flex_int32_t);
258
0
  return bwritten;
259
0
}
260
261
/** Write n bytes.
262
 *  @param  wr   the table writer
263
 *  @param  v    data to be written
264
 *  @param  len  number of bytes
265
 *  @return  -1 on error. number of bytes written on success.
266
 */
267
int yytbl_writen (struct yytbl_writer *wr, void *v, int len)
268
0
{
269
0
  int  rv;
270
271
0
  rv = (int) fwrite (v, 1, (size_t) len, wr->out);
272
0
  if (rv != len)
273
0
    return -1;
274
0
  wr->total_written += len;
275
0
  return len;
276
0
}
277
278
/** Write four bytes in network byte order
279
 *  @param  wr  the table writer
280
 *  @param  v    a dword in host byte order
281
 *  @return  -1 on error. number of bytes written on success.
282
 */
283
int yytbl_write32 (struct yytbl_writer *wr, flex_uint32_t v)
284
0
{
285
0
  flex_uint32_t vnet;
286
0
  int  bytes, rv;
287
288
0
  vnet = htonl (v);
289
0
  bytes = (int) sizeof (flex_uint32_t);
290
0
  rv = (int) fwrite (&vnet, (size_t) bytes, 1, wr->out);
291
0
  if (rv != 1)
292
0
    return -1;
293
0
  wr->total_written += bytes;
294
0
  return bytes;
295
0
}
296
297
/** Write two bytes in network byte order.
298
 *  @param  wr  the table writer
299
 *  @param  v    a word in host byte order
300
 *  @return  -1 on error. number of bytes written on success.
301
 */
302
int yytbl_write16 (struct yytbl_writer *wr, flex_uint16_t v)
303
0
{
304
0
  flex_uint16_t vnet;
305
0
  int  bytes, rv;
306
307
0
  vnet = htons (v);
308
0
  bytes = (int) sizeof (flex_uint16_t);
309
0
  rv = (int) fwrite (&vnet, (size_t) bytes, 1, wr->out);
310
0
  if (rv != 1)
311
0
    return -1;
312
0
  wr->total_written += bytes;
313
0
  return bytes;
314
0
}
315
316
/** Write a byte.
317
 *  @param  wr  the table writer
318
 *  @param  v    the value to be written
319
 *  @return  -1 on error. number of bytes written on success.
320
 */
321
int yytbl_write8 (struct yytbl_writer *wr, flex_uint8_t v)
322
0
{
323
0
  int  bytes, rv;
324
325
0
  bytes = (int) sizeof (flex_uint8_t);
326
0
  rv = (int) fwrite (&v, (size_t) bytes, 1, wr->out);
327
0
  if (rv != 1)
328
0
    return -1;
329
0
  wr->total_written += bytes;
330
0
  return bytes;
331
0
}
332
333
334
/* XXX Not Used */
335
#if 0
336
/** Extract data element [i][j] from array data tables. 
337
 * @param tbl data table
338
 * @param i index into higher dimension array. i should be zero for one-dimensional arrays.
339
 * @param j index into lower dimension array.
340
 * @param k index into struct, must be 0 or 1. Only valid for YYTD_ID_TRANSITION table
341
 * @return data[i][j + k]
342
 */
343
static flex_int32_t yytbl_data_getijk (const struct yytbl_data *tbl, int i,
344
          int j, int k)
345
{
346
  flex_int32_t lo;
347
348
  k %= 2;
349
  lo = tbl->td_lolen;
350
351
  switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
352
  case sizeof (flex_int8_t):
353
    return ((flex_int8_t *) (tbl->td_data))[(i * lo + j) * (k + 1) +
354
               k];
355
  case sizeof (flex_int16_t):
356
    return ((flex_int16_t *) (tbl->td_data))[(i * lo + j) * (k +
357
                    1) +
358
                k];
359
  case sizeof (flex_int32_t):
360
    return ((flex_int32_t *) (tbl->td_data))[(i * lo + j) * (k +
361
                    1) +
362
                k];
363
  default:
364
    flex_die (_("invalid td_flags detected"));
365
    break;
366
  }
367
368
  return 0;
369
}
370
#endif /* Not used */
371
372
/** Extract data element [i] from array data tables treated as a single flat array of integers.
373
 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
374
 * of structs. 
375
 * @param tbl data table
376
 * @param i index into array.
377
 * @return data[i]
378
 */
379
static flex_int32_t yytbl_data_geti (const struct yytbl_data *tbl, int i)
380
0
{
381
382
0
  switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
383
0
  case sizeof (flex_int8_t):
384
0
    return ((flex_int8_t *) (tbl->td_data))[i];
385
0
  case sizeof (flex_int16_t):
386
0
    return ((flex_int16_t *) (tbl->td_data))[i];
387
0
  case sizeof (flex_int32_t):
388
0
    return ((flex_int32_t *) (tbl->td_data))[i];
389
0
  default:
390
0
    flex_die (_("invalid td_flags detected"));
391
0
    break;
392
0
  }
393
0
  return 0;
394
0
}
395
396
/** Set data element [i] in array data tables treated as a single flat array of integers.
397
 * Be careful for 2-dimensional arrays or for YYTD_ID_TRANSITION, which is an array
398
 * of structs. 
399
 * @param tbl data table
400
 * @param i index into array.
401
 * @param newval new value for data[i]
402
 */
403
static void yytbl_data_seti (const struct yytbl_data *tbl, int i,
404
           flex_int32_t newval)
405
0
{
406
407
0
  switch (YYTDFLAGS2BYTES (tbl->td_flags)) {
408
0
  case sizeof (flex_int8_t):
409
0
    ((flex_int8_t *) (tbl->td_data))[i] = (flex_int8_t) newval;
410
0
    break;
411
0
  case sizeof (flex_int16_t):
412
0
    ((flex_int16_t *) (tbl->td_data))[i] = (flex_int16_t) newval;
413
0
    break;
414
0
  case sizeof (flex_int32_t):
415
0
    ((flex_int32_t *) (tbl->td_data))[i] = (flex_int32_t) newval;
416
0
    break;
417
0
  default:
418
0
    flex_die (_("invalid td_flags detected"));
419
0
    break;
420
0
  }
421
0
}
422
423
/** Calculate the number of bytes  needed to hold the largest
424
 *  absolute value in this data array.
425
 *  @param tbl  the data table
426
 *  @return sizeof(n) where n in {flex_int8_t, flex_int16_t, flex_int32_t}
427
 */
428
static size_t min_int_size (struct yytbl_data *tbl)
429
0
{
430
0
  flex_int32_t i, total_len;
431
0
  flex_int32_t max = 0;
432
433
0
  total_len = yytbl_calc_total_len (tbl);
434
435
0
  for (i = 0; i < total_len; i++) {
436
0
    flex_int32_t n;
437
438
0
    n = abs (yytbl_data_geti (tbl, i));
439
440
0
    if (max < n)
441
0
      max = n;
442
0
  }
443
444
0
  if (max <= INT8_MAX)
445
0
    return sizeof (flex_int8_t);
446
0
  else if (max <= INT16_MAX)
447
0
    return sizeof (flex_int16_t);
448
0
  else
449
0
    return sizeof (flex_int32_t);
450
0
}
451
452
/** Transform data to smallest possible of (int32, int16, int8).
453
 * For example, we may have generated an int32 array due to user options
454
 * (e.g., %option align), but if the maximum value in that array
455
 * is 80 (for example), then we can serialize it with only 1 byte per int.
456
 * This is NOT the same as compressed DFA tables. We're just trying
457
 * to save storage space here.
458
 *
459
 * @param tbl the table to be compressed
460
 */
461
void yytbl_data_compress (struct yytbl_data *tbl)
462
0
{
463
0
  flex_int32_t i, total_len;
464
0
  size_t newsz;
465
0
  struct yytbl_data newtbl;
466
467
0
  yytbl_data_init (&newtbl, tbl->td_id);
468
0
  newtbl.td_hilen = tbl->td_hilen;
469
0
  newtbl.td_lolen = tbl->td_lolen;
470
0
  newtbl.td_flags = tbl->td_flags;
471
472
0
  newsz = min_int_size (tbl);
473
474
475
0
  if (newsz == YYTDFLAGS2BYTES (tbl->td_flags))
476
    /* No change in this table needed. */
477
0
    return;
478
479
0
  if (newsz > YYTDFLAGS2BYTES (tbl->td_flags)) {
480
0
    flex_die (_("detected negative compression"));
481
0
    return;
482
0
  }
483
484
0
  total_len = yytbl_calc_total_len (tbl);
485
0
  newtbl.td_data = calloc ((size_t) total_len, newsz);
486
0
  newtbl.td_flags = (flex_uint16_t)
487
0
    (TFLAGS_CLRDATA (newtbl.td_flags) | BYTES2TFLAG (newsz));
488
489
0
  for (i = 0; i < total_len; i++) {
490
0
    flex_int32_t g;
491
492
0
    g = yytbl_data_geti (tbl, i);
493
0
    yytbl_data_seti (&newtbl, i, g);
494
0
  }
495
496
497
  /* Now copy over the old table */
498
0
  free (tbl->td_data);
499
0
  *tbl = newtbl;
500
0
}
501
502
/* vim:set noexpandtab cindent tabstop=8 softtabstop=0 shiftwidth=8 textwidth=0: */