fuzzer_parser_init:
   33|  3.27k|readstat_parser_t *fuzzer_parser_init(const uint8_t *Data, size_t Size) {
   34|  3.27k|    readstat_parser_t *parser = readstat_parser_init();
   35|  3.27k|    readstat_set_open_handler(parser, rt_open_handler);
   36|  3.27k|    readstat_set_close_handler(parser, rt_close_handler);
   37|  3.27k|    readstat_set_seek_handler(parser, rt_seek_handler);
   38|  3.27k|    readstat_set_read_handler(parser, rt_read_handler);
   39|  3.27k|    readstat_set_update_handler(parser, rt_update_handler);
   40|       |
   41|  3.27k|    readstat_set_metadata_handler(parser, &handle_metadata);
   42|  3.27k|    readstat_set_note_handler(parser, &handle_note);
   43|  3.27k|    readstat_set_variable_handler(parser, &handle_variable);
   44|  3.27k|    readstat_set_fweight_handler(parser, &handle_fweight);
   45|  3.27k|    readstat_set_value_handler(parser, &handle_value);
   46|  3.27k|    readstat_set_value_label_handler(parser, &handle_value_label);
   47|       |
   48|  3.27k|    return parser;
   49|  3.27k|}
fuzz_format.c:handle_metadata:
    8|  1.28k|static int handle_metadata(readstat_metadata_t *metadata, void *ctx) {
    9|  1.28k|    return READSTAT_HANDLER_OK;
   10|  1.28k|}
fuzz_format.c:handle_variable:
   21|  2.18k|                           const char *val_labels, void *ctx) {
   22|  2.18k|    return READSTAT_HANDLER_OK;
   23|  2.18k|}
fuzz_format.c:handle_value:
   25|  72.8k|static int handle_value(int obs_index, readstat_variable_t *variable, readstat_value_t value, void *ctx) {
   26|  72.8k|    return READSTAT_HANDLER_OK;
   27|  72.8k|}

LLVMFuzzerTestOneInput:
   10|  3.27k|int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   11|  3.27k|    rt_buffer_t buffer = { .bytes = (char *)Data, .size = Size, .used = Size };
   12|  3.27k|    rt_buffer_ctx_t buffer_ctx = { .buffer = &buffer };
   13|       |
   14|  3.27k|    readstat_parser_t *parser = fuzzer_parser_init(Data, Size);
   15|  3.27k|    readstat_set_io_ctx(parser, &buffer_ctx);
   16|       |
   17|  3.27k|    readstat_parse_sas7bdat(parser, NULL, NULL);
   18|  3.27k|    readstat_parser_free(parser);
   19|  3.27k|    return 0;
   20|  3.27k|}

machine_is_little_endian:
   11|  5.86k|int machine_is_little_endian(void) {
   12|  5.86k|    int test_byte_order = 1;
   13|  5.86k|    return ((char *)&test_byte_order)[0];
   14|  5.86k|}
byteswap2:
   40|   103k|uint16_t byteswap2(uint16_t num) {
   41|   103k|    return ((num & 0xFF00) >> 8) | ((num & 0x00FF) << 8);
   42|   103k|}
byteswap4:
   44|   195k|uint32_t byteswap4(uint32_t num) {
   45|   195k|    num = ((num & 0xFFFF0000) >> 16) | ((num & 0x0000FFFF) << 16);
   46|   195k|    return ((num & 0xFF00FF00) >> 8) | ((num & 0x00FF00FF) << 8);
   47|   195k|}
byteswap8:
   49|  73.9k|uint64_t byteswap8(uint64_t num) {
   50|  73.9k|    num = ((num & 0xFFFFFFFF00000000) >> 32) | ((num & 0x00000000FFFFFFFF) << 32);
   51|  73.9k|    num = ((num & 0xFFFF0000FFFF0000) >> 16) | ((num & 0x0000FFFF0000FFFF) << 16);
   52|  73.9k|    return ((num & 0xFF00FF00FF00FF00) >> 8) | ((num & 0x00FF00FF00FF00FF) << 8);
   53|  73.9k|}
byteswap_double:
   63|  4.98k|double byteswap_double(double num) {
   64|  4.98k|    uint64_t answer = 0;
   65|  4.98k|    memcpy(&answer, &num, 8);
   66|  4.98k|    answer = byteswap8(answer);
   67|  4.98k|    memcpy(&num, &answer, 8);
   68|  4.98k|    return num;
   69|  4.98k|}

readstat_convert:
    7|  27.7k|readstat_error_t readstat_convert(char *dst, size_t dst_len, const char *src, size_t src_len, iconv_t converter) {
    8|       |    /* strip off spaces from the input because the programs use ASCII space
    9|       |     * padding even with non-ASCII encoding. */
   10|  59.5k|    while (src_len && (src[src_len-1] == ' ' || src[src_len-1] == '\0')) {
  ------------------
  |  Branch (10:12): [True: 52.1k, False: 7.43k]
  |  Branch (10:24): [True: 2.98k, False: 49.1k]
  |  Branch (10:49): [True: 28.8k, False: 20.3k]
  ------------------
   11|  31.8k|        src_len--;
   12|  31.8k|    }
   13|  27.7k|    if (dst_len == 0) {
  ------------------
  |  Branch (13:9): [True: 0, False: 27.7k]
  ------------------
   14|      0|        return READSTAT_ERROR_CONVERT_LONG_STRING;
   15|  27.7k|    } else if (converter) {
  ------------------
  |  Branch (15:16): [True: 15.5k, False: 12.2k]
  ------------------
   16|  15.5k|        size_t dst_left = dst_len - 1;
   17|  15.5k|        char *dst_end = dst;
   18|  15.5k|        size_t status = iconv(converter, (readstat_iconv_inbuf_t)&src, &src_len, &dst_end, &dst_left);
   19|  15.5k|        if (status == (size_t)-1) {
  ------------------
  |  Branch (19:13): [True: 793, False: 14.7k]
  ------------------
   20|    793|            if (errno == E2BIG) {
  ------------------
  |  Branch (20:17): [True: 10, False: 783]
  ------------------
   21|     10|                return READSTAT_ERROR_CONVERT_LONG_STRING;
   22|    783|            } else if (errno == EILSEQ) {
  ------------------
  |  Branch (22:24): [True: 26, False: 757]
  ------------------
   23|     26|                return READSTAT_ERROR_CONVERT_BAD_STRING;
   24|    757|            } else if (errno != EINVAL) { /* EINVAL indicates improper truncation; accept it */
  ------------------
  |  Branch (24:24): [True: 0, False: 757]
  ------------------
   25|      0|                return READSTAT_ERROR_CONVERT;
   26|      0|            }
   27|    793|        }
   28|  15.5k|        dst[dst_len - dst_left - 1] = '\0';
   29|  15.5k|    } else if (src_len + 1 > dst_len) {
  ------------------
  |  Branch (29:16): [True: 20, False: 12.2k]
  ------------------
   30|     20|        return READSTAT_ERROR_CONVERT_LONG_STRING;
   31|  12.2k|    } else {
   32|  12.2k|        memcpy(dst, src, src_len);
   33|  12.2k|        dst[src_len] = '\0';
   34|  12.2k|    }
   35|  27.7k|    return READSTAT_OK;
   36|  27.7k|}

unistd_io_init:
  121|  3.27k|readstat_error_t unistd_io_init(readstat_parser_t *parser) {
  122|  3.27k|    readstat_error_t retval = READSTAT_OK;
  123|  3.27k|    unistd_io_ctx_t *io_ctx = NULL;
  124|       |
  125|  3.27k|    if ((retval = readstat_set_open_handler(parser, unistd_open_handler)) != READSTAT_OK)
  ------------------
  |  Branch (125:9): [True: 0, False: 3.27k]
  ------------------
  126|      0|        return retval;
  127|       |
  128|  3.27k|    if ((retval = readstat_set_close_handler(parser, unistd_close_handler)) != READSTAT_OK)
  ------------------
  |  Branch (128:9): [True: 0, False: 3.27k]
  ------------------
  129|      0|        return retval;
  130|       |
  131|  3.27k|    if ((retval = readstat_set_seek_handler(parser, unistd_seek_handler)) != READSTAT_OK)
  ------------------
  |  Branch (131:9): [True: 0, False: 3.27k]
  ------------------
  132|      0|        return retval;
  133|       |
  134|  3.27k|    if ((retval = readstat_set_read_handler(parser, unistd_read_handler)) != READSTAT_OK)
  ------------------
  |  Branch (134:9): [True: 0, False: 3.27k]
  ------------------
  135|      0|        return retval;
  136|       |
  137|  3.27k|    if ((readstat_set_update_handler(parser, unistd_update_handler)) != READSTAT_OK)
  ------------------
  |  Branch (137:9): [True: 0, False: 3.27k]
  ------------------
  138|      0|        return retval;
  139|       |
  140|  3.27k|    io_ctx = calloc(1, sizeof(unistd_io_ctx_t));
  141|  3.27k|    io_ctx->fd = -1;
  142|       |
  143|  3.27k|    retval = readstat_set_io_ctx(parser, (void*) io_ctx);
  144|  3.27k|    parser->io->io_ctx_needs_free = 1;
  145|       |
  146|  3.27k|    return retval;
  147|  3.27k|}

readstat_malloc:
   10|  5.27k|void *readstat_malloc(size_t len) {
   11|  5.27k|    if (len > MAX_MALLOC_SIZE || len == 0) {
  ------------------
  |  |    3|  10.5k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
  |  Branch (11:9): [True: 0, False: 5.27k]
  |  Branch (11:34): [True: 0, False: 5.27k]
  ------------------
   12|      0|        return NULL;
   13|      0|    }
   14|  5.27k|    return malloc(len);
   15|  5.27k|}
