#include "gl/progname.h"
#include "gl/version-etc.h"
#include "gl/xalloc.h"
+#include "gl/xsize.h"
#define ID_MAX_LEN 64
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);
if (argc - optind > 1)
printf ("Reading \"%s\":\n", r.file_name);
-
+
read_header (&r);
while ((rec_type = read_int (&r)) != 999)
{
else if (r.compression == COMP_ZLIB)
read_zlib_compressed_data (&r);
+ free (r.var_widths);
+
fclose (r.file);
}
-
+
return 0;
}
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, read_len;
- char label[255 + 1];
+ enum { MAX_LABEL_LEN = 65536 };
- len = read_int (r);
-
- /* Read up to 255 bytes of label. */
- read_len = MIN (sizeof label - 1, len);
+ 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);
-
- /* Skip unread label bytes. */
- skip_bytes (r, len - read_len);
+ free (label);
/* Skip label padding up to multiple of 4 bytes. */
skip_bytes (r, ROUND_UP (len, 4) - len);
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:
- /* Variable sets information. We don't use these yet.
- They only apply to GUIs; see VARSETS on the APPLY
- DICTIONARY command in SPSS documentation. */
- break;
-
case 6:
/* DATE variable information. We don't use it yet, but we
should. */
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);
const char *key;
int index;
- for (;;)
+ for (;;)
{
key = text_tokenize (text, '(');
if (key == NULL)
return true;
-
+
for (index = 1; ; index++)
{
/* Parse the value. */
const char *value = text_tokenize (text, '\n');
- if (value == NULL)
+ if (value == NULL)
{
sys_warn (r, "%s: Error parsing attribute value %s[%d]",
variable, key, index);
}
if (text_match (text, '/'))
- return true;
+ return true;
}
}
}
static void
-read_datafile_attributes (struct sfm_reader *r, size_t size, size_t count)
+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);
}
read_string (r, encoding, count + 1);
printf ("%08llx: Character Encoding: %s\n", posn, encoding);
+
+ free (encoding);
}
static void
}
static void
-read_variable_attributes (struct sfm_reader *r, size_t size, size_t count)
+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);
- for (;;)
+ text = open_text_record (r, size, count);
+ for (;;)
{
const char *variable = text_tokenize (text, ':');
if (variable == NULL || !read_attributes (r, text, variable))
- break;
+ break;
}
close_text_record (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;
}
}
static bool
-text_match (struct text_record *text, int c)
+text_match (struct text_record *text, int c)
{
- if (text->pos < text->size && text->buffer[text->pos] == c)
+ if (text->pos < text->size && text->buffer[text->pos] == c)
{
text->pos++;
return true;
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