X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fdata%2Fsys-file-reader.c;h=54788deb6e217bb918d8873077e2cb305ffbea77;hb=8e27b1a0dba7f33b7acb0d8894efe2045b0bb98f;hp=9bb1c775783488b96275b69a405ae63ae16b947f;hpb=bea96fcb5c8cf6ffb179a830ecb39f52ff2c5db8;p=pspp diff --git a/src/data/sys-file-reader.c b/src/data/sys-file-reader.c index 9bb1c77578..54788deb6e 100644 --- a/src/data/sys-file-reader.c +++ b/src/data/sys-file-reader.c @@ -1,5 +1,5 @@ /* PSPP - a program for statistical analysis. - Copyright (C) 1997-2000, 2006-2007, 2009-2014 Free Software Foundation, Inc. + Copyright (C) 1997-2000, 2006-2007, 2009-2016 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,7 +16,6 @@ #include -#include "data/sys-file-reader.h" #include "data/sys-file-private.h" #include @@ -26,6 +25,7 @@ #include #include +#include "data/any-reader.h" #include "data/attributes.h" #include "data/case.h" #include "data/casereader-provider.h" @@ -45,6 +45,7 @@ #include "libpspp/assertion.h" #include "libpspp/compiler.h" #include "libpspp/i18n.h" +#include "libpspp/ll.h" #include "libpspp/message.h" #include "libpspp/misc.h" #include "libpspp/pool.h" @@ -98,7 +99,7 @@ struct sfm_header_record int weight_idx; /* 0 if unweighted, otherwise a var index. */ int nominal_case_size; /* Number of var positions. */ - /* These correspond to the members of struct sfm_file_info or a dictionary + /* These correspond to the members of struct any_file_info or a dictionary but in the system file's encoding rather than ASCII. */ char creation_date[10]; /* "dd mmm yy". */ char creation_time[9]; /* "hh:mm:ss". */ @@ -158,6 +159,7 @@ struct sfm_mrset struct sfm_extension_record { + struct ll ll; /* In struct sfm_reader 'var_attrs' list. */ int subtype; /* Record subtype. */ off_t pos; /* Starting offset in file. */ unsigned int size; /* Size of data elements. */ @@ -168,11 +170,13 @@ struct sfm_extension_record /* System file reader. */ struct sfm_reader { + struct any_reader any_reader; + /* Resource tracking. */ struct pool *pool; /* All system file state. */ /* File data. */ - struct sfm_read_info info; + struct any_read_info info; struct sfm_header_record header; struct sfm_var_record *vars; size_t n_vars; @@ -182,6 +186,7 @@ struct sfm_reader struct sfm_mrset *mrsets; size_t n_mrsets; struct sfm_extension_record *extensions[32]; + struct ll_list var_attrs; /* Contains "struct sfm_extension_record"s. */ /* File state. */ struct file_handle *fh; /* File handle. */ @@ -200,7 +205,7 @@ struct sfm_reader const char *encoding; /* String encoding. */ /* Decompression. */ - enum sfm_compression compression; + enum any_compression compression; double bias; /* Compression bias, usually 100.0. */ uint8_t opcodes[8]; /* Current block of opcodes. */ size_t opcode_idx; /* Next opcode to interpret, 8 if none left. */ @@ -219,6 +224,15 @@ struct sfm_reader static const struct casereader_class sys_file_casereader_class; +static struct sfm_reader * +sfm_reader_cast (const struct any_reader *r_) +{ + assert (r_->klass == &sys_file_reader_class); + return UP_CAST (r_, struct sfm_reader, any_reader); +} + +static bool sfm_close (struct any_reader *); + static struct variable *lookup_var_by_index (struct sfm_reader *, off_t, const struct sfm_var_record *, size_t n, int idx); @@ -268,7 +282,7 @@ static bool read_variable_record (struct sfm_reader *, struct sfm_var_record *); static bool read_value_label_record (struct sfm_reader *, struct sfm_value_label_record *); -static struct sfm_document_record *read_document_record (struct sfm_reader *); +static bool read_document_record (struct sfm_reader *); static bool read_extension_record (struct sfm_reader *, int subtype, struct sfm_extension_record **); static bool skip_extension_record (struct sfm_reader *, int subtype); @@ -283,8 +297,7 @@ static bool read_variable_to_value_pair (struct sfm_reader *, struct text_record *, struct variable **var, char **value); static void text_warn (struct sfm_reader *r, struct text_record *text, - const char *format, ...) - PRINTF_FORMAT (3, 4); + const char *format, ...) PRINTF_FORMAT (3, 4); static char *text_get_token (struct text_record *, struct substring delimiters, char *delimiter); static bool text_match (struct text_record *, char c); @@ -312,11 +325,11 @@ enum which_format static bool read_dictionary (struct sfm_reader *); static bool read_record (struct sfm_reader *, int type, size_t *allocated_vars, size_t *allocated_labels); -static bool read_header (struct sfm_reader *, struct sfm_read_info *, +static bool read_header (struct sfm_reader *, struct any_read_info *, struct sfm_header_record *); static void parse_header (struct sfm_reader *, const struct sfm_header_record *, - struct sfm_read_info *, struct dictionary *); + struct any_read_info *, struct dictionary *); static bool parse_variable_records (struct sfm_reader *, struct dictionary *, struct sfm_var_record *, size_t n); static void parse_format_spec (struct sfm_reader *, off_t pos, @@ -328,12 +341,12 @@ static void parse_display_parameters (struct sfm_reader *, struct dictionary *); static bool parse_machine_integer_info (struct sfm_reader *, const struct sfm_extension_record *, - struct sfm_read_info *); + struct any_read_info *); static void parse_machine_float_info (struct sfm_reader *, const struct sfm_extension_record *); static void parse_extra_product_info (struct sfm_reader *, const struct sfm_extension_record *, - struct sfm_read_info *); + struct any_read_info *); static void parse_mrsets (struct sfm_reader *, const struct sfm_extension_record *, size_t *allocated_mrsets); @@ -355,16 +368,16 @@ static void parse_variable_attributes (struct sfm_reader *, const struct sfm_extension_record *, struct dictionary *); static void assign_variable_roles (struct sfm_reader *, struct dictionary *); -static bool parse_long_string_value_labels (struct sfm_reader *, +static void parse_long_string_value_labels (struct sfm_reader *, const struct sfm_extension_record *, struct dictionary *); -static bool parse_long_string_missing_values ( +static void parse_long_string_missing_values ( struct sfm_reader *, const struct sfm_extension_record *, struct dictionary *); /* Frees the strings inside INFO. */ void -sfm_read_info_destroy (struct sfm_read_info *info) +any_read_info_destroy (struct any_read_info *info) { if (info) { @@ -377,7 +390,7 @@ sfm_read_info_destroy (struct sfm_read_info *info) /* Tries to open FH for reading as a system file. Returns an sfm_reader if successful, otherwise NULL. */ -struct sfm_reader * +static struct any_reader * sfm_open (struct file_handle *fh) { size_t allocated_mrsets = 0; @@ -385,10 +398,12 @@ sfm_open (struct file_handle *fh) /* Create and initialize reader. */ r = xzalloc (sizeof *r); + r->any_reader.klass = &sys_file_reader_class; r->pool = pool_create (); pool_register (r->pool, free, r); r->fh = fh_ref (fh); r->opcode_idx = sizeof r->opcodes; + ll_init (&r->var_attrs); /* TRANSLATORS: this fragment will be interpolated into messages in fh_lock() that identify types of files. */ @@ -396,7 +411,7 @@ sfm_open (struct file_handle *fh) if (r->lock == NULL) goto error; - r->file = fn_open (fh_get_file_name (fh), "rb"); + r->file = fn_open (fh, "rb"); if (r->file == NULL) { msg (ME, _("Error opening `%s' for reading as a system file: %s."), @@ -413,9 +428,11 @@ sfm_open (struct file_handle *fh) if (r->extensions[EXT_MRSETS2] != NULL) parse_mrsets (r, r->extensions[EXT_MRSETS2], &allocated_mrsets); - return r; + return &r->any_reader; + error: - sfm_close (r); + if (r) + sfm_close (&r->any_reader); return NULL; } @@ -445,7 +462,7 @@ read_dictionary (struct sfm_reader *r) if (!skip_bytes (r, 4)) return false; - if (r->compression == SFM_COMP_ZLIB && !read_zheader (r)) + if (r->compression == ANY_COMP_ZLIB && !read_zheader (r)) return false; return true; @@ -483,8 +500,7 @@ read_record (struct sfm_reader *r, int type, sys_error (r, r->pos, _("Duplicate type 6 (document) record.")); return false; } - r->document = read_document_record (r); - return r->document != NULL; + return read_document_record (r); case 7: if (!read_int (r, &subtype)) @@ -493,21 +509,32 @@ read_record (struct sfm_reader *r, int type, || subtype >= sizeof r->extensions / sizeof *r->extensions) { sys_warn (r, r->pos, - _("Unrecognized record type 7, subtype %d. Please " - "send a copy of this file, and the syntax which " - "created it to %s."), - subtype, PACKAGE_BUGREPORT); + _("Unrecognized record type 7, subtype %d. For help, " + "please send this file to %s and mention that you were " + "using %s."), + subtype, PACKAGE_BUGREPORT, PACKAGE_STRING); return skip_extension_record (r, subtype); } + else if (subtype == 18) + { + /* System files written by "Stata 14.1/-savespss- 1.77 by S.Radyakin" + put each variable attribute into a separate record with subtype + 18. I'm surprised that SPSS puts up with this. */ + struct sfm_extension_record *ext; + bool ok = read_extension_record (r, subtype, &ext); + if (ok && ext) + ll_push_tail (&r->var_attrs, &ext->ll); + return ok; + } else if (r->extensions[subtype] != NULL) { sys_warn (r, r->pos, _("Record type 7, subtype %d found here has the same " - "type as the record found near offset 0x%llx. " - "Please send a copy of this file, and the syntax " - "which created it to %s."), + "type as the record found near offset 0x%llx. For " + "help, please send this file to %s and mention that " + "you were using %s."), subtype, (long long int) r->extensions[subtype]->pos, - PACKAGE_BUGREPORT); + PACKAGE_BUGREPORT, PACKAGE_STRING); return skip_extension_record (r, subtype); } else @@ -523,7 +550,7 @@ read_record (struct sfm_reader *r, int type, /* Returns the character encoding obtained from R, or a null pointer if R doesn't have an indication of its character encoding. */ -const char * +static const char * sfm_get_encoding (const struct sfm_reader *r) { /* The EXT_ENCODING record is the best way to determine dictionary @@ -628,10 +655,11 @@ add_id (struct get_strings_aux *aux, const char *id, const char *title, ...) whatever encoding system file R uses. *IDS[I] is true if *STRINGSP[I] must be a valid PSPP language identifier, false if *STRINGSP[I] is free-form text. */ -size_t -sfm_get_strings (const struct sfm_reader *r, struct pool *pool, +static size_t +sfm_get_strings (const struct any_reader *r_, struct pool *pool, char ***titlesp, bool **idsp, char ***stringsp) { + struct sfm_reader *r = sfm_reader_cast (r_); const struct sfm_mrset *mrset; struct get_strings_aux aux; size_t var_idx; @@ -704,7 +732,6 @@ sfm_get_strings (const struct sfm_reader *r, struct pool *pool, mrset_idx); } - /* */ /* data file attributes */ /* variable attributes */ /* long var map */ @@ -722,15 +749,16 @@ sfm_get_strings (const struct sfm_reader *r, struct pool *pool, ENCODING is null, or the locale encoding if R specifies no encoding. If INFOP is non-null, then it receives additional info about the system - file, which the caller must eventually free with sfm_read_info_destroy() + file, which the caller must eventually free with any_read_info_destroy() when it is no longer needed. This function consumes R. The caller must use it again later, even to destroy it with sfm_close(). */ -struct casereader * -sfm_decode (struct sfm_reader *r, const char *encoding, - struct dictionary **dictp, struct sfm_read_info *infop) +static struct casereader * +sfm_decode (struct any_reader *r_, const char *encoding, + struct dictionary **dictp, struct any_read_info *infop) { + struct sfm_reader *r = sfm_reader_cast (r_); struct dictionary *dict; size_t i; @@ -814,22 +842,20 @@ sfm_decode (struct sfm_reader *r, const char *encoding, parse_long_var_name_map (r, r->extensions[EXT_LONG_NAMES], dict); /* The following records use long names, so they need to follow renaming. */ - if (r->extensions[EXT_VAR_ATTRS] != NULL) + if (!ll_is_empty (&r->var_attrs)) { - parse_variable_attributes (r, r->extensions[EXT_VAR_ATTRS], dict); + struct sfm_extension_record *ext; + ll_for_each (ext, struct sfm_extension_record, ll, &r->var_attrs) + parse_variable_attributes (r, ext, dict); /* Roles use the $@Role attribute. */ assign_variable_roles (r, dict); } - - if (r->extensions[EXT_LONG_LABELS] != NULL - && !parse_long_string_value_labels (r, r->extensions[EXT_LONG_LABELS], - dict)) - goto error; - if (r->extensions[EXT_LONG_MISSING] != NULL - && !parse_long_string_missing_values (r, r->extensions[EXT_LONG_MISSING], - dict)) - goto error; + if (r->extensions[EXT_LONG_LABELS] != NULL) + parse_long_string_value_labels (r, r->extensions[EXT_LONG_LABELS], dict); + if (r->extensions[EXT_LONG_MISSING] != NULL) + parse_long_string_missing_values (r, r->extensions[EXT_LONG_MISSING], + dict); /* Warn if the actual amount of data per case differs from the amount that the header claims. SPSS version 13 gets this @@ -863,7 +889,7 @@ sfm_decode (struct sfm_reader *r, const char *encoding, &sys_file_casereader_class, r); error: - sfm_close (r); + sfm_close (r_); dict_destroy (dict); *dictp = NULL; return NULL; @@ -873,17 +899,15 @@ error: closed with sfm_decode() or this function. Returns true if an I/O error has occurred on READER, false otherwise. */ -bool -sfm_close (struct sfm_reader *r) +static bool +sfm_close (struct any_reader *r_) { + struct sfm_reader *r = sfm_reader_cast (r_); bool error; - if (r == NULL) - return true; - if (r->file) { - if (fn_close (fh_get_file_name (r->fh), r->file) == EOF) + if (fn_close (r->fh, r->file) == EOF) { msg (ME, _("Error closing system file `%s': %s."), fh_get_file_name (r->fh), strerror (errno)); @@ -892,7 +916,7 @@ sfm_close (struct sfm_reader *r) r->file = NULL; } - sfm_read_info_destroy (&r->info); + any_read_info_destroy (&r->info); fh_unlock (r->lock); fh_unref (r->fh); @@ -907,18 +931,20 @@ static void sys_file_casereader_destroy (struct casereader *reader UNUSED, void *r_) { struct sfm_reader *r = r_; - sfm_close (r); + sfm_close (&r->any_reader); } -/* Returns true if FILE is an SPSS system file, - false otherwise. */ -bool +/* Detects whether FILE is an SPSS system file. Returns 1 if so, 0 if not, and + a negative errno value if there is an error reading FILE. */ +static int sfm_detect (FILE *file) { char magic[5]; + if (fseek (file, 0, SEEK_SET) != 0) + return -errno; if (fread (magic, 4, 1, file) != 1) - return false; + return ferror (file) ? -errno : 0; magic[4] = '\0'; return (!strcmp (ASCII_MAGIC, magic) @@ -930,7 +956,7 @@ sfm_detect (FILE *file) except for the string fields in *INFO, which parse_header() will initialize later once the file's encoding is known. */ static bool -read_header (struct sfm_reader *r, struct sfm_read_info *info, +read_header (struct sfm_reader *r, struct any_read_info *info, struct sfm_header_record *header) { uint8_t raw_layout_code[4]; @@ -979,9 +1005,9 @@ read_header (struct sfm_reader *r, struct sfm_read_info *info, if (!zmagic) { if (compressed == 0) - r->compression = SFM_COMP_NONE; + r->compression = ANY_COMP_NONE; else if (compressed == 1) - r->compression = SFM_COMP_SIMPLE; + r->compression = ANY_COMP_SIMPLE; else if (compressed != 0) { sys_error (r, 0, "System file header has invalid compression " @@ -992,7 +1018,7 @@ read_header (struct sfm_reader *r, struct sfm_read_info *info, else { if (compressed == 2) - r->compression = SFM_COMP_ZLIB; + r->compression = ANY_COMP_ZLIB; else { sys_error (r, 0, "ZLIB-compressed system file header has invalid " @@ -1202,33 +1228,35 @@ read_value_label_record (struct sfm_reader *r, return true; } -/* Reads a document record from R and returns it. */ -static struct sfm_document_record * +/* Reads a document record from R. Returns true if successful, false on + error. */ +static bool read_document_record (struct sfm_reader *r) { - struct sfm_document_record *record; int n_lines; - - record = pool_malloc (r->pool, sizeof *record); - record->pos = r->pos; - if (!read_int (r, &n_lines)) - return NULL; - if (n_lines <= 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH) + return false; + else if (n_lines == 0) + return true; + else if (n_lines < 0 || n_lines >= INT_MAX / DOC_LINE_LENGTH) { - sys_error (r, record->pos, + sys_error (r, r->pos, _("Number of document lines (%d) " "must be greater than 0 and less than %d."), n_lines, INT_MAX / DOC_LINE_LENGTH); - return NULL; + return false; } + struct sfm_document_record *record; + record = pool_malloc (r->pool, sizeof *record); + record->pos = r->pos; record->n_lines = n_lines; record->documents = pool_malloc (r->pool, DOC_LINE_LENGTH * n_lines); if (!read_bytes (r, record->documents, DOC_LINE_LENGTH * n_lines)) - return NULL; + return false; - return record; + r->document = record; + return true; } static bool @@ -1332,9 +1360,9 @@ read_extension_record (struct sfm_reader *r, int subtype, } sys_warn (r, record->pos, - _("Unrecognized record type 7, subtype %d. Please send a " - "copy of this file, and the syntax which created it to %s."), - subtype, PACKAGE_BUGREPORT); + _("Unrecognized record type 7, subtype %d. For help, please " + "send this file to %s and mention that you were using %s."), + subtype, PACKAGE_BUGREPORT, PACKAGE_STRING); skip: return skip_bytes (r, n_bytes); @@ -1351,7 +1379,7 @@ skip_extension_record (struct sfm_reader *r, int subtype) static void parse_header (struct sfm_reader *r, const struct sfm_header_record *header, - struct sfm_read_info *info, struct dictionary *dict) + struct any_read_info *info, struct dictionary *dict) { const char *dict_encoding = dict_get_encoding (dict); struct substring product; @@ -1477,14 +1505,8 @@ parse_variable_records (struct sfm_reader *r, struct dictionary *dict, } } else - { - union value value; - - value_init_pool (r->pool, &value, width); - value_set_missing (&value, width); - for (i = 0; i < rec->missing_value_code; i++) - mv_add_str (&mv, rec->missing + 8 * i, MIN (width, 8)); - } + for (i = 0; i < rec->missing_value_code; i++) + mv_add_str (&mv, rec->missing + 8 * i, MIN (width, 8)); var_set_missing_values (var, &mv); } @@ -1585,7 +1607,7 @@ parse_document (struct dictionary *dict, struct sfm_document_record *record) static bool parse_machine_integer_info (struct sfm_reader *r, const struct sfm_extension_record *record, - struct sfm_read_info *info) + struct any_read_info *info) { int float_representation, expected_float_format; int integer_representation, expected_integer_format; @@ -1667,7 +1689,7 @@ parse_machine_float_info (struct sfm_reader *r, static void parse_extra_product_info (struct sfm_reader *r, const struct sfm_extension_record *record, - struct sfm_read_info *info) + struct any_read_info *info) { struct text_record *text; @@ -2039,7 +2061,8 @@ parse_long_var_name_map (struct sfm_reader *r, while (read_variable_to_value_pair (r, dict, text, &var, &long_name)) { /* Validate long name. */ - if (!dict_id_is_valid (dict, long_name, false)) + if (!dict_id_is_valid (dict, long_name, false) + || long_name[0] == '$' || long_name[0] == '#') { sys_warn (r, record->pos, _("Long variable mapping from %s to invalid " @@ -2286,20 +2309,20 @@ parse_attributes (struct sfm_reader *r, struct text_record *text, text_warn (r, text, _("Error parsing attribute value %s[%d]."), key, index); break; - } + } length = strlen (value); - if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') + if (length >= 2 && value[0] == '\'' && value[length - 1] == '\'') { value[length - 1] = '\0'; - attribute_add_value (attr, value + 1); + attribute_add_value (attr, value + 1); } - else + else { text_warn (r, text, _("Attribute value %s[%d] is not quoted: %s."), key, index, value); - attribute_add_value (attr, value); + attribute_add_value (attr, value); } /* Was this the last value for this attribute? */ @@ -2408,15 +2431,15 @@ check_overflow (struct sfm_reader *r, size_t end = record->size * record->count; if (length >= end || ofs + length > end) { - sys_error (r, record->pos + end, - _("Extension record subtype %d ends unexpectedly."), - record->subtype); + sys_warn (r, record->pos + end, + _("Extension record subtype %d ends unexpectedly."), + record->subtype); return false; } return true; } -static bool +static void parse_long_string_value_labels (struct sfm_reader *r, const struct sfm_extension_record *record, struct dictionary *dict) @@ -2436,13 +2459,14 @@ parse_long_string_value_labels (struct sfm_reader *r, /* Parse variable name length. */ if (!check_overflow (r, record, ofs, 4)) - return false; + return; var_name_len = parse_int (r, record->data, ofs); ofs += 4; /* Parse variable name, width, and number of labels. */ - if (!check_overflow (r, record, ofs, var_name_len + 8)) - return false; + if (!check_overflow (r, record, ofs, var_name_len) + || !check_overflow (r, record, ofs, var_name_len + 8)) + return; var_name = recode_string_pool ("UTF-8", dict_encoding, (const char *) record->data + ofs, var_name_len, r->pool); @@ -2482,13 +2506,13 @@ parse_long_string_value_labels (struct sfm_reader *r, /* Parse value length. */ if (!check_overflow (r, record, ofs, 4)) - return false; + return; value_length = parse_int (r, record->data, ofs); ofs += 4; /* Parse value. */ if (!check_overflow (r, record, ofs, value_length)) - return false; + return; if (!skip) { if (value_length == width) @@ -2508,13 +2532,13 @@ parse_long_string_value_labels (struct sfm_reader *r, /* Parse label length. */ if (!check_overflow (r, record, ofs, 4)) - return false; + return; label_length = parse_int (r, record->data, ofs); ofs += 4; /* Parse label. */ if (!check_overflow (r, record, ofs, label_length)) - return false; + return; if (!skip) { char *label; @@ -2532,11 +2556,9 @@ parse_long_string_value_labels (struct sfm_reader *r, ofs += label_length; } } - - return true; } -static bool +static void parse_long_string_missing_values (struct sfm_reader *r, const struct sfm_extension_record *record, struct dictionary *dict) @@ -2556,13 +2578,14 @@ parse_long_string_missing_values (struct sfm_reader *r, /* Parse variable name length. */ if (!check_overflow (r, record, ofs, 4)) - return false; + return; var_name_len = parse_int (r, record->data, ofs); ofs += 4; /* Parse variable name. */ - if (!check_overflow (r, record, ofs, var_name_len + 1)) - return false; + if (!check_overflow (r, record, ofs, var_name_len) + || !check_overflow (r, record, ofs, var_name_len + 1)) + return; var_name = recode_string_pool ("UTF-8", dict_encoding, (const char *) record->data + ofs, var_name_len, r->pool); @@ -2600,13 +2623,13 @@ parse_long_string_missing_values (struct sfm_reader *r, /* Parse value length. */ if (!check_overflow (r, record, ofs, 4)) - return false; + return; value_length = parse_int (r, record->data, ofs); ofs += 4; /* Parse value. */ if (!check_overflow (r, record, ofs, value_length)) - return false; + return; if (var != NULL && i < 3 && !mv_add_str (&mv, (const uint8_t *) record->data + ofs, @@ -2621,8 +2644,6 @@ parse_long_string_missing_values (struct sfm_reader *r, if (var != NULL) var_set_missing_values (var, &mv); } - - return true; } /* Case reader. */ @@ -2649,7 +2670,7 @@ sys_file_casereader_read (struct casereader *reader, void *r_) int retval; int i; - if (r->error) + if (r->error || !r->sfm_var_cnt) return NULL; c = case_create (r->proto); @@ -2711,7 +2732,7 @@ read_error (struct casereader *r, const struct sfm_reader *sfm) static bool read_case_number (struct sfm_reader *r, double *d) { - if (r->compression == SFM_COMP_NONE) + if (r->compression == ANY_COMP_NONE) { uint8_t number[8]; if (!try_read_bytes (r, number, sizeof number)) @@ -2766,7 +2787,7 @@ read_case_string (struct sfm_reader *r, uint8_t *s, size_t length) static int read_opcode (struct sfm_reader *r) { - assert (r->compression != SFM_COMP_NONE); + assert (r->compression != ANY_COMP_NONE); for (;;) { int opcode; @@ -2878,7 +2899,7 @@ static int read_whole_strings (struct sfm_reader *r, uint8_t *s, size_t length) { assert (length % 8 == 0); - if (r->compression == SFM_COMP_NONE) + if (r->compression == ANY_COMP_NONE) return try_read_bytes (r, s, length); else { @@ -2977,7 +2998,7 @@ read_variable_to_value_pair (struct sfm_reader *r, struct dictionary *dict, { if (!text_read_short_name (r, dict, text, ss_cstr ("="), var)) return false; - + *value = text_get_token (text, ss_buffer ("\t\0", 2), NULL); if (*value == NULL) return false; @@ -3033,7 +3054,7 @@ static void text_warn (struct sfm_reader *r, struct text_record *text, const char *format, ...) { - if (text->n_warnings++ < MAX_TEXT_WARNINGS) + if (text->n_warnings++ < MAX_TEXT_WARNINGS) { va_list args; @@ -3122,7 +3143,10 @@ text_parse_counted_string (struct sfm_reader *r, struct text_record *text) static bool text_match (struct text_record *text, char c) { - if (text->buffer.string[text->pos] == c) + if (text->pos >= text->buffer.length) + return false; + + if (text->buffer.string[text->pos] == c) { text->pos++; return true; @@ -3186,9 +3210,8 @@ sys_warn (struct sfm_reader *r, off_t offset, const char *format, ...) va_end (args); } -/* Displays an error for the current file position, - marks it as in an error state, - and aborts reading it using longjmp. */ +/* Displays an error for the current file position and marks it as in an error + state. */ static void sys_error (struct sfm_reader *r, off_t offset, const char *format, ...) { @@ -3704,7 +3727,7 @@ read_bytes_zlib (struct sfm_reader *r, void *buf_, size_t byte_cnt) static int read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) { - if (r->compression == SFM_COMP_SIMPLE) + if (r->compression == ANY_COMP_SIMPLE) return read_bytes (r, buf, byte_cnt); else { @@ -3718,7 +3741,7 @@ read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) static int try_read_compressed_bytes (struct sfm_reader *r, void *buf, size_t byte_cnt) { - if (r->compression == SFM_COMP_SIMPLE) + if (r->compression == ANY_COMP_SIMPLE) return try_read_bytes (r, buf, byte_cnt); else return read_bytes_zlib (r, buf, byte_cnt); @@ -3745,3 +3768,13 @@ static const struct casereader_class sys_file_casereader_class = NULL, NULL, }; + +const struct any_reader_class sys_file_reader_class = + { + N_("SPSS System File"), + sfm_detect, + sfm_open, + sfm_close, + sfm_decode, + sfm_get_strings, + };