readstat_calloc:
   17|  2.87k|void *readstat_calloc(size_t count, size_t size) {
   18|  2.87k|    if (count > MAX_MALLOC_SIZE || size > MAX_MALLOC_SIZE || count * size > MAX_MALLOC_SIZE) {
  ------------------
  |  |    3|  5.75k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
                  if (count > MAX_MALLOC_SIZE || size > MAX_MALLOC_SIZE || count * size > MAX_MALLOC_SIZE) {
  ------------------
  |  |    3|  5.75k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
                  if (count > MAX_MALLOC_SIZE || size > MAX_MALLOC_SIZE || count * size > MAX_MALLOC_SIZE) {
  ------------------
  |  |    3|  2.87k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
  |  Branch (18:9): [True: 0, False: 2.87k]
  |  Branch (18:36): [True: 0, False: 2.87k]
  |  Branch (18:62): [True: 0, False: 2.87k]
  ------------------
   19|      0|        return NULL;
   20|      0|    }
   21|  2.87k|    if (count == 0 || size == 0) {
  ------------------
  |  Branch (21:9): [True: 0, False: 2.87k]
  |  Branch (21:23): [True: 0, False: 2.87k]
  ------------------
   22|      0|        return NULL;
   23|      0|    }
   24|  2.87k|    return calloc(count, size);
   25|  2.87k|}
readstat_realloc:
   27|   185k|void *readstat_realloc(void *ptr, size_t len) {
   28|   185k|    if (len > MAX_MALLOC_SIZE || len == 0) {
  ------------------
  |  |    3|   370k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
  |  Branch (28:9): [True: 92, False: 185k]
  |  Branch (28:34): [True: 2, False: 185k]
  ------------------
   29|     94|        if (ptr)
  ------------------
  |  Branch (29:13): [True: 62, False: 32]
  ------------------
   30|     62|            free(ptr);
   31|     94|        return NULL;
   32|     94|    }
   33|   185k|    return realloc(ptr, len);
   34|   185k|}

readstat_parser_init:
    6|  3.27k|readstat_parser_t *readstat_parser_init(void) {
    7|  3.27k|    readstat_parser_t *parser = calloc(1, sizeof(readstat_parser_t));
    8|  3.27k|    parser->io = calloc(1, sizeof(readstat_io_t));
    9|  3.27k|    if (unistd_io_init(parser) != READSTAT_OK) {
  ------------------
  |  Branch (9:9): [True: 0, False: 3.27k]
  ------------------
   10|      0|        readstat_parser_free(parser);
   11|      0|        return NULL;
   12|      0|    }
   13|  3.27k|    parser->output_encoding = "UTF-8";
   14|  3.27k|    return parser;
   15|  3.27k|}
readstat_parser_free:
   17|  3.27k|void readstat_parser_free(readstat_parser_t *parser) {
   18|  3.27k|    if (parser) {
  ------------------
  |  Branch (18:9): [True: 3.27k, False: 0]
  ------------------
   19|  3.27k|        if (parser->io) {
  ------------------
  |  Branch (19:13): [True: 3.27k, False: 0]
  ------------------
   20|  3.27k|            readstat_set_io_ctx(parser, NULL);
   21|  3.27k|            free(parser->io);
   22|  3.27k|        }
   23|  3.27k|        free(parser);
   24|  3.27k|    }
   25|  3.27k|}
readstat_set_metadata_handler:
   27|  3.27k|readstat_error_t readstat_set_metadata_handler(readstat_parser_t *parser, readstat_metadata_handler metadata_handler) {
   28|  3.27k|    parser->handlers.metadata = metadata_handler;
   29|  3.27k|    return READSTAT_OK;
   30|  3.27k|}
readstat_set_note_handler:
   32|  3.27k|readstat_error_t readstat_set_note_handler(readstat_parser_t *parser, readstat_note_handler note_handler) {
   33|  3.27k|    parser->handlers.note = note_handler;
   34|  3.27k|    return READSTAT_OK;
   35|  3.27k|}
readstat_set_variable_handler:
   37|  3.27k|readstat_error_t readstat_set_variable_handler(readstat_parser_t *parser, readstat_variable_handler variable_handler) {
   38|  3.27k|    parser->handlers.variable = variable_handler;
   39|  3.27k|    return READSTAT_OK;
   40|  3.27k|}
readstat_set_value_handler:
   42|  3.27k|readstat_error_t readstat_set_value_handler(readstat_parser_t *parser, readstat_value_handler value_handler) {
   43|  3.27k|    parser->handlers.value = value_handler;
   44|  3.27k|    return READSTAT_OK;
   45|  3.27k|}
readstat_set_value_label_handler:
   47|  3.27k|readstat_error_t readstat_set_value_label_handler(readstat_parser_t *parser, readstat_value_label_handler label_handler) {
   48|  3.27k|    parser->handlers.value_label = label_handler;
   49|  3.27k|    return READSTAT_OK;
   50|  3.27k|}
readstat_set_fweight_handler:
   62|  3.27k|readstat_error_t readstat_set_fweight_handler(readstat_parser_t *parser, readstat_fweight_handler fweight_handler) {
   63|  3.27k|    parser->handlers.fweight = fweight_handler;
   64|  3.27k|    return READSTAT_OK;
   65|  3.27k|}
readstat_set_open_handler:
   67|  6.54k|readstat_error_t readstat_set_open_handler(readstat_parser_t *parser, readstat_open_handler open_handler) {
   68|  6.54k|    parser->io->open = open_handler;
   69|  6.54k|    return READSTAT_OK;
   70|  6.54k|}
readstat_set_close_handler:
   72|  6.54k|readstat_error_t readstat_set_close_handler(readstat_parser_t *parser, readstat_close_handler close_handler) {
   73|  6.54k|    parser->io->close = close_handler;
   74|  6.54k|    return READSTAT_OK;
   75|  6.54k|}
readstat_set_seek_handler:
   77|  6.54k|readstat_error_t readstat_set_seek_handler(readstat_parser_t *parser, readstat_seek_handler seek_handler) {
   78|  6.54k|    parser->io->seek = seek_handler;
   79|  6.54k|    return READSTAT_OK;
   80|  6.54k|}
readstat_set_read_handler:
   82|  6.54k|readstat_error_t readstat_set_read_handler(readstat_parser_t *parser, readstat_read_handler read_handler) {
   83|  6.54k|    parser->io->read = read_handler;
   84|  6.54k|    return READSTAT_OK;
   85|  6.54k|}
readstat_set_update_handler:
   87|  6.54k|readstat_error_t readstat_set_update_handler(readstat_parser_t *parser, readstat_update_handler update_handler) {
   88|  6.54k|    parser->io->update = update_handler;
   89|  6.54k|    return READSTAT_OK;
   90|  6.54k|}
readstat_set_io_ctx:
   92|  9.81k|readstat_error_t readstat_set_io_ctx(readstat_parser_t *parser, void *io_ctx) {
   93|  9.81k|    if (parser->io->io_ctx_needs_free) {
  ------------------
  |  Branch (93:9): [True: 3.27k, False: 6.54k]
  ------------------
   94|  3.27k|        free(parser->io->io_ctx);
   95|  3.27k|    }
   96|       |
   97|  9.81k|    parser->io->io_ctx = io_ctx;
   98|  9.81k|    parser->io->io_ctx_needs_free = 0;
   99|       |
  100|  9.81k|    return READSTAT_OK;
  101|  9.81k|}

sas_read8:
  138|  73.6k|uint64_t sas_read8(const char *data, int bswap) {
  139|  73.6k|    uint64_t tmp;
  140|  73.6k|    memcpy(&tmp, data, 8);
  141|  73.6k|    return bswap ? byteswap8(tmp) : tmp;
  ------------------
  |  Branch (141:12): [True: 67.6k, False: 5.98k]
  ------------------
  142|  73.6k|}
sas_read4:
  144|   245k|uint32_t sas_read4(const char *data, int bswap) {
  145|   245k|    uint32_t tmp;
  146|   245k|    memcpy(&tmp, data, 4);
  147|   245k|    return bswap ? byteswap4(tmp) : tmp;
  ------------------
  |  Branch (147:12): [True: 189k, False: 55.2k]
  ------------------
  148|   245k|}
sas_read2:
  150|   163k|uint16_t sas_read2(const char *data, int bswap) {
  151|   163k|    uint16_t tmp;
  152|   163k|    memcpy(&tmp, data, 2);
  153|   163k|    return bswap ? byteswap2(tmp) : tmp;
  ------------------
  |  Branch (153:12): [True: 103k, False: 60.0k]
  ------------------
  154|   163k|}
sas_subheader_remainder:
  156|  7.15k|size_t sas_subheader_remainder(size_t len, size_t signature_len) {
  157|  7.15k|    return len - (4+2*signature_len);
  158|  7.15k|}
sas_read_header:
  161|  3.27k|        readstat_error_handler error_handler, void *user_ctx) {
  162|  3.27k|    sas_header_start_t  header_start;
  163|  3.27k|    sas_header_end_t    header_end;
  164|  3.27k|    int retval = READSTAT_OK;
  165|  3.27k|    char error_buf[1024];
  166|  3.27k|    time_t epoch = sas_epoch();
  167|       |
  168|  3.27k|    if (io->read(&header_start, sizeof(sas_header_start_t), io->io_ctx) < sizeof(sas_header_start_t)) {
  ------------------
  |  Branch (168:9): [True: 20, False: 3.25k]
  ------------------
  169|     20|        retval = READSTAT_ERROR_READ;
  170|     20|        goto cleanup;
  171|     20|    }
  172|  3.25k|    if (memcmp(header_start.magic, sas7bdat_magic_number, sizeof(sas7bdat_magic_number)) != 0 &&
  ------------------
  |  Branch (172:9): [True: 1.61k, False: 1.63k]
  ------------------
  173|  3.25k|            memcmp(header_start.magic, sas7bcat_magic_number, sizeof(sas7bcat_magic_number)) != 0) {
  ------------------
  |  Branch (173:13): [True: 131, False: 1.48k]
  ------------------
  174|    131|        retval = READSTAT_ERROR_PARSE;
  175|    131|        goto cleanup;
  176|    131|    }
  177|  3.12k|    if (header_start.a1 == SAS_ALIGNMENT_OFFSET_4) {
  ------------------
  |  |   74|  3.12k|#define SAS_ALIGNMENT_OFFSET_4  0x33
  ------------------
  |  Branch (177:9): [True: 11, False: 3.11k]
  ------------------
  178|     11|        hinfo->pad1 = 4;
  179|     11|    }
  180|  3.12k|    if (header_start.a2 == SAS_ALIGNMENT_OFFSET_4) {
  ------------------
  |  |   74|  3.12k|#define SAS_ALIGNMENT_OFFSET_4  0x33
  ------------------
  |  Branch (180:9): [True: 1.53k, False: 1.58k]
  ------------------
  181|  1.53k|        hinfo->u64 = 1;
  182|  1.53k|    }
  183|  3.12k|    int bswap = 0;
  184|  3.12k|    if (header_start.endian == SAS_ENDIAN_BIG) {
  ------------------
  |  |   67|  3.12k|#define SAS_ENDIAN_BIG       0x00
  ------------------
  |  Branch (184:9): [True: 2.51k, False: 603]
  ------------------
  185|  2.51k|        bswap = machine_is_little_endian();
  186|  2.51k|        hinfo->little_endian = 0;
  187|  2.51k|    } else if (header_start.endian == SAS_ENDIAN_LITTLE) {
  ------------------
  |  |   68|    603|#define SAS_ENDIAN_LITTLE    0x01
  ------------------
  |  Branch (187:16): [True: 588, False: 15]
  ------------------
  188|    588|        bswap = !machine_is_little_endian();
  189|    588|        hinfo->little_endian = 1;
  190|    588|    } else {
  191|     15|        retval = READSTAT_ERROR_PARSE;
  192|     15|        goto cleanup;
  193|     15|    }
  194|  3.10k|    int i;
  195|  28.4k|    for (i=0; i<sizeof(_charset_table)/sizeof(_charset_table[0]); i++) {
  ------------------
  |  Branch (195:15): [True: 28.4k, False: 9]
  ------------------
  196|  28.4k|        if (header_start.encoding == _charset_table[i].code) {
  ------------------
  |  Branch (196:13): [True: 3.09k, False: 25.3k]
  ------------------
  197|  3.09k|            hinfo->encoding = _charset_table[i].name;
  198|  3.09k|            break;
  199|  3.09k|        }
  200|  28.4k|    }
  201|  3.10k|    if (hinfo->encoding == NULL) {
  ------------------
  |  Branch (201:9): [True: 9, False: 3.09k]
  ------------------
  202|      9|        if (error_handler) {
  ------------------
  |  Branch (202:13): [True: 0, False: 9]
  ------------------
  203|      0|            snprintf(error_buf, sizeof(error_buf), "Unsupported character set code: %d", header_start.encoding);
  204|      0|            error_handler(error_buf, user_ctx);
  205|      0|        }
  206|      9|        retval = READSTAT_ERROR_UNSUPPORTED_CHARSET;
  207|      9|        goto cleanup;
  208|      9|    }
  209|  3.09k|    memcpy(hinfo->table_name, header_start.table_name, sizeof(header_start.table_name));
  210|  3.09k|    if (io->seek(hinfo->pad1, READSTAT_SEEK_CUR, io->io_ctx) == -1) {
  ------------------
  |  Branch (210:9): [True: 4, False: 3.09k]
  ------------------
  211|      4|        retval = READSTAT_ERROR_SEEK;
  212|      4|        goto cleanup;
  213|      4|    }
  214|       |
  215|  3.09k|    double creation_time, modification_time;
  216|       |
  217|  3.09k|    if (io->read(&creation_time, sizeof(double), io->io_ctx) < sizeof(double)) {
  ------------------
  |  Branch (217:9): [True: 13, False: 3.08k]
  ------------------
  218|     13|        retval = READSTAT_ERROR_READ;
  219|     13|        goto cleanup;
  220|     13|    }
  221|  3.08k|    if (bswap)
  ------------------
  |  Branch (221:9): [True: 2.49k, False: 584]
  ------------------
  222|  2.49k|        creation_time = byteswap_double(creation_time);
  223|       |
  224|  3.08k|    if (io->read(&modification_time, sizeof(double), io->io_ctx) < sizeof(double)) {
  ------------------
  |  Branch (224:9): [True: 6, False: 3.07k]
  ------------------
  225|      6|        retval = READSTAT_ERROR_READ;
  226|      6|        goto cleanup;
  227|      6|    }
  228|  3.07k|    if (bswap)
  ------------------
  |  Branch (228:9): [True: 2.49k, False: 581]
  ------------------
  229|  2.49k|        modification_time = byteswap_double(modification_time);
  230|       |
  231|  3.07k|    hinfo->creation_time = sas_convert_time(creation_time, epoch);
  232|  3.07k|    hinfo->modification_time = sas_convert_time(modification_time, epoch);
  233|       |
  234|  3.07k|    if (io->seek(16, READSTAT_SEEK_CUR, io->io_ctx) == -1) {
  ------------------
  |  Branch (234:9): [True: 8, False: 3.06k]
  ------------------
  235|      8|        retval = READSTAT_ERROR_SEEK;
  236|      8|        goto cleanup;
  237|      8|    }
  238|       |
  239|  3.06k|    uint32_t header_size, page_size;
  240|       |
  241|  3.06k|    if (io->read(&header_size, sizeof(uint32_t), io->io_ctx) < sizeof(uint32_t)) {
  ------------------
  |  Branch (241:9): [True: 3, False: 3.06k]
  ------------------
  242|      3|        retval = READSTAT_ERROR_READ;
  243|      3|        goto cleanup;
  244|      3|    }
  245|  3.06k|    if (io->read(&page_size, sizeof(uint32_t), io->io_ctx) < sizeof(uint32_t)) {
  ------------------
  |  Branch (245:9): [True: 3, False: 3.06k]
  ------------------
  246|      3|        retval = READSTAT_ERROR_READ;
  247|      3|        goto cleanup;
  248|      3|    }
  249|       |
  250|  3.06k|    hinfo->header_size = bswap ? byteswap4(header_size) : header_size;
  ------------------
  |  Branch (250:26): [True: 2.48k, False: 580]
  ------------------
  251|  3.06k|    hinfo->page_size = bswap ? byteswap4(page_size) : page_size;
  ------------------
  |  Branch (251:24): [True: 2.48k, False: 580]
  ------------------
  252|       |
  253|  3.06k|    if (hinfo->header_size < 1024 || hinfo->page_size < 1024) {
  ------------------
  |  Branch (253:9): [True: 12, False: 3.04k]
  |  Branch (253:38): [True: 11, False: 3.03k]
  ------------------
  254|     23|        retval = READSTAT_ERROR_PARSE;
  255|     23|        goto cleanup;
  256|     23|    }
  257|  3.03k|    if (hinfo->header_size > (1<<24) || hinfo->page_size > (1<<24)) {
  ------------------
  |  Branch (257:9): [True: 21, False: 3.01k]
  |  Branch (257:41): [True: 28, False: 2.98k]
  ------------------
  258|     49|        retval = READSTAT_ERROR_PARSE;
  259|     49|        goto cleanup;
  260|     49|    }
  261|       |
  262|  2.98k|    if (hinfo->u64) {
  ------------------
  |  Branch (262:9): [True: 1.49k, False: 1.49k]
  ------------------
  263|  1.49k|        hinfo->page_header_size = SAS_PAGE_HEADER_SIZE_64BIT;
  ------------------
  |  |  105|  1.49k|#define SAS_PAGE_HEADER_SIZE_64BIT  40
  ------------------
  264|  1.49k|        hinfo->subheader_pointer_size = SAS_SUBHEADER_POINTER_SIZE_64BIT;
  ------------------
  |  |  102|  1.49k|#define SAS_SUBHEADER_POINTER_SIZE_64BIT    24
  ------------------
  265|  1.49k|    } else {
  266|  1.49k|        hinfo->page_header_size = SAS_PAGE_HEADER_SIZE_32BIT;
  ------------------
  |  |  104|  1.49k|#define SAS_PAGE_HEADER_SIZE_32BIT  24
  ------------------
  267|  1.49k|        hinfo->subheader_pointer_size = SAS_SUBHEADER_POINTER_SIZE_32BIT;
  ------------------
  |  |  101|  1.49k|#define SAS_SUBHEADER_POINTER_SIZE_32BIT    12
  ------------------
  268|  1.49k|    }
  269|       |
  270|  2.98k|    if (hinfo->u64) {
  ------------------
  |  Branch (270:9): [True: 1.49k, False: 1.49k]
  ------------------
  271|  1.49k|        uint64_t page_count;
  272|  1.49k|        if (io->read(&page_count, sizeof(uint64_t), io->io_ctx) < sizeof(uint64_t)) {
  ------------------
  |  Branch (272:13): [True: 18, False: 1.47k]
  ------------------
  273|     18|            retval = READSTAT_ERROR_READ;
  274|     18|            goto cleanup;
  275|     18|        }
  276|  1.47k|        hinfo->page_count = bswap ? byteswap8(page_count) : page_count;
  ------------------
  |  Branch (276:29): [True: 1.34k, False: 124]
  ------------------
  277|  1.49k|    } else {
  278|  1.49k|        uint32_t page_count;
  279|  1.49k|        if (io->read(&page_count, sizeof(uint32_t), io->io_ctx) < sizeof(uint32_t)) {
  ------------------
  |  Branch (279:13): [True: 22, False: 1.47k]
  ------------------
  280|     22|            retval = READSTAT_ERROR_READ;
  281|     22|            goto cleanup;
  282|     22|        }
  283|  1.47k|        hinfo->page_count = bswap ? byteswap4(page_count) : page_count;
  ------------------
  |  Branch (283:29): [True: 1.03k, False: 444]
  ------------------
  284|  1.47k|    }
  285|  2.94k|    if (hinfo->page_count > (1<<24)) {
  ------------------
  |  Branch (285:9): [True: 9, False: 2.93k]
  ------------------
  286|      9|        retval = READSTAT_ERROR_PARSE;
  287|      9|        goto cleanup;
  288|      9|    }
  289|       |    
  290|  2.93k|    if (io->seek(8, READSTAT_SEEK_CUR, io->io_ctx) == -1) {
  ------------------
  |  Branch (290:9): [True: 85, False: 2.85k]
  ------------------
  291|     85|        retval = READSTAT_ERROR_SEEK;
  292|     85|        if (error_handler) {
  ------------------
  |  Branch (292:13): [True: 0, False: 85]
  ------------------
  293|      0|            snprintf(error_buf, sizeof(error_buf), "ReadStat: Failed to seek forward by %d", 8);
  294|      0|            error_handler(error_buf, user_ctx);
  295|      0|        }
  296|     85|        goto cleanup;
  297|     85|    }
  298|  2.85k|    if (io->read(&header_end, sizeof(sas_header_end_t), io->io_ctx) < sizeof(sas_header_end_t)) {
  ------------------
  |  Branch (298:9): [True: 16, False: 2.83k]
  ------------------
  299|     16|        retval = READSTAT_ERROR_READ;
  300|     16|        goto cleanup;
  301|     16|    }
  302|  2.83k|    char major;
  303|  2.83k|    int minor, revision;
  304|  2.83k|    if (sscanf(header_end.release, "%c.%04dM%1d", &major, &minor, &revision) != 3) {
  ------------------
  |  Branch (304:9): [True: 3, False: 2.83k]
  ------------------
  305|      3|        retval = READSTAT_ERROR_PARSE;
  306|      3|        goto cleanup;
  307|      3|    }
  308|       |
  309|  2.83k|    if (major >= '1' && major <= '9') {
  ------------------
  |  Branch (309:9): [True: 2.82k, False: 12]
  |  Branch (309:25): [True: 2.81k, False: 10]
  ------------------
  310|  2.81k|        hinfo->major_version = major - '0';
  311|  2.81k|    } else if (major == 'V') {
  ------------------
  |  Branch (311:16): [True: 3, False: 19]
  ------------------
  312|       |        // It appears that SAS Visual Forecaster reports the major version as "V"
  313|       |        // Treat it as version 9 for all intents and purposes
  314|      3|        hinfo->major_version = 9;
  315|     19|    } else {
  316|     19|        retval = READSTAT_ERROR_PARSE;
  317|     19|        goto cleanup;
  318|     19|    }
  319|  2.81k|    hinfo->minor_version = minor;
  320|  2.81k|    hinfo->revision = revision;
  321|       |
  322|  2.81k|    if ((major == '8' || major == '9') && minor == 0 && revision == 0) {
  ------------------
  |  Branch (322:10): [True: 586, False: 2.23k]
  |  Branch (322:26): [True: 153, False: 2.07k]
  |  Branch (322:43): [True: 330, False: 409]
  |  Branch (322:57): [True: 247, False: 83]
  ------------------
  323|       |        /* A bit of a hack, but most SAS installations are running a minor update */
  324|    247|        hinfo->vendor = READSTAT_VENDOR_STAT_TRANSFER;
  325|  2.56k|    } else {
  326|  2.56k|        hinfo->vendor = READSTAT_VENDOR_SAS;
  327|  2.56k|    }
  328|  2.81k|    if (io->seek(hinfo->header_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (328:9): [True: 54, False: 2.76k]
  ------------------
  329|     54|        retval = READSTAT_ERROR_SEEK;
  330|     54|        if (error_handler) {
  ------------------
  |  Branch (330:13): [True: 0, False: 54]
  ------------------
  331|      0|            snprintf(error_buf, sizeof(error_buf), 
  332|      0|                    "ReadStat: Failed to seek to position %" PRId64, hinfo->header_size);
  333|      0|            error_handler(error_buf, user_ctx);
  334|      0|        }
  335|     54|        goto cleanup;
  336|     54|    }
  337|       |
  338|  3.27k|cleanup:
  339|  3.27k|    return retval;
  340|  2.81k|}
sas_validate_tag:
  492|  4.81k|readstat_error_t sas_validate_tag(char tag) {
  493|  4.81k|    if (tag == '_' || (tag >= 'A' && tag <= 'Z'))
  ------------------
  |  Branch (493:9): [True: 2.09k, False: 2.72k]
  |  Branch (493:24): [True: 1.07k, False: 1.64k]
  |  Branch (493:38): [True: 794, False: 285]
  ------------------
  494|  2.88k|        return READSTAT_OK;
  495|       |
  496|  1.92k|    return READSTAT_ERROR_TAGGED_VALUE_IS_OUT_OF_RANGE;
  497|  4.81k|}
sas_assign_tag:
  499|  4.81k|void sas_assign_tag(readstat_value_t *value, uint8_t tag) {
  500|       |    /* We accommodate two tag schemes. In the first, the tag is an ASCII code
  501|       |     * given by uint8_t tag above. System missing is represented by an ASCII
  502|       |     * period. In the second scheme, (tag-2) is an offset from 'A', except when
  503|       |     * tag == 0, in which case it represents an underscore, or tag == 1, in
  504|       |     * which case it represents system-missing.
  505|       |     */
  506|  4.81k|    if (tag == 0) {
  ------------------
  |  Branch (506:9): [True: 2.09k, False: 2.72k]
  ------------------
  507|  2.09k|        tag = '_';
  508|  2.72k|    } else if (tag >= 2 && tag < 28) {
  ------------------
  |  Branch (508:16): [True: 2.36k, False: 354]
  |  Branch (508:28): [True: 740, False: 1.62k]
  ------------------
  509|    740|        tag = 'A' + (tag - 2);
  510|    740|    }
  511|  4.81k|    if (sas_validate_tag(tag) == READSTAT_OK) {
  ------------------
  |  Branch (511:9): [True: 2.88k, False: 1.92k]
  ------------------
  512|  2.88k|        value->tag = tag;
  513|  2.88k|        value->is_tagged_missing = 1;
  514|  2.88k|    } else {
  515|  1.92k|        value->tag = 0;
  516|  1.92k|        value->is_system_missing = 1;
  517|  1.92k|    }
  518|  4.81k|}
readstat_sas.c:sas_epoch:
  123|  3.27k|static time_t sas_epoch(void) {
  124|  3.27k|    return - 3653 * 86400; // seconds between 01-01-1960 and 01-01-1970
  125|  3.27k|}
readstat_sas.c:sas_convert_time:
  127|  6.14k|static time_t sas_convert_time(double time, time_t epoch) {
  128|  6.14k|    time += epoch;
  129|  6.14k|    if (isnan(time))
  130|    812|        return 0;
  131|  5.33k|    if (time > (double)LONG_MAX)
  ------------------
  |  Branch (131:9): [True: 1.08k, False: 4.25k]
  ------------------
  132|  1.08k|        return LONG_MAX;
  133|  4.25k|    if (time < (double)LONG_MIN)
  ------------------
  |  Branch (133:9): [True: 1.27k, False: 2.98k]
  ------------------
  134|  1.27k|        return LONG_MIN;
  135|  2.98k|    return time;
  136|  4.25k|}

readstat_parse_sas7bdat:
 1166|  3.27k|readstat_error_t readstat_parse_sas7bdat(readstat_parser_t *parser, const char *path, void *user_ctx) {
 1167|  3.27k|    int64_t last_examined_page_pass1 = 0;
 1168|  3.27k|    readstat_error_t retval = READSTAT_OK;
 1169|  3.27k|    readstat_io_t *io = parser->io;
 1170|       |
 1171|  3.27k|    sas7bdat_ctx_t  *ctx = calloc(1, sizeof(sas7bdat_ctx_t));
 1172|  3.27k|    sas_header_info_t  *hinfo = calloc(1, sizeof(sas_header_info_t));
 1173|       |
 1174|  3.27k|    ctx->handle = parser->handlers;
 1175|  3.27k|    ctx->input_encoding = parser->input_encoding;
 1176|  3.27k|    ctx->output_encoding = parser->output_encoding;
 1177|  3.27k|    ctx->user_ctx = user_ctx;
 1178|  3.27k|    ctx->io = parser->io;
 1179|  3.27k|    ctx->row_limit = parser->row_limit;
 1180|  3.27k|    if (parser->row_offset > 0)
  ------------------
  |  Branch (1180:9): [True: 0, False: 3.27k]
  ------------------
 1181|      0|        ctx->row_offset = parser->row_offset;
 1182|       |
 1183|  3.27k|    if (io->open(path, io->io_ctx) == -1) {
  ------------------
  |  Branch (1183:9): [True: 0, False: 3.27k]
  ------------------
 1184|      0|        retval = READSTAT_ERROR_OPEN;
 1185|      0|        goto cleanup;
 1186|      0|    }
 1187|       |
 1188|  3.27k|    if ((ctx->file_size = io->seek(0, READSTAT_SEEK_END, io->io_ctx)) == -1) {
  ------------------
  |  Branch (1188:9): [True: 0, False: 3.27k]
  ------------------
 1189|      0|        retval = READSTAT_ERROR_SEEK;
 1190|      0|        if (ctx->handle.error) {
  ------------------
  |  Branch (1190:13): [True: 0, False: 0]
  ------------------
 1191|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to end of file");
 1192|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1193|      0|        }
 1194|      0|        goto cleanup;
 1195|      0|    }
 1196|       |
 1197|  3.27k|    if (io->seek(0, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1197:9): [True: 0, False: 3.27k]
  ------------------
 1198|      0|        retval = READSTAT_ERROR_SEEK;
 1199|      0|        if (ctx->handle.error) {
  ------------------
  |  Branch (1199:13): [True: 0, False: 0]
  ------------------
 1200|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to beginning of file");
 1201|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1202|      0|        }
 1203|      0|        goto cleanup;
 1204|      0|    }
 1205|       |
 1206|  3.27k|    if ((retval = sas_read_header(io, hinfo, ctx->handle.error, user_ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1206:9): [True: 510, False: 2.76k]
  ------------------
 1207|    510|        goto cleanup;
 1208|    510|    }
 1209|       |
 1210|  2.76k|    ctx->u64 = hinfo->u64;
 1211|  2.76k|    ctx->little_endian = hinfo->little_endian;
 1212|  2.76k|    ctx->vendor = hinfo->vendor;
 1213|  2.76k|    ctx->bswap = machine_is_little_endian() ^ hinfo->little_endian;
 1214|  2.76k|    ctx->header_size = hinfo->header_size;
 1215|  2.76k|    ctx->page_count = hinfo->page_count;
 1216|  2.76k|    ctx->page_size = hinfo->page_size;
 1217|  2.76k|    ctx->page_header_size = hinfo->page_header_size;
 1218|  2.76k|    ctx->subheader_pointer_size = hinfo->subheader_pointer_size;
 1219|  2.76k|    ctx->subheader_signature_size = ctx->u64 ? 8 : 4;
  ------------------
  |  Branch (1219:37): [True: 1.41k, False: 1.35k]
  ------------------
 1220|  2.76k|    ctx->ctime = hinfo->creation_time;
 1221|  2.76k|    ctx->mtime = hinfo->modification_time;
 1222|  2.76k|    ctx->version = hinfo->major_version;
 1223|  2.76k|    if (ctx->input_encoding == NULL) {
  ------------------
  |  Branch (1223:9): [True: 2.76k, False: 0]
  ------------------
 1224|  2.76k|        ctx->input_encoding = hinfo->encoding;
 1225|  2.76k|    }
 1226|  2.76k|    if ((ctx->page = readstat_malloc(ctx->page_size)) == NULL) {
  ------------------
  |  Branch (1226:9): [True: 0, False: 2.76k]
  ------------------
 1227|      0|        retval = READSTAT_ERROR_MALLOC;
 1228|      0|        goto cleanup;
 1229|      0|    }
 1230|       |
 1231|  2.76k|    if (ctx->input_encoding && ctx->output_encoding && strcmp(ctx->input_encoding, ctx->output_encoding) != 0) {
  ------------------
  |  Branch (1231:9): [True: 2.76k, False: 0]
  |  Branch (1231:32): [True: 2.76k, False: 0]
  |  Branch (1231:56): [True: 2.03k, False: 728]
  ------------------
 1232|  2.03k|        iconv_t converter = iconv_open(ctx->output_encoding, ctx->input_encoding);
 1233|  2.03k|        if (converter == (iconv_t)-1) {
  ------------------
  |  Branch (1233:13): [True: 1, False: 2.03k]
  ------------------
 1234|      1|            retval = READSTAT_ERROR_UNSUPPORTED_CHARSET;
 1235|      1|            goto cleanup;
 1236|      1|        }
 1237|  2.03k|        ctx->converter = converter;
 1238|  2.03k|    }
 1239|       |
 1240|  2.76k|    if ((retval = readstat_convert(ctx->table_name, sizeof(ctx->table_name),
  ------------------
  |  Branch (1240:9): [True: 3, False: 2.75k]
  ------------------
 1241|  2.76k|                hinfo->table_name, sizeof(hinfo->table_name), ctx->converter)) != READSTAT_OK) {
 1242|      3|        goto cleanup;
 1243|      3|    }
 1244|       |
 1245|  2.75k|    if ((retval = sas7bdat_parse_meta_pages_pass1(ctx, &last_examined_page_pass1)) != READSTAT_OK) {
  ------------------
  |  Branch (1245:9): [True: 220, False: 2.53k]
  ------------------
 1246|    220|        goto cleanup;
 1247|    220|    }
 1248|       |
 1249|  2.53k|    if ((retval = sas7bdat_parse_amd_pages_pass1(last_examined_page_pass1, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1249:9): [True: 624, False: 1.91k]
  ------------------
 1250|    624|        goto cleanup;
 1251|    624|    }
 1252|       |
 1253|  1.91k|    if (io->seek(ctx->header_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1253:9): [True: 0, False: 1.91k]
  ------------------
 1254|      0|        retval = READSTAT_ERROR_SEEK;
 1255|      0|        if (ctx->handle.error) {
  ------------------
  |  Branch (1255:13): [True: 0, False: 0]
  ------------------
 1256|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to position %" PRId64, 
 1257|      0|                    ctx->header_size);
 1258|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1259|      0|        }
 1260|      0|        goto cleanup;
 1261|      0|    }
 1262|       |
 1263|  1.91k|    if ((retval = sas7bdat_parse_all_pages_pass2(ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1263:9): [True: 1.59k, False: 324]
  ------------------
 1264|  1.59k|        goto cleanup;
 1265|  1.59k|    }
 1266|       |    
 1267|    324|    if ((retval = sas7bdat_submit_columns_if_needed(ctx, 0)) != READSTAT_OK) {
  ------------------
  |  Branch (1267:9): [True: 88, False: 236]
  ------------------
 1268|     88|        goto cleanup;
 1269|     88|    }
 1270|       |
 1271|    236|    if (ctx->handle.value && ctx->parsed_row_count != ctx->row_limit) {
  ------------------
  |  Branch (1271:9): [True: 236, False: 0]
  |  Branch (1271:30): [True: 118, False: 118]
  ------------------
 1272|    118|        retval = READSTAT_ERROR_ROW_COUNT_MISMATCH;
 1273|    118|        if (ctx->handle.error) {
  ------------------
  |  Branch (1273:13): [True: 0, False: 118]
  ------------------
 1274|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Expected %d rows in file, found %d",
 1275|      0|                    ctx->row_limit, ctx->parsed_row_count);
 1276|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1277|      0|        }
 1278|    118|        goto cleanup;
 1279|    118|    }
 1280|       |
 1281|    118|    if ((retval = sas7bdat_update_progress(ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1281:9): [True: 0, False: 118]
  ------------------
 1282|      0|        goto cleanup;
 1283|      0|    }
 1284|       |
 1285|  3.27k|cleanup:
 1286|  3.27k|    io->close(io->io_ctx);
 1287|       |
 1288|  3.27k|    if (retval == READSTAT_ERROR_OPEN ||
  ------------------
  |  Branch (1288:9): [True: 0, False: 3.27k]
  ------------------
 1289|  3.27k|            retval == READSTAT_ERROR_READ ||
  ------------------
  |  Branch (1289:13): [True: 384, False: 2.88k]
  ------------------
 1290|  3.27k|            retval == READSTAT_ERROR_SEEK) {
  ------------------
  |  Branch (1290:13): [True: 403, False: 2.48k]
  ------------------
 1291|    787|        if (ctx->handle.error) {
  ------------------
  |  Branch (1291:13): [True: 0, False: 787]
  ------------------
 1292|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: %s (retval = %d): %s (errno = %d)", 
 1293|      0|                    readstat_error_message(retval), retval, strerror(errno), errno);
 1294|      0|            ctx->handle.error(ctx->error_buf, user_ctx);
 1295|      0|        }
 1296|    787|    }
 1297|       |
 1298|  3.27k|    if (ctx)
  ------------------
  |  Branch (1298:9): [True: 3.27k, False: 0]
  ------------------
 1299|  3.27k|        sas7bdat_ctx_free(ctx);
 1300|  3.27k|    if (hinfo)
  ------------------
  |  Branch (1300:9): [True: 3.27k, False: 0]
  ------------------
 1301|  3.27k|        free(hinfo);
 1302|       |
 1303|  3.27k|    return retval;
 1304|    118|}
readstat_sas7bdat_read.c:sas7bdat_parse_meta_pages_pass1:
 1007|  2.75k|static readstat_error_t sas7bdat_parse_meta_pages_pass1(sas7bdat_ctx_t *ctx, int64_t *outLastExaminedPage) {
 1008|  2.75k|    readstat_error_t retval = READSTAT_OK;
 1009|  2.75k|    readstat_io_t *io = ctx->io;
 1010|  2.75k|    int64_t i;
 1011|       |
 1012|       |    /* look for META and MIX pages at beginning... */
 1013|  7.87k|    for (i=0; i<ctx->page_count; i++) {
  ------------------
  |  Branch (1013:15): [True: 5.85k, False: 2.01k]
  ------------------
 1014|  5.85k|        if (io->seek(ctx->header_size + i*ctx->page_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1014:13): [True: 8, False: 5.85k]
  ------------------
 1015|      8|            retval = READSTAT_ERROR_SEEK;
 1016|      8|            if (ctx->handle.error) {
  ------------------
  |  Branch (1016:17): [True: 0, False: 8]
  ------------------
 1017|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to position %" PRId64 
 1018|      0|                        " (= %" PRId64 " + %" PRId64 "*%" PRId64 ")",
 1019|      0|                        ctx->header_size + i*ctx->page_size, ctx->header_size, i, ctx->page_size);
 1020|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1021|      0|            }
 1022|      8|            goto cleanup;
 1023|      8|        }
 1024|       |
 1025|  5.85k|        readstat_off_t off = 0;
 1026|  5.85k|        if (ctx->u64)
  ------------------
  |  Branch (1026:13): [True: 4.00k, False: 1.84k]
  ------------------
 1027|  4.00k|            off = 16;
 1028|       |
 1029|  5.85k|        size_t head_len = off + 16 + 2;
 1030|  5.85k|        size_t tail_len = ctx->page_size - head_len;
 1031|       |
 1032|  5.85k|        if (io->read(ctx->page, head_len, io->io_ctx) < head_len) {
  ------------------
  |  Branch (1032:13): [True: 143, False: 5.70k]
  ------------------
 1033|    143|            retval = READSTAT_ERROR_READ;
 1034|    143|            goto cleanup;
 1035|    143|        }
 1036|       |
 1037|  5.70k|        uint16_t page_type = sas_read2(&ctx->page[off+16], ctx->bswap);
 1038|       |
 1039|  5.70k|        if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA)
  ------------------
  |  |   96|  5.70k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                      if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA)
  ------------------
  |  |   93|  5.70k|#define SAS_PAGE_TYPE_DATA   0x0100
  ------------------
  |  Branch (1039:13): [True: 523, False: 5.18k]
  ------------------
 1040|    523|            break;
 1041|  5.18k|        if ((page_type & SAS_PAGE_TYPE_COMP))
  ------------------
  |  |   99|  5.18k|#define SAS_PAGE_TYPE_COMP   0x9000
  ------------------
  |  Branch (1041:13): [True: 1.08k, False: 4.09k]
  ------------------
 1042|  1.08k|            continue;
 1043|       |
 1044|  4.09k|        if (io->read(ctx->page + head_len, tail_len, io->io_ctx) < tail_len) {
  ------------------
  |  Branch (1044:13): [True: 24, False: 4.07k]
  ------------------
 1045|     24|            retval = READSTAT_ERROR_READ;
 1046|     24|            goto cleanup;
 1047|     24|        }
 1048|       |
 1049|  4.07k|        if ((retval = sas7bdat_parse_page_pass1(ctx->page, ctx->page_size, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1049:13): [True: 45, False: 4.02k]
  ------------------
 1050|     45|            if (ctx->handle.error && retval != READSTAT_ERROR_USER_ABORT) {
  ------------------
  |  Branch (1050:17): [True: 0, False: 45]
  |  Branch (1050:38): [True: 0, False: 0]
  ------------------
 1051|      0|                int64_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
 1052|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
 1053|      0|                        "ReadStat: Error parsing page %" PRId64 ", bytes %" PRId64 "-%" PRId64, 
 1054|      0|                        i, pos - ctx->page_size, pos-1);
 1055|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1056|      0|            }
 1057|     45|            goto cleanup;
 1058|     45|        }
 1059|  4.07k|    }
 1060|       |
 1061|  2.75k|cleanup:
 1062|  2.75k|    if (outLastExaminedPage)
  ------------------
  |  Branch (1062:9): [True: 2.75k, False: 0]
  ------------------
 1063|  2.75k|        *outLastExaminedPage = i;
 1064|       |
 1065|  2.75k|    return retval;
 1066|  2.75k|}
