diff --git a/src/sas/readstat_sas.c b/src/sas/readstat_sas.c index 5dfd583..84ff085 100644 --- a/src/sas/readstat_sas.c +++ b/src/sas/readstat_sas.c @@ -26,6 +26,13 @@ unsigned char sas7bdat_magic_number[32] = { 0x09, 0xc7, 0x31, 0x8c, 0x18, 0x1f, 0x10, 0x11 }; +unsigned char sas7bdat_magic_number_alt[32] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x1f, 0x10, 0x11 +}; + unsigned char sas7bcat_magic_number[32] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0xea, 0x81, 0x63, @@ -171,6 +178,7 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo, goto cleanup; } if (memcmp(header_start.magic, sas7bdat_magic_number, sizeof(sas7bdat_magic_number)) != 0 && + memcmp(header_start.magic, sas7bdat_magic_number_alt, sizeof(sas7bdat_magic_number_alt)) != 0 && memcmp(header_start.magic, sas7bcat_magic_number, sizeof(sas7bcat_magic_number)) != 0) { retval = READSTAT_ERROR_PARSE; goto cleanup; @@ -309,9 +317,9 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo, retval = READSTAT_ERROR_READ; goto cleanup; } - char major, revision_tag; - int minor, revision; - if (sscanf(header_end.release, "%c.%04d%c%1d", &major, &minor, &revision_tag, &revision) != 4) { + char major, revision_tag, revision; + int minor; + if (sscanf(header_end.release, "%c.%04d%c%c", &major, &minor, &revision_tag, &revision) != 4) { retval = READSTAT_ERROR_PARSE; goto cleanup; } @@ -327,12 +335,21 @@ readstat_error_t sas_read_header(readstat_io_t *io, sas_header_info_t *hinfo, goto cleanup; } // revision_tag is usually M, but J has been observed in the wild (not created with SAS?) - if (revision_tag != 'M' && revision_tag != 'J') { + // files have also been observed with TK in place of the revision details. + if (revision_tag != 'M' && revision_tag != 'J' && revision_tag != 'T') { retval = READSTAT_ERROR_PARSE; goto cleanup; } hinfo->minor_version = minor; - hinfo->revision = revision; + if (revision >= '0' && revision <= '9') { + hinfo->revision = revision - '0'; + } else if (revision_tag == 'T' && revision == 'K') { + // files have been observed with TK in place of the revision details. + hinfo->revision = 0; + } else { + retval = READSTAT_ERROR_PARSE; + goto cleanup; + } if ((major == '8' || major == '9') && minor == 0 && revision == 0) { /* A bit of a hack, but most SAS installations are running a minor update */ diff --git a/src/sas/readstat_sas.h b/src/sas/readstat_sas.h index 6b80c2f..e9dc268 100644 --- a/src/sas/readstat_sas.h +++ b/src/sas/readstat_sas.h @@ -114,6 +114,7 @@ typedef struct sas_text_ref_s { #define SAS_DEFAULT_FILE_VERSION 9 extern unsigned char sas7bdat_magic_number[32]; +extern unsigned char sas7bdat_magic_number_alt[32]; extern unsigned char sas7bcat_magic_number[32]; uint64_t sas_read8(const char *data, int bswap);