#include "gl/progname.h"
#include "gl/version-etc.h"
#include "gl/xalloc.h"
+#include "gl/xsize.h"
#define ID_MAX_LEN 64
size_t size, size_t count);
static void read_extra_product_info (struct sfm_reader *,
size_t size, size_t count);
+static void read_variable_sets (struct sfm_reader *, size_t size, size_t count);
static void read_mrsets (struct sfm_reader *, size_t size, size_t count);
static void read_display_parameters (struct sfm_reader *,
size_t size, size_t count);
static void read_zlib_compressed_data (struct sfm_reader *);
static struct text_record *open_text_record (
- struct sfm_reader *, size_t size);
+ struct sfm_reader *, size_t size, size_t count);
static void close_text_record (struct text_record *);
static bool read_variable_to_value_pair (struct text_record *,
char **key, char **value);
else if (r.compression == COMP_ZLIB)
read_zlib_compressed_data (&r);
+ free (r.var_widths);
+
fclose (r.file);
}
case 37: return "CCE";
case 38: return "EDATE";
case 39: return "SDATE";
+ case 40: return "MTIME";
+ case 41: return "YMDHMS";
default: return "invalid";
}
}
char name[9];
printf ("%08llx: variable record #%d\n",
- (long long int) ftello (r->file), r->n_variable_records++);
+ (long long int) ftello (r->file), ++r->n_variable_records);
width = read_int (r);
has_variable_label = read_int (r);
if (has_variable_label == 1)
{
long long int offset = ftello (r->file);
- size_t len;
- char *label;
-
- len = read_int (r);
+ enum { MAX_LABEL_LEN = 65536 };
- /* Read up to 255 bytes of label. */
- label = xmalloc (len + 1);
- read_string (r, label, len + 1);
+ size_t len = read_int (r);
+ size_t read_len = MIN (MAX_LABEL_LEN, len);
+ char *label = xmalloc (read_len + 1);
+ read_string (r, label, read_len + 1);
printf("\t%08llx Variable label: \"%s\"\n", offset, label);
free (label);
static void
read_value_label_record (struct sfm_reader *r)
{
- int label_cnt, var_cnt;
+ int n_labels, n_vars;
int i;
printf ("%08llx: value labels record\n", (long long int) ftello (r->file));
/* Read number of labels. */
- label_cnt = read_int (r);
- for (i = 0; i < label_cnt; i++)
+ n_labels = read_int (r);
+ for (i = 0; i < n_labels; i++)
{
char raw_value[8];
unsigned char label_len;
/* Read number of variables associated with value label from type 4
record. */
printf ("\t%08llx: apply to variables", (long long int) ftello (r->file));
- var_cnt = read_int (r);
- for (i = 0; i < var_cnt; i++)
+ n_vars = read_int (r);
+ for (i = 0; i < n_vars; i++)
printf (" #%d", read_int (r));
putchar ('\n');
}
read_machine_float_info (r, size, count);
return;
+ case 5:
+ read_variable_sets (r, size, count);
+ return;
+
case 6:
/* DATE variable information. We don't use it yet, but we
should. */
DBL_DIG + 1, lowest, lowest, "LOWEST");
}
+/* Read record type 7, subtype 5. */
+static void
+read_variable_sets (struct sfm_reader *r, size_t size, size_t count)
+{
+ printf ("%08llx: variable sets\n", (long long int) ftello (r->file));
+ struct text_record *text = open_text_record (r, size, count);
+ for (;;)
+ {
+ while (text_match (text, '\n'))
+ continue;
+
+ const char *set = text_tokenize (text, '=');
+ if (!set)
+ break;
+
+ /* Always present even for an empty set. */
+ text_match (text, ' ');
+
+ char *variables = text_tokenize (text, '\n');
+ if (!variables)
+ printf ("\tset \"%s\" is empty\n", set);
+ else
+ {
+ size_t length = strlen (variables);
+ if (variables[length - 1] == '\r')
+ variables[length - 1] = '\0';
+ printf ("\tset \"%s\" contains \"%s\"\n", set, variables);
+ }
+ }
+ close_text_record (text);
+}
+
static void
read_extra_product_info (struct sfm_reader *r,
size_t size, size_t count)
const char *s;
printf ("%08llx: extra product info\n", (long long int) ftello (r->file));
- text = open_text_record (r, size * count);
+ text = open_text_record (r, size, count);
s = text_get_all (text);
print_string (s, strlen (s));
close_text_record (text);
printf ("%08llx: multiple response sets\n",
(long long int) ftello (r->file));
- text = open_text_record (r, size * count);
+ text = open_text_record (r, size, count);
for (;;)
{
const char *name;
}
number = text_tokenize (text, ' ');
- if (!strcmp (number, "11"))
+ if (!number)
+ sys_warn (r, "Missing label source value "
+ "following `E' at offset %zu in MRSETS record",
+ text_pos (text));
+ else if (!strcmp (number, "11"))
label_from_var_label = true;
else if (strcmp (number, "1"))
sys_warn (r, "Unexpected label source value `%s' "
printf ("%08llx: long variable names (short => long)\n",
(long long int) ftello (r->file));
- text = open_text_record (r, size * count);
+ text = open_text_record (r, size, count);
while (read_variable_to_value_pair (text, &var, &long_name))
printf ("\t%s => %s\n", var, long_name);
close_text_record (text);
printf ("%08llx: very long strings (variable => length)\n",
(long long int) ftello (r->file));
- text = open_text_record (r, size * count);
+ text = open_text_record (r, size, count);
while (read_variable_to_value_pair (text, &var, &length_s))
printf ("\t%s => %d\n", var, atoi (length_s));
close_text_record (text);
struct text_record *text;
printf ("%08llx: datafile attributes\n", (long long int) ftello (r->file));
- text = open_text_record (r, size * count);
+ text = open_text_record (r, size, count);
read_attributes (r, text, "datafile");
close_text_record (text);
}
read_string (r, encoding, count + 1);
printf ("%08llx: Character Encoding: %s\n", posn, encoding);
+
+ free (encoding);
}
static void
while (ftello (r->file) - start < size * count)
{
long long posn = ftello (r->file);
- char var_name[ID_MAX_LEN + 1];
- uint8_t n_missing_values;
- int var_name_len;
- int i;
/* Read variable name. */
- var_name_len = read_int (r);
+ int var_name_len = read_int (r);
if (var_name_len > ID_MAX_LEN)
sys_error (r, "Variable name length in long string value label "
"record (%d) exceeds %d-byte limit.",
var_name_len, ID_MAX_LEN);
+ char var_name[ID_MAX_LEN + 1];
read_string (r, var_name, var_name_len + 1);
/* Read number of values. */
+ uint8_t n_missing_values;
read_bytes (r, &n_missing_values, 1);
- printf ("\t%08llx: %s, %d missing values:",
- posn, var_name, n_missing_values);
+ /* Read value length. */
+ int value_length = read_int (r);
+
+ printf ("\t%08llx: %s, %d missing values, each %d bytes:",
+ posn, var_name, n_missing_values, value_length);
/* Read values. */
- for (i = 0; i < n_missing_values; i++)
+ for (int i = 0; i < n_missing_values; i++)
{
- char *value;
- int value_length;
-
posn = ftello (r->file);
/* Read value. */
- value_length = read_int (r);
- value = xmalloc (value_length + 1);
+ char *value = xmalloc (value_length + 1);
read_string (r, value, value_length + 1);
printf (" \"%s\"", value);
struct text_record *text;
printf ("%08llx: variable attributes\n", (long long int) ftello (r->file));
- text = open_text_record (r, size * count);
+ text = open_text_record (r, size, count);
for (;;)
{
const char *variable = text_tokenize (text, ':');
{
printf ("%08llx: case %d's uncompressible data begins\n",
(long long int) ftello (r->file), case_num);
- for (i = 0; i < r->n_var_widths; )
+ for (i = 0; i < r->n_var_widths;)
{
int width = r->var_widths[i];
char raw_value[8];
size_t pos; /* Current position in buffer. */
};
-/* Reads SIZE bytes into a text record for R,
+/* Reads SIZE * COUNT bytes into a text record for R,
and returns the new text record. */
static struct text_record *
-open_text_record (struct sfm_reader *r, size_t size)
+open_text_record (struct sfm_reader *r, size_t size, size_t count)
{
struct text_record *text = xmalloc (sizeof *text);
- char *buffer = xmalloc (size + 1);
- read_bytes (r, buffer, size);
- buffer[size] = '\0';
+
+ if (size_overflow_p (xsum (1, xtimes (size, count))))
+ sys_error (r, "Extension record too large.");
+
+ size_t n_bytes = size * count;
+ char *buffer = xmalloc (n_bytes + 1);
+ read_bytes (r, buffer, n_bytes);
+ buffer[n_bytes] = '\0';
text->reader = r;
text->buffer = buffer;
- text->size = size;
+ text->size = n_bytes;
text->pos = 0;
return text;
}
too. */
static inline bool
read_bytes_internal (struct sfm_reader *r, bool eof_is_ok,
- void *buf, size_t byte_cnt)
+ void *buf, size_t n_bytes)
{
- size_t bytes_read = fread (buf, 1, byte_cnt, r->file);
- if (bytes_read == byte_cnt)
+ size_t bytes_read = fread (buf, 1, n_bytes, r->file);
+ if (bytes_read == n_bytes)
return true;
else if (ferror (r->file))
sys_error (r, "System error: %s.", strerror (errno));
/* Reads BYTE_CNT into BUF.
Aborts upon I/O error or if end-of-file is encountered. */
static void
-read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
+read_bytes (struct sfm_reader *r, void *buf, size_t n_bytes)
{
- read_bytes_internal (r, false, buf, byte_cnt);
+ read_bytes_internal (r, false, buf, n_bytes);
}
/* Reads BYTE_CNT bytes into BUF.
Returns false if an immediate end-of-file is encountered.
Aborts if an I/O error or a partial read occurs. */
static bool
-try_read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt)
+try_read_bytes (struct sfm_reader *r, void *buf, size_t n_bytes)
{
- return read_bytes_internal (r, true, buf, byte_cnt);
+ return read_bytes_internal (r, true, buf, n_bytes);
}
/* Reads a 32-bit signed integer from R and returns its value in