readstat_sas7bdat_read.c:sas7bdat_parse_page_pass1:
  854|  7.08k|static readstat_error_t sas7bdat_parse_page_pass1(const char *page, size_t page_size, sas7bdat_ctx_t *ctx) {
  855|  7.08k|    readstat_error_t retval = READSTAT_OK;
  856|       |
  857|  7.08k|    uint16_t subheader_count = sas_read2(&page[ctx->page_header_size-4], ctx->bswap);
  858|       |
  859|  7.08k|    int i;
  860|  7.08k|    const char *shp = &page[ctx->page_header_size];
  861|  7.08k|    int lshp = ctx->subheader_pointer_size;
  862|       |
  863|  7.08k|    if (ctx->page_header_size + subheader_count*lshp > page_size) {
  ------------------
  |  Branch (863:9): [True: 37, False: 7.05k]
  ------------------
  864|     37|        retval = READSTAT_ERROR_PARSE;
  865|     37|        goto cleanup;
  866|     37|    }
  867|       |
  868|  71.3k|    for (i=0; i<subheader_count; i++) {
  ------------------
  |  Branch (868:15): [True: 64.6k, False: 6.67k]
  ------------------
  869|  64.6k|        subheader_pointer_t shp_info = { 0 };
  870|  64.6k|        uint32_t signature = 0;
  871|  64.6k|        size_t signature_len = ctx->subheader_signature_size;
  872|  64.6k|        if ((retval = sas7bdat_parse_subheader_pointer(shp, page + page_size - shp, &shp_info, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (872:13): [True: 0, False: 64.6k]
  ------------------
  873|      0|            goto cleanup;
  874|      0|        }
  875|  64.6k|        if (shp_info.len > 0 && shp_info.compression != SAS_COMPRESSION_TRUNC) {
  ------------------
  |  |  108|  40.0k|#define SAS_COMPRESSION_TRUNC  0x01
  ------------------
  |  Branch (875:13): [True: 40.0k, False: 24.5k]
  |  Branch (875:33): [True: 32.4k, False: 7.66k]
  ------------------
  876|  32.4k|            if ((retval = sas7bdat_validate_subheader_pointer(&shp_info, page_size, subheader_count, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (876:17): [True: 311, False: 32.1k]
  ------------------
  877|    311|                goto cleanup;
  878|    311|            }
  879|  32.1k|            if (shp_info.compression == SAS_COMPRESSION_NONE) {
  ------------------
  |  |  107|  32.1k|#define SAS_COMPRESSION_NONE   0x00
  ------------------
  |  Branch (879:17): [True: 29.4k, False: 2.69k]
  ------------------
  880|  29.4k|                signature = sas_read4(page + shp_info.offset, ctx->bswap);
  881|  29.4k|                if (!ctx->little_endian && signature == -1 && signature_len == 8) {
  ------------------
  |  Branch (881:21): [True: 23.4k, False: 5.93k]
  |  Branch (881:44): [True: 2.77k, False: 20.7k]
  |  Branch (881:63): [True: 1.59k, False: 1.18k]
  ------------------
  882|  1.59k|                    signature = sas_read4(page + shp_info.offset + 4, ctx->bswap);
  883|  1.59k|                }
  884|  29.4k|                if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT) {
  ------------------
  |  |   88|  29.4k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT    0xFFFFFFFD
  ------------------
  |  Branch (884:21): [True: 2.57k, False: 26.8k]
  ------------------
  885|  2.57k|                    if ((retval = sas7bdat_parse_subheader(signature, page + shp_info.offset, shp_info.len, ctx))
  ------------------
  |  Branch (885:25): [True: 56, False: 2.51k]
  ------------------
  886|  2.57k|                            != READSTAT_OK) {
  887|     56|                        goto cleanup;
  888|     56|                    }
  889|  2.57k|                }
  890|  29.4k|            } else if (shp_info.compression == SAS_COMPRESSION_ROW) {
  ------------------
  |  |  109|  2.69k|#define SAS_COMPRESSION_ROW    0x04
  ------------------
  |  Branch (890:24): [True: 2.68k, False: 11]
  ------------------
  891|       |                /* void */
  892|  2.68k|            } else {
  893|     11|                retval = READSTAT_ERROR_UNSUPPORTED_COMPRESSION;
  894|     11|                goto cleanup;
  895|     11|            }
  896|  32.1k|        }
  897|       |
  898|  64.2k|        shp += lshp;
  899|  64.2k|    }
  900|       |
  901|  7.08k|cleanup:
  902|       |
  903|  7.08k|    return retval;
  904|  7.05k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_pointer:
  808|   107k|        subheader_pointer_t *info, sas7bdat_ctx_t *ctx) {
  809|   107k|    readstat_error_t retval = READSTAT_OK;
  810|   107k|    if (ctx->u64) {
  ------------------
  |  Branch (810:9): [True: 27.5k, False: 80.4k]
  ------------------
  811|  27.5k|        if (shp_size <= 17) {
  ------------------
  |  Branch (811:13): [True: 0, False: 27.5k]
  ------------------
  812|      0|            retval = READSTAT_ERROR_PARSE;
  813|      0|            goto cleanup;
  814|      0|        }
  815|  27.5k|        info->offset = sas_read8(&shp[0], ctx->bswap);
  816|  27.5k|        info->len = sas_read8(&shp[8], ctx->bswap);
  817|  27.5k|        info->compression = shp[16];
  818|  27.5k|        info->is_compressed_data = shp[17];
  819|  80.4k|    } else {
  820|  80.4k|        if (shp_size <= 9) {
  ------------------
  |  Branch (820:13): [True: 0, False: 80.4k]
  ------------------
  821|      0|            retval = READSTAT_ERROR_PARSE;
  822|      0|            goto cleanup;
  823|      0|        }
  824|  80.4k|        info->offset = sas_read4(&shp[0], ctx->bswap);
  825|  80.4k|        info->len = sas_read4(&shp[4], ctx->bswap);
  826|  80.4k|        info->compression = shp[8];
  827|  80.4k|        info->is_compressed_data = shp[9];
  828|  80.4k|    }
  829|   107k|cleanup:
  830|   107k|    return retval;
  831|   107k|}
readstat_sas7bdat_read.c:sas7bdat_validate_subheader_pointer:
  834|  56.5k|        uint16_t subheader_count, sas7bdat_ctx_t *ctx) {
  835|  56.5k|    if (shp_info->offset > page_size)
  ------------------
  |  Branch (835:9): [True: 233, False: 56.3k]
  ------------------
  836|    233|        return READSTAT_ERROR_PARSE;
  837|  56.3k|    if (shp_info->len > page_size)
  ------------------
  |  Branch (837:9): [True: 218, False: 56.1k]
  ------------------
  838|    218|        return READSTAT_ERROR_PARSE;
  839|  56.1k|    if (shp_info->offset + shp_info->len > page_size)
  ------------------
  |  Branch (839:9): [True: 32, False: 56.0k]
  ------------------
  840|     32|        return READSTAT_ERROR_PARSE;
  841|  56.0k|    if (shp_info->offset < ctx->page_header_size + subheader_count*ctx->subheader_pointer_size)
  ------------------
  |  Branch (841:9): [True: 9, False: 56.0k]
  ------------------
  842|      9|        return READSTAT_ERROR_PARSE;
  843|  56.0k|    if (shp_info->compression == SAS_COMPRESSION_NONE) {
  ------------------
  |  |  107|  56.0k|#define SAS_COMPRESSION_NONE   0x00
  ------------------
  |  Branch (843:9): [True: 52.2k, False: 3.86k]
  ------------------
  844|  52.2k|        if (shp_info->len < ctx->subheader_signature_size)
  ------------------
  |  Branch (844:13): [True: 4, False: 52.2k]
  ------------------
  845|      4|            return READSTAT_ERROR_PARSE;
  846|  52.2k|        if (shp_info->offset + ctx->subheader_signature_size > page_size)
  ------------------
  |  Branch (846:13): [True: 0, False: 52.2k]
  ------------------
  847|      0|            return READSTAT_ERROR_PARSE;
  848|  52.2k|    }
  849|       |    
  850|  56.0k|    return READSTAT_OK;
  851|  56.0k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader:
  626|  22.3k|static readstat_error_t sas7bdat_parse_subheader(uint32_t signature, const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  627|  22.3k|    readstat_error_t retval = READSTAT_OK;
  628|       |
  629|  22.3k|    if (len < 2 + ctx->subheader_signature_size) {
  ------------------
  |  Branch (629:9): [True: 14, False: 22.3k]
  ------------------
  630|     14|        retval = READSTAT_ERROR_PARSE;
  631|     14|        goto cleanup;
  632|     14|    }
  633|  22.3k|    if (signature == SAS_SUBHEADER_SIGNATURE_ROW_SIZE) {
  ------------------
  |  |   79|  22.3k|#define SAS_SUBHEADER_SIGNATURE_ROW_SIZE       0xF7F7F7F7
  ------------------
  |  Branch (633:9): [True: 7.78k, False: 14.5k]
  ------------------
  634|  7.78k|        retval = sas7bdat_parse_row_size_subheader(subheader, len, ctx);
  635|  14.5k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE) {
  ------------------
  |  |   80|  14.5k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE    0xF6F6F6F6
  ------------------
  |  Branch (635:16): [True: 1.16k, False: 13.4k]
  ------------------
  636|  1.16k|        retval = sas7bdat_parse_column_size_subheader(subheader, len, ctx);
  637|  13.4k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COUNTS) {
  ------------------
  |  |   81|  13.4k|#define SAS_SUBHEADER_SIGNATURE_COUNTS         0xFFFFFC00
  ------------------
  |  Branch (637:16): [True: 955, False: 12.4k]
  ------------------
  638|       |        /* void */
  639|  12.4k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT) {
  ------------------
  |  |   88|  12.4k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT    0xFFFFFFFD
  ------------------
  |  Branch (639:16): [True: 2.56k, False: 9.88k]
  ------------------
  640|  2.56k|        retval = sas7bdat_parse_column_text_subheader(subheader, len, ctx);
  641|  9.88k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_NAME) {
  ------------------
  |  |   90|  9.88k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_NAME    0xFFFFFFFF
  ------------------
  |  Branch (641:16): [True: 1.27k, False: 8.61k]
  ------------------
  642|  1.27k|        retval = sas7bdat_parse_column_name_subheader(subheader, len, ctx);
  643|  8.61k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_ATTRS) {
  ------------------
  |  |   87|  8.61k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_ATTRS   0xFFFFFFFC
  ------------------
  |  Branch (643:16): [True: 3.30k, False: 5.30k]
  ------------------
  644|  3.30k|        retval = sas7bdat_parse_column_attributes_subheader(subheader, len, ctx);
  645|  5.30k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_FORMAT) {
  ------------------
  |  |   82|  5.30k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_FORMAT  0xFFFFFBFE
  ------------------
  |  Branch (645:16): [True: 3.83k, False: 1.47k]
  ------------------
  646|  3.83k|        retval = sas7bdat_parse_column_format_subheader(subheader, len, ctx);
  647|  3.83k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_LIST) {
  ------------------
  |  |   89|  1.47k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_LIST    0xFFFFFFFE
  ------------------
  |  Branch (647:16): [True: 836, False: 636]
  ------------------
  648|       |        /* void */
  649|    836|    } else if ((signature & SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) == SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) {
  ------------------
  |  |   84|    636|#define SAS_SUBHEADER_SIGNATURE_COLUMN_MASK    0xFFFFFFF8
  ------------------
                  } else if ((signature & SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) == SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) {
  ------------------
  |  |   84|    636|#define SAS_SUBHEADER_SIGNATURE_COLUMN_MASK    0xFFFFFFF8
  ------------------
  |  Branch (649:16): [True: 468, False: 168]
  ------------------
  650|       |        /* void */
  651|    468|    } else {
  652|    168|        retval = READSTAT_ERROR_PARSE;
  653|    168|    }
  654|       |
  655|  22.3k|cleanup:
  656|       |
  657|  22.3k|    return retval;
  658|  22.3k|}
readstat_sas7bdat_read.c:sas7bdat_parse_row_size_subheader:
  231|  7.78k|static readstat_error_t sas7bdat_parse_row_size_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  232|  7.78k|    readstat_error_t retval = READSTAT_OK;
  233|  7.78k|    uint64_t total_row_count;
  234|  7.78k|    uint64_t row_length, page_row_count;
  235|       |
  236|  7.78k|    if (len < (ctx->u64 ? 250: 190)) {
  ------------------
  |  Branch (236:9): [True: 16, False: 7.77k]
  |  Branch (236:16): [True: 5.67k, False: 2.11k]
  ------------------
  237|     16|        retval = READSTAT_ERROR_PARSE;
  238|     16|        goto cleanup;
  239|     16|    }
  240|       |
  241|  7.77k|    if (ctx->u64) {
  ------------------
  |  Branch (241:9): [True: 5.66k, False: 2.10k]
  ------------------
  242|  5.66k|        row_length = sas_read8(&subheader[40], ctx->bswap);
  243|  5.66k|        total_row_count = sas_read8(&subheader[48], ctx->bswap);
  244|  5.66k|        page_row_count = sas_read8(&subheader[120], ctx->bswap);
  245|  5.66k|    } else {
  246|  2.10k|        row_length = sas_read4(&subheader[20], ctx->bswap);
  247|  2.10k|        total_row_count = sas_read4(&subheader[24], ctx->bswap);
  248|  2.10k|        page_row_count = sas_read4(&subheader[60], ctx->bswap);
  249|  2.10k|    }
  250|       |
  251|  7.77k|    sas_text_ref_t file_label_ref = sas7bdat_parse_text_ref(&subheader[len-130], ctx);
  252|  7.77k|    if (file_label_ref.length) {
  ------------------
  |  Branch (252:9): [True: 964, False: 6.80k]
  ------------------
  253|    964|        if ((retval = sas7bdat_copy_text_ref(ctx->file_label, sizeof(ctx->file_label),
  ------------------
  |  Branch (253:13): [True: 36, False: 928]
  ------------------
  254|    964|                        file_label_ref, ctx)) != READSTAT_OK) {
  255|     36|            goto cleanup;
  256|     36|        }
  257|    964|    }
  258|       |
  259|  7.73k|    sas_text_ref_t compression_ref = sas7bdat_parse_text_ref(&subheader[len-118], ctx);
  260|  7.73k|    if (compression_ref.length) {
  ------------------
  |  Branch (260:9): [True: 901, False: 6.83k]
  ------------------
  261|    901|        char compression[9];
  262|    901|        if ((retval = sas7bdat_copy_text_ref(compression, sizeof(compression),
  ------------------
  |  Branch (262:13): [True: 53, False: 848]
  ------------------
  263|    901|                        compression_ref, ctx)) != READSTAT_OK) {
  264|     53|            goto cleanup;
  265|     53|        }
  266|    848|        ctx->rdc_compression = (memcmp(compression, SAS_COMPRESSION_SIGNATURE_RDC, 8) == 0);
  ------------------
  |  |  112|    848|#define SAS_COMPRESSION_SIGNATURE_RDC  "SASYZCR2"
  ------------------
  267|    848|    }
  268|       |
  269|  7.68k|    ctx->row_length = row_length;
  270|  7.68k|    ctx->row = readstat_realloc(ctx->row, ctx->row_length);
  271|  7.68k|    if (ctx->row == NULL) {
  ------------------
  |  Branch (271:9): [True: 9, False: 7.67k]
  ------------------
  272|      9|        retval = READSTAT_ERROR_MALLOC;
  273|      9|        goto cleanup;
  274|      9|    }
  275|       |
  276|  7.67k|    ctx->page_row_count = page_row_count;
  277|  7.67k|    uint64_t total_row_count_after_skipping = total_row_count;
  278|  7.67k|    if (total_row_count > ctx->row_offset) {
  ------------------
  |  Branch (278:9): [True: 5.41k, False: 2.25k]
  ------------------
  279|  5.41k|        total_row_count_after_skipping -= ctx->row_offset;
  280|  5.41k|    } else {
  281|  2.25k|        total_row_count_after_skipping = 0;
  282|  2.25k|        ctx->row_offset = total_row_count;
  283|  2.25k|    }
  284|  7.67k|    if (ctx->row_limit == 0 || total_row_count_after_skipping < ctx->row_limit)
  ------------------
  |  Branch (284:9): [True: 3.55k, False: 4.11k]
  |  Branch (284:32): [True: 862, False: 3.25k]
  ------------------
  285|  4.42k|        ctx->row_limit = total_row_count_after_skipping;
  286|       |
  287|  7.78k|cleanup:
  288|  7.78k|    return retval;
  289|  7.67k|}
readstat_sas7bdat_read.c:sas7bdat_parse_text_ref:
  132|  43.2k|static sas_text_ref_t sas7bdat_parse_text_ref(const char *data, sas7bdat_ctx_t *ctx) {
  133|  43.2k|    sas_text_ref_t  ref;
  134|       |
  135|  43.2k|    ref.index = sas_read2(&data[0], ctx->bswap);
  136|  43.2k|    ref.offset = sas_read2(&data[2], ctx->bswap);
  137|  43.2k|    ref.length = sas_read2(&data[4], ctx->bswap);
  138|       |
  139|  43.2k|    return ref;
  140|  43.2k|}
readstat_sas7bdat_read.c:sas7bdat_copy_text_ref:
  142|  8.71k|static readstat_error_t sas7bdat_copy_text_ref(char *out_buffer, size_t out_buffer_len, sas_text_ref_t text_ref, sas7bdat_ctx_t *ctx) {
  143|  8.71k|    if (text_ref.index >= ctx->text_blob_count)
  ------------------
  |  Branch (143:9): [True: 120, False: 8.59k]
  ------------------
  144|    120|        return READSTAT_ERROR_PARSE;
  145|       |    
  146|  8.59k|    if (text_ref.length == 0) {
  ------------------
  |  Branch (146:9): [True: 5.56k, False: 3.03k]
  ------------------
  147|  5.56k|        out_buffer[0] = '\0';
  148|  5.56k|        return READSTAT_OK;
  149|  5.56k|    }
  150|       |
  151|  3.03k|    char *blob = ctx->text_blobs[text_ref.index];
  152|       |
  153|  3.03k|    if (text_ref.offset + text_ref.length > ctx->text_blob_lengths[text_ref.index])
  ------------------
  |  Branch (153:9): [True: 81, False: 2.95k]
  ------------------
  154|     81|        return READSTAT_ERROR_PARSE;
  155|       |
  156|  2.95k|    return readstat_convert(out_buffer, out_buffer_len, &blob[text_ref.offset], text_ref.length,
  157|  2.95k|            ctx->converter);
  158|  3.03k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_size_subheader:
  203|  1.16k|static readstat_error_t sas7bdat_parse_column_size_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  204|  1.16k|    uint64_t col_count;
  205|  1.16k|    readstat_error_t retval = READSTAT_OK;
  206|       |
  207|  1.16k|    if (ctx->column_count || ctx->did_submit_columns) {
  ------------------
  |  Branch (207:9): [True: 20, False: 1.14k]
  |  Branch (207:30): [True: 4, False: 1.14k]
  ------------------
  208|     24|        retval = READSTAT_ERROR_PARSE;
  209|     24|        goto cleanup;
  210|     24|    }
  211|       |
  212|  1.14k|    if (len < (ctx->u64 ? 16 : 8)) {
  ------------------
  |  Branch (212:9): [True: 1, False: 1.14k]
  |  Branch (212:16): [True: 288, False: 853]
  ------------------
  213|      1|        retval = READSTAT_ERROR_PARSE;
  214|      1|        goto cleanup;
  215|      1|    }
  216|       |
  217|  1.14k|    if (ctx->u64) {
  ------------------
  |  Branch (217:9): [True: 287, False: 853]
  ------------------
  218|    287|        col_count = sas_read8(&subheader[8], ctx->bswap);
  219|    853|    } else {
  220|    853|        col_count = sas_read4(&subheader[4], ctx->bswap);
  221|    853|    }
  222|       |
  223|  1.14k|    ctx->column_count = col_count;
  224|       |
  225|  1.14k|    retval = sas7bdat_realloc_col_info(ctx, ctx->column_count);
  226|       |
  227|  1.16k|cleanup:
  228|  1.16k|    return retval;
  229|  1.14k|}
readstat_sas7bdat_read.c:sas7bdat_realloc_col_info:
  190|  9.43k|static readstat_error_t sas7bdat_realloc_col_info(sas7bdat_ctx_t *ctx, size_t count) {
  191|  9.43k|    if (ctx->col_info_count < count) {
  ------------------
  |  Branch (191:9): [True: 4.47k, False: 4.95k]
  ------------------
  192|  4.47k|        size_t old_count = ctx->col_info_count;
  193|  4.47k|        ctx->col_info_count = count;
  194|  4.47k|        ctx->col_info = readstat_realloc(ctx->col_info, ctx->col_info_count * sizeof(col_info_t));
  195|  4.47k|        if (ctx->col_info == NULL) {
  ------------------
  |  Branch (195:13): [True: 82, False: 4.39k]
  ------------------
  196|     82|            return READSTAT_ERROR_MALLOC;
  197|     82|        }
  198|  4.39k|        memset(ctx->col_info + old_count, 0, (count - old_count) * sizeof(col_info_t));
  199|  4.39k|    }
  200|  9.35k|    return READSTAT_OK;
  201|  9.43k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_text_subheader:
  160|  2.56k|static readstat_error_t sas7bdat_parse_column_text_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  161|  2.56k|    readstat_error_t retval = READSTAT_OK;
  162|  2.56k|    size_t signature_len = ctx->subheader_signature_size;
  163|  2.56k|    uint16_t remainder = sas_read2(&subheader[signature_len], ctx->bswap);
  164|  2.56k|    char *blob = NULL;
  165|  2.56k|    if (remainder != sas_subheader_remainder(len, signature_len)) {
  ------------------
  |  Branch (165:9): [True: 54, False: 2.51k]
  ------------------
  166|     54|        retval = READSTAT_ERROR_PARSE;
  167|     54|        goto cleanup;
  168|     54|    }
  169|  2.51k|    ctx->text_blob_count++;
  170|  2.51k|    ctx->text_blobs = readstat_realloc(ctx->text_blobs, ctx->text_blob_count * sizeof(char *));
  171|  2.51k|    ctx->text_blob_lengths = readstat_realloc(ctx->text_blob_lengths,
  172|  2.51k|            ctx->text_blob_count * sizeof(ctx->text_blob_lengths[0]));
  173|  2.51k|    if (ctx->text_blobs == NULL || ctx->text_blob_lengths == NULL) {
  ------------------
  |  Branch (173:9): [True: 0, False: 2.51k]
  |  Branch (173:36): [True: 0, False: 2.51k]
  ------------------
  174|      0|        retval = READSTAT_ERROR_MALLOC;
  175|      0|        goto cleanup;
  176|      0|    }
  177|       |
  178|  2.51k|    if ((blob = readstat_malloc(len-signature_len)) == NULL) {
  ------------------
  |  Branch (178:9): [True: 0, False: 2.51k]
  ------------------
  179|      0|        retval = READSTAT_ERROR_MALLOC;
  180|      0|        goto cleanup;
  181|      0|    }
  182|  2.51k|    memcpy(blob, subheader+signature_len, len-signature_len);
  183|  2.51k|    ctx->text_blob_lengths[ctx->text_blob_count-1] = len-signature_len;
  184|  2.51k|    ctx->text_blobs[ctx->text_blob_count-1] = blob;
  185|       |
  186|  2.56k|cleanup:
  187|  2.56k|    return retval;
  188|  2.51k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_name_subheader:
  291|  1.27k|static readstat_error_t sas7bdat_parse_column_name_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  292|  1.27k|    readstat_error_t retval = READSTAT_OK;
  293|  1.27k|    size_t signature_len = ctx->subheader_signature_size;
  294|  1.27k|    int cmax = ctx->u64 ? (len-28)/8 : (len-20)/8;
  ------------------
  |  Branch (294:16): [True: 146, False: 1.12k]
  ------------------
  295|  1.27k|    int i;
  296|  1.27k|    const char *cnp = &subheader[signature_len+8];
  297|  1.27k|    uint16_t remainder = sas_read2(&subheader[signature_len], ctx->bswap);
  298|       |
  299|  1.27k|    if (remainder != sas_subheader_remainder(len, signature_len)) {
  ------------------
  |  Branch (299:9): [True: 58, False: 1.21k]
  ------------------
  300|     58|        retval = READSTAT_ERROR_PARSE;
  301|     58|        goto cleanup;
  302|     58|    }
  303|       |
  304|  1.21k|    ctx->col_names_count += cmax;
  305|       |
  306|  1.21k|    if ((retval = sas7bdat_realloc_col_info(ctx, ctx->col_names_count)) != READSTAT_OK)
  ------------------
  |  Branch (306:9): [True: 17, False: 1.20k]
  ------------------
  307|     17|        goto cleanup;
  308|       |
  309|  21.3k|    for (i=ctx->col_names_count-cmax; i<ctx->col_names_count; i++) {
  ------------------
  |  Branch (309:39): [True: 20.1k, False: 1.20k]
  ------------------
  310|  20.1k|        ctx->col_info[i].name_ref = sas7bdat_parse_text_ref(cnp, ctx);
  311|  20.1k|        cnp += 8;
  312|  20.1k|    }
  313|       |
  314|  1.27k|cleanup:
  315|       |
  316|  1.27k|    return retval;
  317|  1.20k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_attributes_subheader:
  319|  3.30k|static readstat_error_t sas7bdat_parse_column_attributes_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  320|  3.30k|    readstat_error_t retval = READSTAT_OK;
  321|  3.30k|    size_t signature_len = ctx->subheader_signature_size;
  322|  3.30k|    int cmax = ctx->u64 ? (len-28)/16 : (len-20)/12;
  ------------------
  |  Branch (322:16): [True: 632, False: 2.67k]
  ------------------
  323|  3.30k|    int i;
  324|  3.30k|    const char *cap = &subheader[signature_len+8];
  325|  3.30k|    uint16_t remainder = sas_read2(&subheader[signature_len], ctx->bswap);
  326|       |
  327|  3.30k|    if (remainder != sas_subheader_remainder(len, signature_len)) {
  ------------------
  |  Branch (327:9): [True: 55, False: 3.25k]
  ------------------
  328|     55|        retval = READSTAT_ERROR_PARSE;
  329|     55|        goto cleanup;
  330|     55|    }
  331|  3.25k|    ctx->col_attrs_count += cmax;
  332|  3.25k|    if ((retval = sas7bdat_realloc_col_info(ctx, ctx->col_attrs_count)) != READSTAT_OK)
  ------------------
  |  Branch (332:9): [True: 14, False: 3.23k]
  ------------------
  333|     14|        goto cleanup;
  334|       |
  335|  14.9k|    for (i=ctx->col_attrs_count-cmax; i<ctx->col_attrs_count; i++) {
  ------------------
  |  Branch (335:39): [True: 11.7k, False: 3.22k]
  ------------------
  336|  11.7k|        if (ctx->u64) {
  ------------------
  |  Branch (336:13): [True: 1.27k, False: 10.4k]
  ------------------
  337|  1.27k|            ctx->col_info[i].offset = sas_read8(&cap[0], ctx->bswap);
  338|  10.4k|        } else {
  339|  10.4k|            ctx->col_info[i].offset = sas_read4(&cap[0], ctx->bswap);
  340|  10.4k|        }
  341|       |
  342|  11.7k|        readstat_off_t off=4;
  343|  11.7k|        if (ctx->u64)
  ------------------
  |  Branch (343:13): [True: 1.27k, False: 10.4k]
  ------------------
  344|  1.27k|            off=8;
  345|       |
  346|  11.7k|        ctx->col_info[i].width = sas_read4(&cap[off], ctx->bswap);
  347|  11.7k|        if (ctx->col_info[i].width > ctx->max_col_width)
  ------------------
  |  Branch (347:13): [True: 1.35k, False: 10.4k]
  ------------------
  348|  1.35k|            ctx->max_col_width = ctx->col_info[i].width;
  349|       |
  350|  11.7k|        if (cap[off+6] == SAS_COLUMN_TYPE_NUM) {
  ------------------
  |  |   76|  11.7k|#define SAS_COLUMN_TYPE_NUM  0x01
  ------------------
  |  Branch (350:13): [True: 5.98k, False: 5.78k]
  ------------------
  351|  5.98k|            ctx->col_info[i].type = READSTAT_TYPE_DOUBLE;
  352|  5.98k|        } else if (cap[off+6] == SAS_COLUMN_TYPE_CHR) {
  ------------------
  |  |   77|  5.78k|#define SAS_COLUMN_TYPE_CHR  0x02
  ------------------
  |  Branch (352:20): [True: 5.76k, False: 18]
  ------------------
  353|  5.76k|            ctx->col_info[i].type = READSTAT_TYPE_STRING;
  354|  5.76k|        } else {
  355|     18|            retval = READSTAT_ERROR_PARSE;
  356|     18|            goto cleanup;
  357|     18|        }
  358|  11.7k|        ctx->col_info[i].index = i;
  359|  11.7k|        cap += off+8;
  360|  11.7k|    }
  361|       |
  362|  3.30k|cleanup:
  363|       |
  364|  3.30k|    return retval;
  365|  3.23k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_format_subheader:
  367|  3.83k|static readstat_error_t sas7bdat_parse_column_format_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  368|  3.83k|    readstat_error_t retval = READSTAT_OK;
  369|       |
  370|  3.83k|    if (len < (ctx->u64 ? 58 : 46)) {
  ------------------
  |  Branch (370:9): [True: 8, False: 3.82k]
  |  Branch (370:16): [True: 640, False: 3.19k]
  ------------------
  371|      8|        retval = READSTAT_ERROR_PARSE;
  372|      8|        goto cleanup;
  373|      8|    }
  374|       |
  375|  3.82k|    ctx->col_formats_count++;
  376|  3.82k|    if ((retval = sas7bdat_realloc_col_info(ctx, ctx->col_formats_count)) != READSTAT_OK)
  ------------------
  |  Branch (376:9): [True: 0, False: 3.82k]
  ------------------
  377|      0|        goto cleanup;
  378|       |
  379|  3.82k|    if (ctx->u64)
  ------------------
  |  Branch (379:9): [True: 639, False: 3.18k]
  ------------------
  380|    639|        ctx->col_info[ctx->col_formats_count-1].format_len = sas_read2(&subheader[24], ctx->bswap);
  381|  3.82k|    ctx->col_info[ctx->col_formats_count-1].format_ref = sas7bdat_parse_text_ref(
  382|  3.82k|            ctx->u64 ? &subheader[46] : &subheader[34], ctx);
  ------------------
  |  Branch (382:13): [True: 639, False: 3.18k]
  ------------------
  383|  3.82k|    ctx->col_info[ctx->col_formats_count-1].label_ref = sas7bdat_parse_text_ref(
  384|  3.82k|            ctx->u64 ? &subheader[52] : &subheader[40], ctx);
  ------------------
  |  Branch (384:13): [True: 639, False: 3.18k]
  ------------------
  385|       |
  386|  3.83k|cleanup:
  387|  3.83k|    return retval;
  388|  3.82k|}
readstat_sas7bdat_read.c:sas7bdat_parse_amd_pages_pass1:
 1068|  2.53k|static readstat_error_t sas7bdat_parse_amd_pages_pass1(int64_t last_examined_page_pass1, sas7bdat_ctx_t *ctx) {
 1069|  2.53k|    readstat_error_t retval = READSTAT_OK;
 1070|  2.53k|    readstat_io_t *io = ctx->io;
 1071|  2.53k|    uint64_t i;
 1072|  2.53k|    uint64_t amd_page_count = 0;
 1073|       |
 1074|       |    /* ...then AMD pages at the end */
 1075|  6.57k|    for (i=ctx->page_count-1; i>last_examined_page_pass1; i--) {
  ------------------
  |  Branch (1075:31): [True: 4.97k, False: 1.59k]
  ------------------
 1076|  4.97k|        if (io->seek(ctx->header_size + i*ctx->page_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1076:13): [True: 244, False: 4.73k]
  ------------------
 1077|    244|            retval = READSTAT_ERROR_SEEK;
 1078|    244|            if (ctx->handle.error) {
  ------------------
  |  Branch (1078:17): [True: 0, False: 244]
  ------------------
 1079|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to position %" PRId64 
 1080|      0|                        " (= %" PRId64 " + %" PRId64 "*%" PRId64 ")",
 1081|      0|                        ctx->header_size + i*ctx->page_size, ctx->header_size, i, ctx->page_size);
 1082|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1083|      0|            }
 1084|    244|            goto cleanup;
 1085|    244|        }
 1086|       |
 1087|  4.73k|        readstat_off_t off = 0;
 1088|  4.73k|        if (ctx->u64)
  ------------------
  |  Branch (1088:13): [True: 4.19k, False: 536]
  ------------------
 1089|  4.19k|            off = 16;
 1090|       |
 1091|  4.73k|        size_t head_len = off + 16 + 2;
 1092|  4.73k|        size_t tail_len = ctx->page_size - head_len;
 1093|       |
 1094|  4.73k|        if (io->read(ctx->page, head_len, io->io_ctx) < head_len) {
  ------------------
  |  Branch (1094:13): [True: 9, False: 4.72k]
  ------------------
 1095|      9|            retval = READSTAT_ERROR_READ;
 1096|      9|            goto cleanup;
 1097|      9|        }
 1098|       |
 1099|  4.72k|        uint16_t page_type = sas_read2(&ctx->page[off+16], ctx->bswap);
 1100|       |
 1101|  4.72k|        if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |   96|  4.72k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                      if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |   93|  4.72k|#define SAS_PAGE_TYPE_DATA   0x0100
  ------------------
  |  Branch (1101:13): [True: 892, False: 3.83k]
  ------------------
 1102|       |            /* Usually AMD pages are at the end but sometimes data pages appear after them */
 1103|    892|            if (amd_page_count > 0)
  ------------------
  |  Branch (1103:17): [True: 319, False: 573]
  ------------------
 1104|    319|                break;
 1105|    573|            continue;
 1106|    892|        }
 1107|  3.83k|        if ((page_type & SAS_PAGE_TYPE_COMP))
  ------------------
  |  |   99|  3.83k|#define SAS_PAGE_TYPE_COMP   0x9000
  ------------------
  |  Branch (1107:13): [True: 815, False: 3.01k]
  ------------------
 1108|    815|            continue;
 1109|       |
 1110|  3.01k|        if (io->read(ctx->page + head_len, tail_len, io->io_ctx) < tail_len) {
  ------------------
  |  Branch (1110:13): [True: 1, False: 3.01k]
  ------------------
 1111|      1|            retval = READSTAT_ERROR_READ;
 1112|      1|            goto cleanup;
 1113|      1|        }
 1114|       |
 1115|  3.01k|        if ((retval = sas7bdat_parse_page_pass1(ctx->page, ctx->page_size, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1115:13): [True: 370, False: 2.64k]
  ------------------
 1116|    370|            if (ctx->handle.error && retval != READSTAT_ERROR_USER_ABORT) {
  ------------------
  |  Branch (1116:17): [True: 0, False: 370]
  |  Branch (1116:38): [True: 0, False: 0]
  ------------------
 1117|      0|                int64_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
 1118|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
 1119|      0|                        "ReadStat: Error parsing page %" PRId64 ", bytes %" PRId64 "-%" PRId64, 
 1120|      0|                        i, pos - ctx->page_size, pos-1);
 1121|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1122|      0|            }
 1123|    370|            goto cleanup;
 1124|    370|        }
 1125|       |
 1126|  2.64k|        amd_page_count++;
 1127|  2.64k|    }
 1128|       |
 1129|  2.53k|cleanup:
 1130|       |
 1131|  2.53k|    return retval;
 1132|  2.53k|}
