X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=utilities%2Fpspp-dump-sav.c;h=3d85b9b0890b26a1d27b225318ed0f1ec0da1fab;hb=0b4388bfca70b1ce3e9daeb00d48681db823a337;hp=f207d8ecbf0f3362f2daf5e4f7d9245714555c86;hpb=3dd0f6ae0d5eb73a2270a243e443c4ae03c2c16e;p=pspp diff --git a/utilities/pspp-dump-sav.c b/utilities/pspp-dump-sav.c index f207d8ecbf..3d85b9b089 100644 --- a/utilities/pspp-dump-sav.c +++ b/utilities/pspp-dump-sav.c @@ -37,6 +37,7 @@ #include "gl/progname.h" #include "gl/version-etc.h" #include "gl/xalloc.h" +#include "gl/xsize.h" #define ID_MAX_LEN 64 @@ -75,6 +76,7 @@ static void read_machine_float_info (struct sfm_reader *, 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); @@ -99,7 +101,7 @@ static void read_simple_compressed_data (struct sfm_reader *, int max_cases); 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); @@ -235,6 +237,8 @@ main (int argc, char *argv[]) else if (r.compression == COMP_ZLIB) read_zlib_compressed_data (&r); + free (r.var_widths); + fclose (r.file); } @@ -379,6 +383,8 @@ format_name (int format) case 37: return "CCE"; case 38: return "EDATE"; case 39: return "SDATE"; + case 40: return "MTIME"; + case 41: return "YMDHMS"; default: return "invalid"; } } @@ -398,7 +404,7 @@ read_variable_record (struct sfm_reader *r) 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); @@ -444,14 +450,12 @@ read_variable_record (struct sfm_reader *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); @@ -516,14 +520,14 @@ print_untyped_value (struct sfm_reader *r, char raw_value[8]) 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; @@ -556,8 +560,8 @@ read_value_label_record (struct sfm_reader *r) /* 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'); } @@ -604,6 +608,10 @@ read_extension_record (struct sfm_reader *r) 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. */ @@ -727,6 +735,38 @@ read_machine_float_info (struct sfm_reader *r, size_t size, size_t count) 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) @@ -735,7 +775,7 @@ read_extra_product_info (struct sfm_reader *r, 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); @@ -749,7 +789,7 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) 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; @@ -797,7 +837,11 @@ read_mrsets (struct sfm_reader *r, size_t size, size_t count) } 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' " @@ -867,7 +911,7 @@ read_display_parameters (struct sfm_reader *r, size_t size, size_t count) includes_width = false; else { - sys_warn (r, "Extension 11 has bad count %zu (for %zu variables.", + sys_warn (r, "Extension 11 has bad count %zu (for %zu variables).", count, n_vars); skip_bytes (r, size * count); return; @@ -905,7 +949,7 @@ read_long_var_name_map (struct sfm_reader *r, size_t size, size_t count) 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); @@ -922,7 +966,7 @@ read_long_string_map (struct sfm_reader *r, size_t size, size_t count) 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); @@ -1000,7 +1044,7 @@ read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count) 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); } @@ -1013,6 +1057,8 @@ read_character_encoding (struct sfm_reader *r, size_t size, size_t count) read_string (r, encoding, count + 1); printf ("%08llx: Character Encoding: %s\n", posn, encoding); + + free (encoding); } static void @@ -1085,36 +1131,33 @@ read_long_string_missing_values (struct sfm_reader *r, 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); @@ -1192,7 +1235,7 @@ read_variable_attributes (struct sfm_reader *r, size_t size, size_t count) 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, ':'); @@ -1222,7 +1265,7 @@ read_simple_compressed_data (struct sfm_reader *r, int max_cases) { 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]; @@ -1385,18 +1428,23 @@ struct text_record 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; } @@ -1576,10 +1624,10 @@ sys_error (struct sfm_reader *r, const char *format, ...) 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)); @@ -1592,9 +1640,9 @@ read_bytes_internal (struct sfm_reader *r, bool eof_is_ok, /* 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. @@ -1602,9 +1650,9 @@ read_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) 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