readstat_sas7bdat_read.c:sas7bdat_parse_all_pages_pass2:
 1134|  1.91k|static readstat_error_t sas7bdat_parse_all_pages_pass2(sas7bdat_ctx_t *ctx) {
 1135|  1.91k|    readstat_error_t retval = READSTAT_OK;
 1136|  1.91k|    readstat_io_t *io = ctx->io;
 1137|  1.91k|    int64_t i;
 1138|       |
 1139|  4.53k|    for (i=0; i<ctx->page_count; i++) {
  ------------------
  |  Branch (1139:15): [True: 4.40k, False: 135]
  ------------------
 1140|  4.40k|        if ((retval = sas7bdat_update_progress(ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1140:13): [True: 0, False: 4.40k]
  ------------------
 1141|      0|            goto cleanup;
 1142|      0|        }
 1143|  4.40k|        if (io->read(ctx->page, ctx->page_size, io->io_ctx) < ctx->page_size) {
  ------------------
  |  Branch (1143:13): [True: 106, False: 4.29k]
  ------------------
 1144|    106|            retval = READSTAT_ERROR_READ;
 1145|    106|            goto cleanup;
 1146|    106|        }
 1147|       |
 1148|  4.29k|        if ((retval = sas7bdat_parse_page_pass2(ctx->page, ctx->page_size, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1148:13): [True: 1.48k, False: 2.81k]
  ------------------
 1149|  1.48k|            if (ctx->handle.error && retval != READSTAT_ERROR_USER_ABORT) {
  ------------------
  |  Branch (1149:17): [True: 0, False: 1.48k]
  |  Branch (1149:38): [True: 0, False: 0]
  ------------------
 1150|      0|                int64_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
 1151|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
 1152|      0|                        "ReadStat: Error parsing page %" PRId64 ", bytes %" PRId64 "-%" PRId64, 
 1153|      0|                        i, pos - ctx->page_size, pos-1);
 1154|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1155|      0|            }
 1156|  1.48k|            goto cleanup;
 1157|  1.48k|        }
 1158|  2.81k|        if (ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (1158:13): [True: 189, False: 2.62k]
  ------------------
 1159|    189|            break;
 1160|  2.81k|    }
 1161|  1.91k|cleanup:
 1162|       |
 1163|  1.91k|    return retval;
 1164|  1.91k|}
readstat_sas7bdat_read.c:sas7bdat_parse_page_pass2:
  906|  4.29k|static readstat_error_t sas7bdat_parse_page_pass2(const char *page, size_t page_size, sas7bdat_ctx_t *ctx) {
  907|  4.29k|    uint16_t page_type;
  908|       |
  909|  4.29k|    readstat_error_t retval = READSTAT_OK;
  910|       |
  911|  4.29k|    page_type = sas_read2(&page[ctx->page_header_size-8], ctx->bswap);
  912|       |
  913|  4.29k|    const char *data = NULL;
  914|       |
  915|  4.29k|    if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |   96|  4.29k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                  if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |   93|  4.29k|#define SAS_PAGE_TYPE_DATA   0x0100
  ------------------
  |  Branch (915:9): [True: 639, False: 3.65k]
  ------------------
  916|    639|        ctx->page_row_count = sas_read2(&page[ctx->page_header_size-6], ctx->bswap);
  917|    639|        data = &page[ctx->page_header_size];
  918|  3.65k|    } else if (!(page_type & SAS_PAGE_TYPE_COMP)) {
  ------------------
  |  |   99|  3.65k|#define SAS_PAGE_TYPE_COMP   0x9000
  ------------------
  |  Branch (918:16): [True: 3.45k, False: 201]
  ------------------
  919|  3.45k|        uint16_t subheader_count = sas_read2(&page[ctx->page_header_size-4], ctx->bswap);
  920|       |
  921|  3.45k|        int i;
  922|  3.45k|        const char *shp = &page[ctx->page_header_size];
  923|  3.45k|        int lshp = ctx->subheader_pointer_size;
  924|       |
  925|  3.45k|        if (ctx->page_header_size + subheader_count*lshp > page_size) {
  ------------------
  |  Branch (925:13): [True: 26, False: 3.43k]
  ------------------
  926|     26|            retval = READSTAT_ERROR_PARSE;
  927|     26|            goto cleanup;
  928|     26|        }
  929|       |
  930|  45.5k|        for (i=0; i<subheader_count; i++) {
  ------------------
  |  Branch (930:19): [True: 43.3k, False: 2.26k]
  ------------------
  931|  43.3k|            subheader_pointer_t shp_info = { 0 };
  932|  43.3k|            uint32_t signature = 0;
  933|  43.3k|            if ((retval = sas7bdat_parse_subheader_pointer(shp, page + page_size - shp, &shp_info, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (933:17): [True: 0, False: 43.3k]
  ------------------
  934|      0|                goto cleanup;
  935|      0|            }
  936|  43.3k|            if (shp_info.len > 0 && shp_info.compression != SAS_COMPRESSION_TRUNC) {
  ------------------
  |  |  108|  29.4k|#define SAS_COMPRESSION_TRUNC  0x01
  ------------------
  |  Branch (936:17): [True: 29.4k, False: 13.8k]
  |  Branch (936:37): [True: 24.1k, False: 5.33k]
  ------------------
  937|  24.1k|                if ((retval = sas7bdat_validate_subheader_pointer(&shp_info, page_size, subheader_count, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (937:21): [True: 185, False: 23.9k]
  ------------------
  938|    185|                    goto cleanup;
  939|    185|                }
  940|  23.9k|                if (shp_info.compression == SAS_COMPRESSION_NONE) {
  ------------------
  |  |  107|  23.9k|#define SAS_COMPRESSION_NONE   0x00
  ------------------
  |  Branch (940:21): [True: 22.7k, False: 1.16k]
  ------------------
  941|  22.7k|                    signature = sas_read4(page + shp_info.offset, ctx->bswap);
  942|  22.7k|                    if (!ctx->little_endian && signature == -1 && ctx->u64) {
  ------------------
  |  Branch (942:25): [True: 18.7k, False: 4.07k]
  |  Branch (942:48): [True: 1.51k, False: 17.2k]
  |  Branch (942:67): [True: 962, False: 555]
  ------------------
  943|    962|                        signature = sas_read4(page + shp_info.offset + 4, ctx->bswap);
  944|    962|                    }
  945|  22.7k|                    if (shp_info.is_compressed_data && !sas7bdat_signature_is_recognized(signature)) {
  ------------------
  |  Branch (945:25): [True: 17.4k, False: 5.39k]
  |  Branch (945:56): [True: 1.70k, False: 15.7k]
  ------------------
  946|  1.70k|                        if (shp_info.len != ctx->row_length) {
  ------------------
  |  Branch (946:29): [True: 167, False: 1.53k]
  ------------------
  947|    167|                            retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  948|    167|                            goto cleanup;
  949|    167|                        }
  950|  1.53k|                        if ((retval = sas7bdat_submit_columns_if_needed(ctx, 1)) != READSTAT_OK) {
  ------------------
  |  Branch (950:29): [True: 1, False: 1.53k]
  ------------------
  951|      1|                            goto cleanup;
  952|      1|                        }
  953|  1.53k|                        if ((retval = sas7bdat_parse_single_row(page + shp_info.offset, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (953:29): [True: 1, False: 1.53k]
  ------------------
  954|      1|                            goto cleanup;
  955|      1|                        }
  956|  21.0k|                    } else {
  957|  21.0k|                        if (signature != SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT) {
  ------------------
  |  |   88|  21.0k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT    0xFFFFFFFD
  ------------------
  |  Branch (957:29): [True: 19.8k, False: 1.29k]
  ------------------
  958|  19.8k|                            if ((retval = sas7bdat_parse_subheader(signature, page + shp_info.offset, shp_info.len, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (958:33): [True: 540, False: 19.2k]
  ------------------
  959|    540|                                goto cleanup;
  960|    540|                            }
  961|  19.8k|                        }
  962|  21.0k|                    }
  963|  22.7k|                } else if (shp_info.compression == SAS_COMPRESSION_ROW) {
  ------------------
  |  |  109|  1.16k|#define SAS_COMPRESSION_ROW    0x04
  ------------------
  |  Branch (963:28): [True: 1.15k, False: 10]
  ------------------
  964|  1.15k|                    if ((retval = sas7bdat_submit_columns_if_needed(ctx, 1)) != READSTAT_OK) {
  ------------------
  |  Branch (964:25): [True: 57, False: 1.10k]
  ------------------
  965|     57|                        goto cleanup;
  966|     57|                    }
  967|  1.10k|                    if ((retval = sas7bdat_parse_subheader_compressed(page + shp_info.offset, shp_info.len, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (967:25): [True: 207, False: 894]
  ------------------
  968|    207|                        goto cleanup;
  969|    207|                    }
  970|  1.10k|                } else {
  971|     10|                    retval = READSTAT_ERROR_UNSUPPORTED_COMPRESSION;
  972|     10|                    goto cleanup;
  973|     10|                }
  974|  23.9k|            }
  975|       |
  976|  42.1k|            shp += lshp;
  977|  42.1k|        }
  978|       |
  979|  2.26k|        if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_MIX) {
  ------------------
  |  |   96|  2.26k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                      if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_MIX) {
  ------------------
  |  |   94|  2.26k|#define SAS_PAGE_TYPE_MIX    0x0200
  ------------------
  |  Branch (979:13): [True: 1.24k, False: 1.02k]
  ------------------
  980|       |            /* HACK - this is supposed to obey 8-byte boundaries but
  981|       |             * some files created by Stat/Transfer don't. So verify that the
  982|       |             * padding is { 0, 0, 0, 0 } or { ' ', ' ', ' ', ' ' } (or that
  983|       |             * the file is not from Stat/Transfer) before skipping it */
  984|  1.24k|            if ((shp-page)%8 == 4 && shp + 4 <= page + page_size &&
  ------------------
  |  Branch (984:17): [True: 243, False: 998]
  |  Branch (984:38): [True: 241, False: 2]
  ------------------
  985|  1.24k|                    (*(uint32_t *)shp == 0x00000000 ||
  ------------------
  |  Branch (985:22): [True: 19, False: 222]
  ------------------
  986|    241|                     *(uint32_t *)shp == 0x20202020 ||
  ------------------
  |  Branch (986:22): [True: 13, False: 209]
  ------------------
  987|    241|                     ctx->vendor != READSTAT_VENDOR_STAT_TRANSFER)) {
  ------------------
  |  Branch (987:22): [True: 136, False: 73]
  ------------------
  988|    168|                data = shp + 4;
  989|  1.07k|            } else {
  990|  1.07k|                data = shp;
  991|  1.07k|            }
  992|  1.24k|        }
  993|  2.26k|    }
  994|  3.10k|    if (data) {
  ------------------
  |  Branch (994:9): [True: 1.88k, False: 1.22k]
  ------------------
  995|  1.88k|        if ((retval = sas7bdat_submit_columns_if_needed(ctx, 0)) != READSTAT_OK) {
  ------------------
  |  Branch (995:13): [True: 126, False: 1.75k]
  ------------------
  996|    126|            goto cleanup;
  997|    126|        }
  998|  1.75k|        if (ctx->handle.value) {
  ------------------
  |  Branch (998:13): [True: 1.75k, False: 0]
  ------------------
  999|  1.75k|            retval = sas7bdat_parse_rows(data, page + page_size - data, ctx);
 1000|  1.75k|        }
 1001|  1.75k|    } 
 1002|  4.29k|cleanup:
 1003|       |
 1004|  4.29k|    return retval;
 1005|  3.10k|}
readstat_sas7bdat_read.c:sas7bdat_signature_is_recognized:
  799|  17.4k|static int sas7bdat_signature_is_recognized(uint32_t signature) {
  800|  17.4k|    return (signature == SAS_SUBHEADER_SIGNATURE_ROW_SIZE ||
  ------------------
  |  |   79|  34.8k|#define SAS_SUBHEADER_SIGNATURE_ROW_SIZE       0xF7F7F7F7
  ------------------
  |  Branch (800:13): [True: 6.22k, False: 11.1k]
  ------------------
  801|  17.4k|            signature == SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE ||
  ------------------
  |  |   80|  28.5k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE    0xF6F6F6F6
  ------------------
  |  Branch (801:13): [True: 843, False: 10.3k]
  ------------------
  802|  17.4k|            signature == SAS_SUBHEADER_SIGNATURE_COUNTS ||
  ------------------
  |  |   81|  27.7k|#define SAS_SUBHEADER_SIGNATURE_COUNTS         0xFFFFFC00
  ------------------
  |  Branch (802:13): [True: 664, False: 9.67k]
  ------------------
  803|  17.4k|            signature == SAS_SUBHEADER_SIGNATURE_COLUMN_FORMAT ||
  ------------------
  |  |   82|  27.0k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_FORMAT  0xFFFFFBFE
  ------------------
  |  Branch (803:13): [True: 3.31k, False: 6.36k]
  ------------------
  804|  17.4k|            (signature & SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) == SAS_SUBHEADER_SIGNATURE_COLUMN_MASK);
  ------------------
  |  |   84|  6.36k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_MASK    0xFFFFFFF8
  ------------------
                          (signature & SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) == SAS_SUBHEADER_SIGNATURE_COLUMN_MASK);
  ------------------
  |  |   84|  6.36k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_MASK    0xFFFFFFF8
  ------------------
  |  Branch (804:13): [True: 4.66k, False: 1.70k]
  ------------------
  805|  17.4k|}
readstat_sas7bdat_read.c:sas7bdat_parse_single_row:
  447|   168k|static readstat_error_t sas7bdat_parse_single_row(const char *data, sas7bdat_ctx_t *ctx) {
  448|   168k|    if (ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (448:9): [True: 396, False: 167k]
  ------------------
  449|    396|        return READSTAT_OK;
  450|   167k|    if (ctx->row_offset) {
  ------------------
  |  Branch (450:9): [True: 0, False: 167k]
  ------------------
  451|      0|        ctx->row_offset--;
  452|      0|        return READSTAT_OK;
  453|      0|    }
  454|       |
  455|   167k|    readstat_error_t retval = READSTAT_OK;
  456|   167k|    int j;
  457|   167k|    if (ctx->handle.value) {
  ------------------
  |  Branch (457:9): [True: 167k, False: 0]
  ------------------
  458|   167k|        ctx->scratch_buffer_len = 4*ctx->max_col_width+1;
  459|   167k|        ctx->scratch_buffer = readstat_realloc(ctx->scratch_buffer, ctx->scratch_buffer_len);
  460|   167k|        if (ctx->scratch_buffer == NULL) {
  ------------------
  |  Branch (460:13): [True: 3, False: 167k]
  ------------------
  461|      3|            retval = READSTAT_ERROR_MALLOC;
  462|      3|            goto cleanup;
  463|      3|        }
  464|       |
  465|   240k|        for (j=0; j<ctx->column_count; j++) {
  ------------------
  |  Branch (465:19): [True: 73.0k, False: 167k]
  ------------------
  466|  73.0k|            col_info_t *col_info = &ctx->col_info[j];
  467|  73.0k|            readstat_variable_t *variable = ctx->variables[j];
  468|  73.0k|            if (variable->skip)
  ------------------
  |  Branch (468:17): [True: 0, False: 73.0k]
  ------------------
  469|      0|                continue;
  470|       |
  471|  73.0k|            if (col_info->offset > ctx->row_length || col_info->offset + col_info->width > ctx->row_length) {
  ------------------
  |  Branch (471:17): [True: 95, False: 72.9k]
  |  Branch (471:55): [True: 2, False: 72.9k]
  ------------------
  472|     97|                retval = READSTAT_ERROR_PARSE;
  473|     97|                goto cleanup;
  474|     97|            }
  475|  72.9k|            retval = sas7bdat_handle_data_value(variable, col_info, &data[col_info->offset], ctx);
  476|  72.9k|            if (retval != READSTAT_OK) {
  ------------------
  |  Branch (476:17): [True: 18, False: 72.8k]
  ------------------
  477|     18|                goto cleanup;
  478|     18|            }
  479|  72.9k|        }
  480|   167k|    }
  481|   167k|    ctx->parsed_row_count++;
  482|       |
  483|   167k|cleanup:
  484|   167k|    return retval;
  485|   167k|}
readstat_sas7bdat_read.c:sas7bdat_handle_data_value:
  391|  72.9k|        col_info_t *col_info, const char *col_data, sas7bdat_ctx_t *ctx) {
  392|  72.9k|    readstat_error_t retval = READSTAT_OK;
  393|  72.9k|    int cb_retval = 0;
  394|  72.9k|    readstat_value_t value;
  395|  72.9k|    memset(&value, 0, sizeof(readstat_value_t));
  396|       |
  397|  72.9k|    value.type = col_info->type;
  398|       |
  399|  72.9k|    if (col_info->type == READSTAT_TYPE_STRING) {
  ------------------
  |  Branch (399:9): [True: 22.0k, False: 50.8k]
  ------------------
  400|  22.0k|        retval = readstat_convert(ctx->scratch_buffer, ctx->scratch_buffer_len,
  401|  22.0k|                col_data, col_info->width, ctx->converter);
  402|  22.0k|        if (retval != READSTAT_OK) {
  ------------------
  |  Branch (402:13): [True: 18, False: 22.0k]
  ------------------
  403|     18|            if (ctx->handle.error) {
  ------------------
  |  Branch (403:17): [True: 0, False: 18]
  ------------------
  404|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf),
  405|      0|                        "ReadStat: Error converting string (row=%u, col=%u) to specified encoding: %.*s",
  406|      0|                        ctx->parsed_row_count+1, col_info->index+1, col_info->width, col_data);
  407|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
  408|      0|            }
  409|     18|            goto cleanup;
  410|     18|        }
  411|       |
  412|  22.0k|        value.v.string_value = ctx->scratch_buffer;
  413|  50.8k|    } else if (col_info->type == READSTAT_TYPE_DOUBLE) {
  ------------------
  |  Branch (413:16): [True: 50.8k, False: 0]
  ------------------
  414|  50.8k|        uint64_t  val = 0;
  415|  50.8k|        double dval = NAN;
  416|  50.8k|        if (ctx->little_endian) {
  ------------------
  |  Branch (416:13): [True: 50.8k, False: 0]
  ------------------
  417|  50.8k|            int k;
  418|   312k|            for (k=0; k<col_info->width; k++) {
  ------------------
  |  Branch (418:23): [True: 261k, False: 50.8k]
  ------------------
  419|   261k|                val = (val << 8) | (unsigned char)col_data[col_info->width-1-k];
  420|   261k|            }
  421|  50.8k|        } else {
  422|      0|            int k;
  423|      0|            for (k=0; k<col_info->width; k++) {
  ------------------
  |  Branch (423:23): [True: 0, False: 0]
  ------------------
  424|      0|                val = (val << 8) | (unsigned char)col_data[k];
  425|      0|            }
  426|      0|        }
  427|  50.8k|        val <<= (8-col_info->width)*8;
  428|       |
  429|  50.8k|        memcpy(&dval, &val, 8);
  430|       |
  431|  50.8k|        if (isnan(dval)) {
  432|  4.81k|            value.v.double_value = NAN;
  433|  4.81k|            sas_assign_tag(&value, ~((val >> 40) & 0xFF));
  434|  46.0k|        } else {
  435|  46.0k|            value.v.double_value = dval;
  436|  46.0k|        }
  437|  50.8k|    }
  438|  72.8k|    cb_retval = ctx->handle.value(ctx->parsed_row_count, variable, value, ctx->user_ctx);
  439|       |
  440|  72.8k|    if (cb_retval != READSTAT_HANDLER_OK)
  ------------------
  |  Branch (440:9): [True: 0, False: 72.8k]
  ------------------
  441|      0|        retval = READSTAT_ERROR_USER_ABORT;
  442|       |
  443|  72.9k|cleanup:
  444|  72.9k|    return retval;
  445|  72.8k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_compressed:
  619|  1.10k|static readstat_error_t sas7bdat_parse_subheader_compressed(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  620|  1.10k|    if (ctx->rdc_compression)
  ------------------
  |  Branch (620:9): [True: 299, False: 802]
  ------------------
  621|    299|        return sas7bdat_parse_subheader_rdc(subheader, len, ctx);
  622|       |
  623|    802|    return sas7bdat_parse_subheader_rle(subheader, len, ctx);
  624|  1.10k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_rdc:
  506|    299|static readstat_error_t sas7bdat_parse_subheader_rdc(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  507|    299|    readstat_error_t retval = READSTAT_OK;
  508|    299|    const unsigned char *input = (const unsigned char *)subheader;
  509|    299|    char *buffer = malloc(ctx->row_length);
  510|    299|    char *output = buffer;
  511|  1.83k|    while (input + 2 <= (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (511:12): [True: 1.56k, False: 265]
  ------------------
  512|  1.56k|        int i;
  513|  1.56k|        unsigned short prefix = (input[0] << 8) + input[1];
  514|  1.56k|        input += 2;
  515|  23.3k|        for (i=0; i<16; i++) {
  ------------------
  |  Branch (515:19): [True: 22.0k, False: 1.26k]
  ------------------
  516|  22.0k|            if ((prefix & (1 << (15 - i))) == 0) {
  ------------------
  |  Branch (516:17): [True: 15.8k, False: 6.23k]
  ------------------
  517|  15.8k|                if (input + 1 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (517:21): [True: 265, False: 15.5k]
  ------------------
  518|    265|                    break;
  519|    265|                }
  520|  15.5k|                if (output + 1 > buffer + ctx->row_length) {
  ------------------
  |  Branch (520:21): [True: 2, False: 15.5k]
  ------------------
  521|      2|                    retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  522|      2|                    goto cleanup;
  523|      2|                }
  524|  15.5k|                *output++ = *input++;
  525|  15.5k|                continue;
  526|  15.5k|            }
  527|       |
  528|  6.23k|            if (input + 2 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (528:17): [True: 4, False: 6.22k]
  ------------------
  529|      4|                retval = READSTAT_ERROR_PARSE;
  530|      4|                goto cleanup;
  531|      4|            }
  532|       |
  533|  6.22k|            unsigned char marker_byte = *input++;
  534|  6.22k|            unsigned char next_byte = *input++;
  535|  6.22k|            size_t insert_len = 0, copy_len = 0;
  536|  6.22k|            unsigned char insert_byte = 0x00;
  537|  6.22k|            size_t back_offset = 0;
  538|       |
  539|  6.22k|            if (marker_byte <= 0x0F) {
  ------------------
  |  Branch (539:17): [True: 2.63k, False: 3.59k]
  ------------------
  540|  2.63k|                insert_len = 3 + marker_byte;
  541|  2.63k|                insert_byte = next_byte;
  542|  3.59k|            } else if ((marker_byte >> 4) == 1) {
  ------------------
  |  Branch (542:24): [True: 948, False: 2.64k]
  ------------------
  543|    948|                if (input + 1 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (543:21): [True: 3, False: 945]
  ------------------
  544|      3|                    retval = READSTAT_ERROR_PARSE;
  545|      3|                    goto cleanup;
  546|      3|                }
  547|    945|                insert_len = 19 + (marker_byte & 0x0F) + next_byte * 16;
  548|    945|                insert_byte = *input++;
  549|  2.64k|            } else if ((marker_byte >> 4) == 2) {
  ------------------
  |  Branch (549:24): [True: 550, False: 2.09k]
  ------------------
  550|    550|                if (input + 1 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (550:21): [True: 1, False: 549]
  ------------------
  551|      1|                    retval = READSTAT_ERROR_PARSE;
  552|      1|                    goto cleanup;
  553|      1|                }
  554|    549|                copy_len = 16 + (*input++);
  555|    549|                back_offset = 3 + (marker_byte & 0x0F) + next_byte * 16;
  556|  2.09k|            } else {
  557|  2.09k|                copy_len = (marker_byte >> 4);
  558|  2.09k|                back_offset = 3 + (marker_byte & 0x0F) + next_byte * 16;
  559|  2.09k|            }
  560|       |
  561|  6.22k|            if (insert_len) {
  ------------------
  |  Branch (561:17): [True: 3.57k, False: 2.64k]
  ------------------
  562|  3.57k|                if (output + insert_len > buffer + ctx->row_length) {
  ------------------
  |  Branch (562:21): [True: 1, False: 3.57k]
  ------------------
  563|      1|                    retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  564|      1|                    goto cleanup;
  565|      1|                }
  566|  3.57k|                memset(output, insert_byte, insert_len);
  567|  3.57k|                output += insert_len;
  568|  3.57k|            } else if (copy_len) {
  ------------------
  |  Branch (568:24): [True: 2.64k, False: 0]
  ------------------
  569|  2.64k|                if (output - buffer < back_offset || copy_len > back_offset) {
  ------------------
  |  Branch (569:21): [True: 8, False: 2.64k]
  |  Branch (569:54): [True: 14, False: 2.62k]
  ------------------
  570|     22|                    retval = READSTAT_ERROR_PARSE;
  571|     22|                    goto cleanup;
  572|     22|                }
  573|  2.62k|                if (output + copy_len > buffer + ctx->row_length) {
  ------------------
  |  Branch (573:21): [True: 1, False: 2.62k]
  ------------------
  574|      1|                    retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  575|      1|                    goto cleanup;
  576|      1|                }
  577|  2.62k|                memcpy(output, output - back_offset, copy_len);
  578|  2.62k|                output += copy_len;
  579|  2.62k|            }
  580|  6.22k|        }
  581|  1.56k|    }
  582|       |
  583|    265|    if (output - buffer != ctx->row_length) {
  ------------------
  |  Branch (583:9): [True: 13, False: 252]
  ------------------
  584|     13|        retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  585|     13|        goto cleanup;
  586|     13|    }
  587|    252|    retval = sas7bdat_parse_single_row(buffer, ctx);
  588|    299|cleanup:
  589|    299|    free(buffer);
  590|       |
  591|    299|    return retval;
  592|    252|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_rle:
  594|    802|static readstat_error_t sas7bdat_parse_subheader_rle(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  595|    802|    if (ctx->row_limit == ctx->parsed_row_count)
  ------------------
  |  Branch (595:9): [True: 529, False: 273]
  ------------------
  596|    529|        return READSTAT_OK;
  597|       |
  598|    273|    readstat_error_t retval = READSTAT_OK;
  599|    273|    ssize_t bytes_decompressed = 0;
  600|       |
  601|    273|    bytes_decompressed = sas_rle_decompress(ctx->row, ctx->row_length, subheader, len);
  602|       |
  603|    273|    if (bytes_decompressed != ctx->row_length) {
  ------------------
  |  Branch (603:9): [True: 113, False: 160]
  ------------------
  604|    113|        retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  605|    113|        if (ctx->handle.error) {
  ------------------
  |  Branch (605:13): [True: 0, False: 113]
  ------------------
  606|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
  607|      0|                    "ReadStat: Row #%d decompressed to %ld bytes (expected %d bytes)",
  608|      0|                    ctx->parsed_row_count, (long)(bytes_decompressed), ctx->row_length);
  609|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
  610|      0|        }
  611|    113|        goto cleanup;
  612|    113|    }
  613|    160|    retval = sas7bdat_parse_single_row(ctx->row, ctx);
  614|       |
  615|    273|cleanup:
  616|    273|    return retval;
  617|    160|}
readstat_sas7bdat_read.c:sas7bdat_parse_rows:
  487|  1.75k|static readstat_error_t sas7bdat_parse_rows(const char *data, size_t len, sas7bdat_ctx_t *ctx) {
  488|  1.75k|    readstat_error_t retval = READSTAT_OK;
  489|  1.75k|    int i;
  490|  1.75k|    size_t row_offset=0;
  491|   168k|    for (i=0; i<ctx->page_row_count && ctx->parsed_row_count < ctx->row_limit; i++) {
  ------------------
  |  Branch (491:15): [True: 166k, False: 1.37k]
  |  Branch (491:40): [True: 166k, False: 220]
  ------------------
  492|   166k|        if (row_offset + ctx->row_length > len) {
  ------------------
  |  Branch (492:13): [True: 94, False: 166k]
  ------------------
  493|     94|            retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  494|     94|            goto cleanup;
  495|     94|        }
  496|   166k|        if ((retval = sas7bdat_parse_single_row(&data[row_offset], ctx)) != READSTAT_OK)
  ------------------
  |  Branch (496:13): [True: 70, False: 166k]
  ------------------
  497|     70|            goto cleanup;
  498|       |
  499|   166k|        row_offset += ctx->row_length;
  500|   166k|    }
  501|       |
  502|  1.75k|cleanup:
  503|  1.75k|    return retval;
  504|  1.75k|}
readstat_sas7bdat_read.c:sas7bdat_submit_columns_if_needed:
  787|  4.89k|static readstat_error_t sas7bdat_submit_columns_if_needed(sas7bdat_ctx_t *ctx, int compressed) {
  788|  4.89k|    readstat_error_t retval = READSTAT_OK;
  789|  4.89k|    if (!ctx->did_submit_columns) {
  ------------------
  |  Branch (789:9): [True: 1.28k, False: 3.61k]
  ------------------
  790|  1.28k|        if ((retval = sas7bdat_submit_columns(ctx, compressed)) != READSTAT_OK) {
  ------------------
  |  Branch (790:13): [True: 272, False: 1.00k]
  ------------------
  791|    272|            goto cleanup;
  792|    272|        }
  793|  1.00k|        ctx->did_submit_columns = 1;
  794|  1.00k|    }
  795|  4.89k|cleanup:
  796|  4.89k|    return retval;
  797|  4.89k|}
readstat_sas7bdat_read.c:sas7bdat_submit_columns:
  726|  1.28k|static readstat_error_t sas7bdat_submit_columns(sas7bdat_ctx_t *ctx, int compressed) {
  727|  1.28k|    readstat_error_t retval = READSTAT_OK;
  728|  1.28k|    if (ctx->handle.metadata) {
  ------------------
  |  Branch (728:9): [True: 1.28k, False: 0]
  ------------------
  729|  1.28k|        readstat_metadata_t metadata = {
  730|  1.28k|            .row_count = ctx->row_limit,
  731|  1.28k|            .var_count = ctx->column_count,
  732|  1.28k|            .table_name = ctx->table_name,
  733|  1.28k|            .file_label = ctx->file_label,
  734|  1.28k|            .file_encoding = ctx->input_encoding, /* orig encoding? */
  735|  1.28k|            .creation_time = ctx->ctime,
  736|  1.28k|            .modified_time = ctx->mtime,
  737|  1.28k|            .file_format_version = ctx->version,
  738|  1.28k|            .compression = READSTAT_COMPRESS_NONE,
  739|  1.28k|            .endianness = ctx->little_endian ? READSTAT_ENDIAN_LITTLE : READSTAT_ENDIAN_BIG,
  ------------------
  |  Branch (739:27): [True: 240, False: 1.04k]
  ------------------
  740|  1.28k|            .is64bit = ctx->u64
  741|  1.28k|        };
  742|  1.28k|        if (compressed) {
  ------------------
  |  Branch (742:13): [True: 482, False: 798]
  ------------------
  743|    482|            if (ctx->rdc_compression) {
  ------------------
  |  Branch (743:17): [True: 25, False: 457]
  ------------------
  744|     25|                metadata.compression = READSTAT_COMPRESS_BINARY;
  745|    457|            } else {
  746|    457|                metadata.compression = READSTAT_COMPRESS_ROWS;
  747|    457|            }
  748|    482|        }
  749|  1.28k|        if (ctx->handle.metadata(&metadata, ctx->user_ctx) != READSTAT_HANDLER_OK) {
  ------------------
  |  Branch (749:13): [True: 0, False: 1.28k]
  ------------------
  750|      0|            retval = READSTAT_ERROR_USER_ABORT;
  751|      0|            goto cleanup;
  752|      0|        }
  753|  1.28k|    }
  754|  1.28k|    if (ctx->column_count == 0)
  ------------------
  |  Branch (754:9): [True: 858, False: 422]
  ------------------
  755|    858|        goto cleanup;
  756|       |
  757|    422|    if ((ctx->variables = readstat_calloc(ctx->column_count, sizeof(readstat_variable_t *))) == NULL) {
  ------------------
  |  Branch (757:9): [True: 0, False: 422]
  ------------------
  758|      0|        retval = READSTAT_ERROR_MALLOC;
  759|      0|        goto cleanup;
  760|      0|    }
  761|    422|    int i;
  762|    422|    int index_after_skipping = 0;
  763|  2.60k|    for (i=0; i<ctx->column_count; i++) {
  ------------------
  |  Branch (763:15): [True: 2.45k, False: 150]
  ------------------
  764|  2.45k|        ctx->variables[i] = sas7bdat_init_variable(ctx, i, index_after_skipping, &retval);
  765|  2.45k|        if (ctx->variables[i] == NULL)
  ------------------
  |  Branch (765:13): [True: 272, False: 2.18k]
  ------------------
  766|    272|            break;
  767|       |
  768|  2.18k|        int cb_retval = READSTAT_HANDLER_OK;
  769|  2.18k|        if (ctx->handle.variable) {
  ------------------
  |  Branch (769:13): [True: 2.18k, False: 0]
  ------------------
  770|  2.18k|            cb_retval = ctx->handle.variable(i, ctx->variables[i], ctx->variables[i]->format, ctx->user_ctx);
  771|  2.18k|        }
  772|  2.18k|        if (cb_retval == READSTAT_HANDLER_ABORT) {
  ------------------
  |  Branch (772:13): [True: 0, False: 2.18k]
  ------------------
  773|      0|            retval = READSTAT_ERROR_USER_ABORT;
  774|      0|            goto cleanup;
  775|      0|        }
  776|       |
  777|  2.18k|        if (cb_retval == READSTAT_HANDLER_SKIP_VARIABLE) {
  ------------------
  |  Branch (777:13): [True: 0, False: 2.18k]
  ------------------
  778|      0|            ctx->variables[i]->skip = 1;
  779|  2.18k|        } else {
  780|  2.18k|            index_after_skipping++;
  781|  2.18k|        }
  782|  2.18k|    }
  783|  1.28k|cleanup:
  784|  1.28k|    return retval;
  785|    422|}
readstat_sas7bdat_read.c:sas7bdat_init_variable:
  675|  2.45k|        int index_after_skipping, readstat_error_t *out_retval) {
  676|  2.45k|    readstat_error_t retval = READSTAT_OK;
  677|  2.45k|    readstat_variable_t *variable = readstat_calloc(1, sizeof(readstat_variable_t));
  678|       |
  679|  2.45k|    variable->index = i;
  680|  2.45k|    variable->index_after_skipping = index_after_skipping;
  681|  2.45k|    variable->type = ctx->col_info[i].type;
  682|  2.45k|    variable->storage_width = ctx->col_info[i].width;
  683|       |
  684|  2.45k|    if ((retval = sas7bdat_validate_column(&ctx->col_info[i])) != READSTAT_OK) {
  ------------------
  |  Branch (684:9): [True: 125, False: 2.32k]
  ------------------
  685|    125|        goto cleanup;
  686|    125|    }
  687|  2.32k|    if ((retval = sas7bdat_copy_text_ref(variable->name, sizeof(variable->name), 
  ------------------
  |  Branch (687:9): [True: 43, False: 2.28k]
  ------------------
  688|  2.32k|                    ctx->col_info[i].name_ref, ctx)) != READSTAT_OK) {
  689|     43|        goto cleanup;
  690|     43|    }
  691|  2.28k|    if ((retval = sas7bdat_copy_text_ref(variable->format, sizeof(variable->format),
  ------------------
  |  Branch (691:9): [True: 49, False: 2.23k]
  ------------------
  692|  2.28k|                    ctx->col_info[i].format_ref, ctx)) != READSTAT_OK) {
  693|     49|        goto cleanup;
  694|     49|    }
  695|  2.23k|    size_t len = strlen(variable->format);
  696|  2.23k|    if (len && ctx->col_info[i].format_len) {
  ------------------
  |  Branch (696:9): [True: 354, False: 1.88k]
  |  Branch (696:16): [True: 122, False: 232]
  ------------------
  697|    122|        snprintf(variable->format + len, sizeof(variable->format) - len, "%d", ctx->col_info[i].format_len);
  698|    122|    }
  699|  2.23k|    if ((retval = sas7bdat_copy_text_ref(variable->label, sizeof(variable->label), 
  ------------------
  |  Branch (699:9): [True: 55, False: 2.18k]
  ------------------
  700|  2.23k|                    ctx->col_info[i].label_ref, ctx)) != READSTAT_OK) {
  701|     55|        goto cleanup;
  702|     55|    }
  703|       |
  704|  2.45k|cleanup:
  705|  2.45k|    if (retval != READSTAT_OK) {
  ------------------
  |  Branch (705:9): [True: 272, False: 2.18k]
  ------------------
  706|    272|        if (out_retval)
  ------------------
  |  Branch (706:13): [True: 272, False: 0]
  ------------------
  707|    272|            *out_retval = retval;
  708|       |
  709|    272|        if (retval == READSTAT_ERROR_CONVERT_BAD_STRING) {
  ------------------
  |  Branch (709:13): [True: 5, False: 267]
  ------------------
  710|      5|            if (ctx->handle.error) {
  ------------------
  |  Branch (710:17): [True: 0, False: 5]
  ------------------
  711|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf),
  712|      0|                        "ReadStat: Error converting variable #%d info to specified encoding: %s %s (%s)",
  713|      0|                        i, variable->name, variable->format, variable->label);
  714|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
  715|      0|            }
  716|      5|        }
  717|       |
  718|    272|        free(variable);
  719|       |
  720|    272|        return NULL;
  721|    272|    }
  722|       |
  723|  2.18k|    return variable;
  724|  2.45k|}
readstat_sas7bdat_read.c:sas7bdat_validate_column:
  660|  2.45k|static readstat_error_t sas7bdat_validate_column(col_info_t *col_info) {
  661|  2.45k|    if (col_info->type == READSTAT_TYPE_DOUBLE) {
  ------------------
  |  Branch (661:9): [True: 1.02k, False: 1.43k]
  ------------------
  662|  1.02k|        if (col_info->width > 8 || col_info->width < 3) {
  ------------------
  |  Branch (662:13): [True: 53, False: 969]
  |  Branch (662:36): [True: 3, False: 966]
  ------------------
  663|     56|            return READSTAT_ERROR_PARSE;
  664|     56|        }
  665|  1.02k|    }
  666|  2.39k|    if (col_info->type == READSTAT_TYPE_STRING) {
  ------------------
  |  Branch (666:9): [True: 1.43k, False: 966]
  ------------------
  667|  1.43k|        if (col_info->width > INT16_MAX || col_info->width == 0) {
  ------------------
  |  Branch (667:13): [True: 38, False: 1.39k]
  |  Branch (667:44): [True: 31, False: 1.36k]
  ------------------
  668|     69|            return READSTAT_ERROR_PARSE;
  669|     69|        }
  670|  1.43k|    }
  671|  2.32k|    return READSTAT_OK;
  672|  2.39k|}
readstat_sas7bdat_read.c:sas7bdat_update_progress:
  127|  4.52k|static readstat_error_t sas7bdat_update_progress(sas7bdat_ctx_t *ctx) {
  128|  4.52k|    readstat_io_t *io = ctx->io;
  129|  4.52k|    return io->update(ctx->file_size, ctx->handle.progress, ctx->user_ctx, io->io_ctx);
  130|  4.52k|}
readstat_sas7bdat_read.c:sas7bdat_ctx_free:
   93|  3.27k|static void sas7bdat_ctx_free(sas7bdat_ctx_t *ctx) {
   94|  3.27k|    int i;
   95|  3.27k|    if (ctx->text_blobs) {
  ------------------
  |  Branch (95:9): [True: 912, False: 2.36k]
  ------------------
   96|  3.42k|        for (i=0; i<ctx->text_blob_count; i++) {
  ------------------
  |  Branch (96:19): [True: 2.51k, False: 912]
  ------------------
   97|  2.51k|            free(ctx->text_blobs[i]);
   98|  2.51k|        }
   99|    912|        free(ctx->text_blobs);
  100|    912|        free(ctx->text_blob_lengths);
  101|    912|    }
  102|  3.27k|    if (ctx->variables) {
  ------------------
  |  Branch (102:9): [True: 422, False: 2.85k]
  ------------------
  103|  20.7M|        for (i=0; i<ctx->column_count; i++) {
  ------------------
  |  Branch (103:19): [True: 20.7M, False: 422]
  ------------------
  104|  20.7M|            if (ctx->variables[i])
  ------------------
  |  Branch (104:17): [True: 2.18k, False: 20.7M]
  ------------------
  105|  2.18k|                free(ctx->variables[i]);
  106|  20.7M|        }
  107|    422|        free(ctx->variables);
  108|    422|    }
  109|  3.27k|    if (ctx->col_info)
  ------------------
  |  Branch (109:9): [True: 662, False: 2.61k]
  ------------------
  110|    662|        free(ctx->col_info);
  111|       |
  112|  3.27k|    if (ctx->scratch_buffer)
  ------------------
  |  Branch (112:9): [True: 482, False: 2.79k]
  ------------------
  113|    482|        free(ctx->scratch_buffer);
  114|       |
  115|  3.27k|    if (ctx->page)
  ------------------
  |  Branch (115:9): [True: 2.76k, False: 510]
  ------------------
  116|  2.76k|        free(ctx->page);
  117|       |
  118|  3.27k|    if (ctx->row)
  ------------------
  |  Branch (118:9): [True: 937, False: 2.33k]
  ------------------
  119|    937|        free(ctx->row);
  120|       |
  121|  3.27k|    if (ctx->converter)
  ------------------
  |  Branch (121:9): [True: 2.03k, False: 1.23k]
  ------------------
  122|  2.03k|        iconv_close(ctx->converter);
  123|       |
  124|  3.27k|    free(ctx);
  125|  3.27k|}

sas_rle_decompress:
   47|    273|        const void *input_buf, size_t input_len) {
   48|    273|    unsigned char *buffer = (unsigned char *)output_buf;
   49|    273|    unsigned char *output = buffer;
   50|    273|    size_t output_written = 0;
   51|       |
   52|    273|    const unsigned char *input = (const unsigned char *)input_buf;
   53|       |
   54|  13.2k|    while (input < (const unsigned char *)input_buf + input_len) {
  ------------------
  |  Branch (54:12): [True: 13.1k, False: 165]
  ------------------
   55|  13.1k|        unsigned char control = *input++;
   56|  13.1k|        unsigned char command = (control & 0xF0) >> 4;
   57|  13.1k|        unsigned char length = (control & 0x0F);
   58|  13.1k|        int copy_len = 0;
   59|  13.1k|        int insert_len = 0;
   60|  13.1k|        unsigned char insert_byte = '\0';
   61|  13.1k|        if (input + command_lengths[command] > (const unsigned char *)input_buf + input_len) {
  ------------------
  |  Branch (61:13): [True: 3, False: 13.1k]
  ------------------
   62|      3|            return -1;
   63|      3|        }
   64|  13.1k|        switch (command) {
   65|  1.03k|            case SAS_RLE_COMMAND_COPY64:
  ------------------
  |  |   13|  1.03k|#define SAS_RLE_COMMAND_COPY64          0
  ------------------
  |  Branch (65:13): [True: 1.03k, False: 12.1k]
  ------------------
   66|  1.03k|                copy_len = (*input++) + 64 + length * 256;
   67|  1.03k|                break;
   68|     59|            case SAS_RLE_COMMAND_COPY64_PLUS_4096:
  ------------------
  |  |   14|     59|#define SAS_RLE_COMMAND_COPY64_PLUS_4096 1
  ------------------
  |  Branch (68:13): [True: 59, False: 13.0k]
  ------------------
   69|     59|                copy_len = (*input++) + 64 + length * 256 + 4096;
   70|     59|                break;
   71|    353|            case SAS_RLE_COMMAND_COPY96: copy_len = length + 96; break;
  ------------------
  |  |   15|    353|#define SAS_RLE_COMMAND_COPY96          2
  ------------------
  |  Branch (71:13): [True: 353, False: 12.7k]
  ------------------
   72|    613|            case SAS_RLE_COMMAND_INSERT_BYTE18:
  ------------------
  |  |   16|    613|#define SAS_RLE_COMMAND_INSERT_BYTE18   4
  ------------------
  |  Branch (72:13): [True: 613, False: 12.5k]
  ------------------
   73|    613|                insert_len = (*input++) + 18 + length * 256;
   74|    613|                insert_byte = *input++;
   75|    613|                break;
   76|    365|            case SAS_RLE_COMMAND_INSERT_AT17:
  ------------------
  |  |   17|    365|#define SAS_RLE_COMMAND_INSERT_AT17     5
  ------------------
  |  Branch (76:13): [True: 365, False: 12.7k]
  ------------------
   77|    365|                insert_len = (*input++) + 17 + length * 256;
   78|    365|                insert_byte = '@';
   79|    365|                break;
   80|    702|            case SAS_RLE_COMMAND_INSERT_BLANK17:
  ------------------
  |  |   18|    702|#define SAS_RLE_COMMAND_INSERT_BLANK17  6
  ------------------
  |  Branch (80:13): [True: 702, False: 12.4k]
  ------------------
   81|    702|                insert_len = (*input++) + 17 + length * 256;
   82|    702|                insert_byte = ' ';
   83|    702|                break;
   84|    463|            case SAS_RLE_COMMAND_INSERT_ZERO17:
  ------------------
  |  |   19|    463|#define SAS_RLE_COMMAND_INSERT_ZERO17   7
  ------------------
  |  Branch (84:13): [True: 463, False: 12.6k]
  ------------------
   85|    463|                insert_len = (*input++) + 17 + length * 256;
   86|    463|                insert_byte = '\0';
   87|    463|                break;
   88|    757|            case SAS_RLE_COMMAND_COPY1:  copy_len = length + 1; break;
  ------------------
  |  |   20|    757|#define SAS_RLE_COMMAND_COPY1           8
  ------------------
  |  Branch (88:13): [True: 757, False: 12.3k]
  ------------------
   89|    273|            case SAS_RLE_COMMAND_COPY17: copy_len = length + 17; break;
  ------------------
  |  |   21|    273|#define SAS_RLE_COMMAND_COPY17          9
  ------------------
  |  Branch (89:13): [True: 273, False: 12.8k]
  ------------------
   90|    307|            case SAS_RLE_COMMAND_COPY33: copy_len = length + 33; break;
  ------------------
  |  |   22|    307|#define SAS_RLE_COMMAND_COPY33         10
  ------------------
  |  Branch (90:13): [True: 307, False: 12.8k]
  ------------------
   91|    250|            case SAS_RLE_COMMAND_COPY49: copy_len = length + 49; break;
  ------------------
  |  |   23|    250|#define SAS_RLE_COMMAND_COPY49         11
  ------------------
  |  Branch (91:13): [True: 250, False: 12.8k]
  ------------------
   92|    603|            case SAS_RLE_COMMAND_INSERT_BYTE3:
  ------------------
  |  |   24|    603|#define SAS_RLE_COMMAND_INSERT_BYTE3   12
  ------------------
  |  Branch (92:13): [True: 603, False: 12.5k]
  ------------------
   93|    603|                insert_byte = *input++;
   94|    603|                insert_len = length + 3;
   95|    603|                break;
   96|  1.49k|            case SAS_RLE_COMMAND_INSERT_AT2:
  ------------------
  |  |   25|  1.49k|#define SAS_RLE_COMMAND_INSERT_AT2     13
  ------------------
  |  Branch (96:13): [True: 1.49k, False: 11.6k]
  ------------------
   97|  1.49k|                insert_byte = '@';
   98|  1.49k|                insert_len = length + 2;
   99|  1.49k|                break;
  100|  1.07k|            case SAS_RLE_COMMAND_INSERT_BLANK2:
  ------------------
  |  |   26|  1.07k|#define SAS_RLE_COMMAND_INSERT_BLANK2  14
  ------------------
  |  Branch (100:13): [True: 1.07k, False: 12.0k]
  ------------------
  101|  1.07k|                insert_byte = ' ';
  102|  1.07k|                insert_len = length + 2;
  103|  1.07k|                break;
  104|  3.08k|            case SAS_RLE_COMMAND_INSERT_ZERO2:
  ------------------
  |  |   27|  3.08k|#define SAS_RLE_COMMAND_INSERT_ZERO2   15
  ------------------
  |  Branch (104:13): [True: 3.08k, False: 10.0k]
  ------------------
  105|  3.08k|                insert_byte = '\0';
  106|  3.08k|                insert_len = length + 2;
  107|  3.08k|                break;
  108|  1.69k|            default:
  ------------------
  |  Branch (108:13): [True: 1.69k, False: 11.4k]
  ------------------
  109|       |                /* error out here? */
  110|  1.69k|                break;
  111|  13.1k|        }
  112|  13.1k|        if (copy_len) {
  ------------------
  |  Branch (112:13): [True: 3.03k, False: 10.1k]
  ------------------
  113|  3.03k|            if (output_written + copy_len > output_len) {
  ------------------
  |  Branch (113:17): [True: 24, False: 3.00k]
  ------------------
  114|     24|                return -1;
  115|     24|            }
  116|  3.00k|            if (input + copy_len > (const unsigned char *)input_buf + input_len) {
  ------------------
  |  Branch (116:17): [True: 61, False: 2.94k]
  ------------------
  117|     61|                return -1;
  118|     61|            }
  119|  2.94k|            if (output) {
  ------------------
  |  Branch (119:17): [True: 2.94k, False: 0]
  ------------------
  120|  2.94k|                memcpy(&output[output_written], input, copy_len);
  121|  2.94k|            }
  122|  2.94k|            input += copy_len;
  123|  2.94k|            output_written += copy_len;
  124|  2.94k|        }
  125|  13.0k|        if (insert_len) {
  ------------------
  |  Branch (125:13): [True: 8.40k, False: 4.63k]
  ------------------
  126|  8.40k|            if (output_written + insert_len > output_len) {
  ------------------
  |  Branch (126:17): [True: 20, False: 8.38k]
  ------------------
  127|     20|                return -1;
  128|     20|            }
  129|  8.38k|            if (output) {
  ------------------
  |  Branch (129:17): [True: 8.38k, False: 0]
  ------------------
  130|  8.38k|                memset(&output[output_written], insert_byte, insert_len);
  131|  8.38k|            }
  132|  8.38k|            output_written += insert_len;
  133|  8.38k|        }
  134|  13.0k|    }
  135|       |
  136|    165|    return output_written;
  137|    273|}

rt_open_handler:
    8|  3.27k|int rt_open_handler(const char *path, void *io_ctx) {
    9|  3.27k|    return 0;
   10|  3.27k|}
rt_close_handler:
   12|  3.27k|int rt_close_handler(void *io_ctx) {
   13|  3.27k|    return 0;
   14|  3.27k|}
rt_seek_handler:
   17|  31.2k|        readstat_io_flags_t whence, void *io_ctx) {
   18|  31.2k|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   19|  31.2k|    readstat_off_t newpos = -1;
   20|  31.2k|    if (whence == READSTAT_SEEK_SET) {
  ------------------
  |  Branch (20:9): [True: 18.8k, False: 12.3k]
  ------------------
   21|  18.8k|        newpos = offset;
   22|  18.8k|    } else if (whence == READSTAT_SEEK_CUR) {
  ------------------
  |  Branch (22:16): [True: 9.11k, False: 3.27k]
  ------------------
   23|  9.11k|        newpos = buffer_ctx->pos + offset;
   24|  9.11k|    } else if (whence == READSTAT_SEEK_END) {
  ------------------
  |  Branch (24:16): [True: 3.27k, False: 0]
  ------------------
   25|  3.27k|        newpos = buffer_ctx->buffer->used + offset;
   26|  3.27k|    }
   27|       |
   28|  31.2k|    if (newpos < 0)
  ------------------
  |  Branch (28:9): [True: 148, False: 31.0k]
  ------------------
   29|    148|        return -1;
   30|       |
   31|  31.0k|    if (newpos > buffer_ctx->buffer->used)
  ------------------
  |  Branch (31:9): [True: 255, False: 30.8k]
  ------------------
   32|    255|        return -1;
   33|       |
   34|  30.8k|    buffer_ctx->pos = newpos;
   35|  30.8k|    return newpos;
   36|  31.0k|}
rt_read_handler:
   38|  43.5k|ssize_t rt_read_handler(void *buf, size_t nbytes, void *io_ctx) {
   39|  43.5k|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   40|  43.5k|    ssize_t bytes_copied = 0;
   41|  43.5k|    ssize_t bytes_left = buffer_ctx->buffer->used - buffer_ctx->pos;
   42|  43.5k|    if (nbytes <= bytes_left) {
  ------------------
  |  Branch (42:9): [True: 43.1k, False: 384]
  ------------------
   43|  43.1k|        memcpy(buf, buffer_ctx->buffer->bytes + buffer_ctx->pos, nbytes);
   44|  43.1k|        bytes_copied = nbytes;
   45|  43.1k|    } else if (bytes_left > 0) {
  ------------------
  |  Branch (45:16): [True: 141, False: 243]
  ------------------
   46|    141|        memcpy(buf, buffer_ctx->buffer->bytes + buffer_ctx->pos, bytes_left);
   47|    141|        bytes_copied = bytes_left;
   48|    141|    }
   49|  43.5k|    buffer_ctx->pos += bytes_copied;
   50|  43.5k|    return bytes_copied;
   51|  43.5k|}
rt_update_handler:
   54|  4.52k|        void *user_ctx, void *io_ctx) {
   55|  4.52k|    if (!progress_handler)
  ------------------
  |  Branch (55:9): [True: 4.52k, False: 0]
  ------------------
   56|  4.52k|        return READSTAT_OK;
   57|       |
   58|      0|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   59|       |
   60|      0|    if (progress_handler(1.0 * buffer_ctx->pos / buffer_ctx->buffer->used, user_ctx))
  ------------------
  |  Branch (60:9): [True: 0, False: 0]
  ------------------
   61|      0|        return READSTAT_ERROR_USER_ABORT;
   62|       |
   63|      0|    return READSTAT_OK;
   64|      0|}

