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

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

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

readstat_convert:
    7|  23.3M|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|  23.4M|    while (src_len && (src[src_len-1] == ' ' || src[src_len-1] == '\0')) {
  ------------------
  |  Branch (10:12): [True: 64.4k, False: 23.3M]
  |  Branch (10:24): [True: 3.70k, False: 60.7k]
  |  Branch (10:49): [True: 37.5k, False: 23.1k]
  ------------------
   11|  41.2k|        src_len--;
   12|  41.2k|    }
   13|  23.3M|    if (dst_len == 0) {
  ------------------
  |  Branch (13:9): [True: 0, False: 23.3M]
  ------------------
   14|      0|        return READSTAT_ERROR_CONVERT_LONG_STRING;
   15|  23.3M|    } else if (converter) {
  ------------------
  |  Branch (15:16): [True: 23.1M, False: 267k]
  ------------------
   16|  23.1M|        size_t dst_left = dst_len - 1;
   17|  23.1M|        char *dst_end = dst;
   18|  23.1M|        size_t status = iconv(converter, (readstat_iconv_inbuf_t)&src, &src_len, &dst_end, &dst_left);
   19|  23.1M|        if (status == (size_t)-1) {
  ------------------
  |  Branch (19:13): [True: 2.13k, False: 23.1M]
  ------------------
   20|  2.13k|            if (errno == E2BIG) {
  ------------------
  |  Branch (20:17): [True: 5, False: 2.13k]
  ------------------
   21|      5|                return READSTAT_ERROR_CONVERT_LONG_STRING;
   22|  2.13k|            } else if (errno == EILSEQ) {
  ------------------
  |  Branch (22:24): [True: 25, False: 2.10k]
  ------------------
   23|     25|                return READSTAT_ERROR_CONVERT_BAD_STRING;
   24|  2.10k|            } else if (errno != EINVAL) { /* EINVAL indicates improper truncation; accept it */
  ------------------
  |  Branch (24:24): [True: 0, False: 2.10k]
  ------------------
   25|      0|                return READSTAT_ERROR_CONVERT;
   26|      0|            }
   27|  2.13k|        }
   28|  23.1M|        dst[dst_len - dst_left - 1] = '\0';
   29|  23.1M|    } else if (src_len + 1 > dst_len) {
  ------------------
  |  Branch (29:16): [True: 20, False: 267k]
  ------------------
   30|     20|        return READSTAT_ERROR_CONVERT_LONG_STRING;
   31|   267k|    } else {
   32|   267k|        memcpy(dst, src, src_len);
   33|   267k|        dst[src_len] = '\0';
   34|   267k|    }
   35|  23.3M|    return READSTAT_OK;
   36|  23.3M|}

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

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

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

sas_read8:
  139|  49.4k|uint64_t sas_read8(const char *data, int bswap) {
  140|  49.4k|    uint64_t tmp;
  141|  49.4k|    memcpy(&tmp, data, 8);
  142|  49.4k|    return bswap ? byteswap8(tmp) : tmp;
  ------------------
  |  Branch (142:12): [True: 44.4k, False: 5.03k]
  ------------------
  143|  49.4k|}
sas_read4:
  145|   225k|uint32_t sas_read4(const char *data, int bswap) {
  146|   225k|    uint32_t tmp;
  147|   225k|    memcpy(&tmp, data, 4);
  148|   225k|    return bswap ? byteswap4(tmp) : tmp;
  ------------------
  |  Branch (148:12): [True: 175k, False: 50.4k]
  ------------------
  149|   225k|}
sas_read2:
  151|   200k|uint16_t sas_read2(const char *data, int bswap) {
  152|   200k|    uint16_t tmp;
  153|   200k|    memcpy(&tmp, data, 2);
  154|   200k|    return bswap ? byteswap2(tmp) : tmp;
  ------------------
  |  Branch (154:12): [True: 79.7k, False: 120k]
  ------------------
  155|   200k|}
sas_subheader_remainder:
  157|  6.12k|size_t sas_subheader_remainder(size_t len, size_t signature_len) {
  158|  6.12k|    return len - (4+2*signature_len);
  159|  6.12k|}
sas_read_header:
  162|  3.75k|        readstat_error_handler error_handler, void *user_ctx) {
  163|  3.75k|    sas_header_start_t  header_start;
  164|  3.75k|    sas_header_end_t    header_end;
  165|  3.75k|    int retval = READSTAT_OK;
  166|  3.75k|    char error_buf[1024];
  167|  3.75k|    time_t epoch = sas_epoch();
  168|       |
  169|  3.75k|    if (io->read(&header_start, sizeof(sas_header_start_t), io->io_ctx) < sizeof(sas_header_start_t)) {
  ------------------
  |  Branch (169:9): [True: 20, False: 3.73k]
  ------------------
  170|     20|        retval = READSTAT_ERROR_READ;
  171|     20|        goto cleanup;
  172|     20|    }
  173|  3.73k|    if (memcmp(header_start.magic, sas7bdat_magic_number, sizeof(sas7bdat_magic_number)) != 0 &&
  ------------------
  |  Branch (173:9): [True: 1.70k, False: 2.02k]
  ------------------
  174|  1.70k|            memcmp(header_start.magic, sas7bcat_magic_number, sizeof(sas7bcat_magic_number)) != 0) {
  ------------------
  |  Branch (174:13): [True: 131, False: 1.57k]
  ------------------
  175|    131|        retval = READSTAT_ERROR_PARSE;
  176|    131|        goto cleanup;
  177|    131|    }
  178|  3.60k|    if (header_start.a1 == SAS_ALIGNMENT_OFFSET_4) {
  ------------------
  |  |   87|  3.60k|#define SAS_ALIGNMENT_OFFSET_4  0x33
  ------------------
  |  Branch (178:9): [True: 9, False: 3.59k]
  ------------------
  179|      9|        hinfo->pad1 = 4;
  180|      9|    }
  181|  3.60k|    if (header_start.a2 == SAS_ALIGNMENT_OFFSET_4) {
  ------------------
  |  |   87|  3.60k|#define SAS_ALIGNMENT_OFFSET_4  0x33
  ------------------
  |  Branch (181:9): [True: 1.67k, False: 1.92k]
  ------------------
  182|  1.67k|        hinfo->u64 = 1;
  183|  1.67k|    }
  184|  3.60k|    int bswap = 0;
  185|  3.60k|    if (header_start.endian == SAS_ENDIAN_BIG) {
  ------------------
  |  |   80|  3.60k|#define SAS_ENDIAN_BIG       0x00
  ------------------
  |  Branch (185:9): [True: 2.94k, False: 657]
  ------------------
  186|  2.94k|        bswap = machine_is_little_endian();
  187|  2.94k|        hinfo->little_endian = 0;
  188|  2.94k|    } else if (header_start.endian == SAS_ENDIAN_LITTLE) {
  ------------------
  |  |   81|    657|#define SAS_ENDIAN_LITTLE    0x01
  ------------------
  |  Branch (188:16): [True: 645, False: 12]
  ------------------
  189|    645|        bswap = !machine_is_little_endian();
  190|    645|        hinfo->little_endian = 1;
  191|    645|    } else {
  192|     12|        retval = READSTAT_ERROR_PARSE;
  193|     12|        goto cleanup;
  194|     12|    }
  195|  3.59k|    int i;
  196|  24.0k|    for (i=0; i<sizeof(_charset_table)/sizeof(_charset_table[0]); i++) {
  ------------------
  |  Branch (196:15): [True: 24.0k, False: 4]
  ------------------
  197|  24.0k|        if (header_start.encoding == _charset_table[i].code) {
  ------------------
  |  Branch (197:13): [True: 3.58k, False: 20.4k]
  ------------------
  198|  3.58k|            hinfo->encoding = _charset_table[i].name;
  199|  3.58k|            break;
  200|  3.58k|        }
  201|  24.0k|    }
  202|  3.59k|    if (hinfo->encoding == NULL) {
  ------------------
  |  Branch (202:9): [True: 4, False: 3.58k]
  ------------------
  203|      4|        if (error_handler) {
  ------------------
  |  Branch (203:13): [True: 0, False: 4]
  ------------------
  204|      0|            snprintf(error_buf, sizeof(error_buf), "Unsupported character set code: %d", header_start.encoding);
  205|      0|            error_handler(error_buf, user_ctx);
  206|      0|        }
  207|      4|        retval = READSTAT_ERROR_UNSUPPORTED_CHARSET;
  208|      4|        goto cleanup;
  209|      4|    }
  210|  3.58k|    memcpy(hinfo->table_name, header_start.table_name, sizeof(header_start.table_name));
  211|  3.58k|    if (io->seek(hinfo->pad1, READSTAT_SEEK_CUR, io->io_ctx) == -1) {
  ------------------
  |  Branch (211:9): [True: 5, False: 3.58k]
  ------------------
  212|      5|        retval = READSTAT_ERROR_SEEK;
  213|      5|        goto cleanup;
  214|      5|    }
  215|       |
  216|  3.58k|    double creation_time, modification_time, creation_time_diff, modification_time_diff;
  217|       |
  218|  3.58k|    if (io->read(&creation_time, sizeof(double), io->io_ctx) < sizeof(double)) {
  ------------------
  |  Branch (218:9): [True: 18, False: 3.56k]
  ------------------
  219|     18|        retval = READSTAT_ERROR_READ;
  220|     18|        goto cleanup;
  221|     18|    }
  222|  3.56k|    if (bswap)
  ------------------
  |  Branch (222:9): [True: 2.92k, False: 643]
  ------------------
  223|  2.92k|        creation_time = byteswap_double(creation_time);
  224|       |
  225|  3.56k|    if (io->read(&modification_time, sizeof(double), io->io_ctx) < sizeof(double)) {
  ------------------
  |  Branch (225:9): [True: 6, False: 3.55k]
  ------------------
  226|      6|        retval = READSTAT_ERROR_READ;
  227|      6|        goto cleanup;
  228|      6|    }
  229|  3.55k|    if (bswap)
  ------------------
  |  Branch (229:9): [True: 2.91k, False: 640]
  ------------------
  230|  2.91k|        modification_time = byteswap_double(modification_time);
  231|       |
  232|  3.55k|    if (io->read(&creation_time_diff, sizeof(double), io->io_ctx) < sizeof(double)) {
  ------------------
  |  Branch (232:9): [True: 6, False: 3.55k]
  ------------------
  233|      6|        retval = READSTAT_ERROR_READ;
  234|      6|        goto cleanup;
  235|      6|    }
  236|  3.55k|    if (bswap)
  ------------------
  |  Branch (236:9): [True: 2.91k, False: 638]
  ------------------
  237|  2.91k|        creation_time_diff = byteswap_double(creation_time_diff);
  238|       |    
  239|  3.55k|    if (io->read(&modification_time_diff, sizeof(double), io->io_ctx) < sizeof(double)) {
  ------------------
  |  Branch (239:9): [True: 6, False: 3.54k]
  ------------------
  240|      6|        retval = READSTAT_ERROR_READ;
  241|      6|        goto cleanup;
  242|      6|    }
  243|  3.54k|    if (bswap)
  ------------------
  |  Branch (243:9): [True: 2.91k, False: 636]
  ------------------
  244|  2.91k|        modification_time_diff = byteswap_double(modification_time_diff);
  245|       |    
  246|  3.54k|    hinfo->creation_time = sas_convert_time(creation_time, creation_time_diff, epoch);
  247|  3.54k|    hinfo->modification_time = sas_convert_time(modification_time, modification_time_diff, epoch);
  248|       |
  249|  3.54k|    uint32_t header_size, page_size;
  250|       |
  251|  3.54k|    if (io->read(&header_size, sizeof(uint32_t), io->io_ctx) < sizeof(uint32_t)) {
  ------------------
  |  Branch (251:9): [True: 9, False: 3.53k]
  ------------------
  252|      9|        retval = READSTAT_ERROR_READ;
  253|      9|        goto cleanup;
  254|      9|    }
  255|  3.53k|    if (io->read(&page_size, sizeof(uint32_t), io->io_ctx) < sizeof(uint32_t)) {
  ------------------
  |  Branch (255:9): [True: 3, False: 3.53k]
  ------------------
  256|      3|        retval = READSTAT_ERROR_READ;
  257|      3|        goto cleanup;
  258|      3|    }
  259|       |
  260|  3.53k|    hinfo->header_size = bswap ? byteswap4(header_size) : header_size;
  ------------------
  |  Branch (260:26): [True: 2.90k, False: 633]
  ------------------
  261|  3.53k|    hinfo->page_size = bswap ? byteswap4(page_size) : page_size;
  ------------------
  |  Branch (261:24): [True: 2.90k, False: 633]
  ------------------
  262|       |
  263|  3.53k|    if (hinfo->header_size < 1024 || hinfo->page_size < 1024) {
  ------------------
  |  Branch (263:9): [True: 13, False: 3.52k]
  |  Branch (263:38): [True: 13, False: 3.50k]
  ------------------
  264|     26|        retval = READSTAT_ERROR_PARSE;
  265|     26|        goto cleanup;
  266|     26|    }
  267|  3.50k|    if (hinfo->header_size > (1<<24) || hinfo->page_size > (1<<24)) {
  ------------------
  |  Branch (267:9): [True: 23, False: 3.48k]
  |  Branch (267:41): [True: 30, False: 3.45k]
  ------------------
  268|     53|        retval = READSTAT_ERROR_PARSE;
  269|     53|        goto cleanup;
  270|     53|    }
  271|       |
  272|  3.45k|    if (hinfo->u64) {
  ------------------
  |  Branch (272:9): [True: 1.62k, False: 1.83k]
  ------------------
  273|  1.62k|        hinfo->page_header_size = SAS_PAGE_HEADER_SIZE_64BIT;
  ------------------
  |  |  121|  1.62k|#define SAS_PAGE_HEADER_SIZE_64BIT  40
  ------------------
  274|  1.62k|        hinfo->subheader_pointer_size = SAS_SUBHEADER_POINTER_SIZE_64BIT;
  ------------------
  |  |  118|  1.62k|#define SAS_SUBHEADER_POINTER_SIZE_64BIT    24
  ------------------
  275|  1.83k|    } else {
  276|  1.83k|        hinfo->page_header_size = SAS_PAGE_HEADER_SIZE_32BIT;
  ------------------
  |  |  120|  1.83k|#define SAS_PAGE_HEADER_SIZE_32BIT  24
  ------------------
  277|  1.83k|        hinfo->subheader_pointer_size = SAS_SUBHEADER_POINTER_SIZE_32BIT;
  ------------------
  |  |  117|  1.83k|#define SAS_SUBHEADER_POINTER_SIZE_32BIT    12
  ------------------
  278|  1.83k|    }
  279|       |
  280|  3.45k|    if (hinfo->u64) {
  ------------------
  |  Branch (280:9): [True: 1.62k, False: 1.83k]
  ------------------
  281|  1.62k|        uint64_t page_count;
  282|  1.62k|        if (io->read(&page_count, sizeof(uint64_t), io->io_ctx) < sizeof(uint64_t)) {
  ------------------
  |  Branch (282:13): [True: 17, False: 1.60k]
  ------------------
  283|     17|            retval = READSTAT_ERROR_READ;
  284|     17|            goto cleanup;
  285|     17|        }
  286|  1.60k|        hinfo->page_count = bswap ? byteswap8(page_count) : page_count;
  ------------------
  |  Branch (286:29): [True: 1.51k, False: 90]
  ------------------
  287|  1.83k|    } else {
  288|  1.83k|        uint32_t page_count;
  289|  1.83k|        if (io->read(&page_count, sizeof(uint32_t), io->io_ctx) < sizeof(uint32_t)) {
  ------------------
  |  Branch (289:13): [True: 19, False: 1.81k]
  ------------------
  290|     19|            retval = READSTAT_ERROR_READ;
  291|     19|            goto cleanup;
  292|     19|        }
  293|  1.81k|        hinfo->page_count = bswap ? byteswap4(page_count) : page_count;
  ------------------
  |  Branch (293:29): [True: 1.28k, False: 524]
  ------------------
  294|  1.81k|    }
  295|  3.42k|    if (hinfo->page_count > (1<<24)) {
  ------------------
  |  Branch (295:9): [True: 16, False: 3.40k]
  ------------------
  296|     16|        retval = READSTAT_ERROR_PARSE;
  297|     16|        goto cleanup;
  298|     16|    }
  299|       |    
  300|  3.40k|    if (io->seek(8, READSTAT_SEEK_CUR, io->io_ctx) == -1) {
  ------------------
  |  Branch (300:9): [True: 81, False: 3.32k]
  ------------------
  301|     81|        retval = READSTAT_ERROR_SEEK;
  302|     81|        if (error_handler) {
  ------------------
  |  Branch (302:13): [True: 0, False: 81]
  ------------------
  303|      0|            snprintf(error_buf, sizeof(error_buf), "ReadStat: Failed to seek forward by %d", 8);
  304|      0|            error_handler(error_buf, user_ctx);
  305|      0|        }
  306|     81|        goto cleanup;
  307|     81|    }
  308|  3.32k|    if (io->read(&header_end, sizeof(sas_header_end_t), io->io_ctx) < sizeof(sas_header_end_t)) {
  ------------------
  |  Branch (308:9): [True: 17, False: 3.30k]
  ------------------
  309|     17|        retval = READSTAT_ERROR_READ;
  310|     17|        goto cleanup;
  311|     17|    }
  312|  3.30k|    char major, revision_tag;
  313|  3.30k|    int minor, revision;
  314|  3.30k|    if (sscanf(header_end.release, "%c.%04d%c%1d", &major, &minor, &revision_tag, &revision) != 4) {
  ------------------
  |  Branch (314:9): [True: 4, False: 3.30k]
  ------------------
  315|      4|        retval = READSTAT_ERROR_PARSE;
  316|      4|        goto cleanup;
  317|      4|    }
  318|       |
  319|  3.30k|    if (major >= '1' && major <= '9') {
  ------------------
  |  Branch (319:9): [True: 3.28k, False: 14]
  |  Branch (319:25): [True: 3.27k, False: 9]
  ------------------
  320|  3.27k|        hinfo->major_version = major - '0';
  321|  3.27k|    } else if (major == 'V') {
  ------------------
  |  Branch (321:16): [True: 1, False: 22]
  ------------------
  322|       |        // It appears that SAS Visual Forecaster reports the major version as "V"
  323|       |        // Treat it as version 9 for all intents and purposes
  324|      1|        hinfo->major_version = 9;
  325|     22|    } else {
  326|     22|        retval = READSTAT_ERROR_PARSE;
  327|     22|        goto cleanup;
  328|     22|    }
  329|       |    // revision_tag is usually M, but J has been observed in the wild (not created with SAS?)
  330|  3.28k|    if (revision_tag != 'M' && revision_tag != 'J') {
  ------------------
  |  Branch (330:9): [True: 26, False: 3.25k]
  |  Branch (330:32): [True: 15, False: 11]
  ------------------
  331|     15|        retval = READSTAT_ERROR_PARSE;
  332|     15|        goto cleanup;
  333|     15|    }
  334|  3.26k|    hinfo->minor_version = minor;
  335|  3.26k|    hinfo->revision = revision;
  336|       |
  337|  3.26k|    if ((major == '8' || major == '9') && minor == 0 && revision == 0) {
  ------------------
  |  Branch (337:10): [True: 311, False: 2.95k]
  |  Branch (337:26): [True: 126, False: 2.82k]
  |  Branch (337:43): [True: 77, False: 360]
  |  Branch (337:57): [True: 58, False: 19]
  ------------------
  338|       |        /* A bit of a hack, but most SAS installations are running a minor update */
  339|     58|        hinfo->vendor = READSTAT_VENDOR_STAT_TRANSFER;
  340|  3.20k|    } else {
  341|  3.20k|        hinfo->vendor = READSTAT_VENDOR_SAS;
  342|  3.20k|    }
  343|  3.26k|    if (io->seek(hinfo->header_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (343:9): [True: 57, False: 3.20k]
  ------------------
  344|     57|        retval = READSTAT_ERROR_SEEK;
  345|     57|        if (error_handler) {
  ------------------
  |  Branch (345:13): [True: 0, False: 57]
  ------------------
  346|      0|            snprintf(error_buf, sizeof(error_buf), 
  347|      0|                    "ReadStat: Failed to seek to position %" PRId64, hinfo->header_size);
  348|      0|            error_handler(error_buf, user_ctx);
  349|      0|        }
  350|     57|        goto cleanup;
  351|     57|    }
  352|       |
  353|  3.75k|cleanup:
  354|  3.75k|    return retval;
  355|  3.26k|}
sas_validate_tag:
  507|  13.6k|readstat_error_t sas_validate_tag(char tag) {
  508|  13.6k|    if (tag == '_' || (tag >= 'A' && tag <= 'Z'))
  ------------------
  |  Branch (508:9): [True: 7.09k, False: 6.60k]
  |  Branch (508:24): [True: 1.75k, False: 4.84k]
  |  Branch (508:38): [True: 1.24k, False: 504]
  ------------------
  509|  8.34k|        return READSTAT_OK;
  510|       |
  511|  5.35k|    return READSTAT_ERROR_TAGGED_VALUE_IS_OUT_OF_RANGE;
  512|  13.6k|}
sas_assign_tag:
  514|  13.6k|void sas_assign_tag(readstat_value_t *value, uint8_t tag) {
  515|       |    /* We accommodate two tag schemes. In the first, the tag is an ASCII code
  516|       |     * given by uint8_t tag above. System missing is represented by an ASCII
  517|       |     * period. In the second scheme, (tag-2) is an offset from 'A', except when
  518|       |     * tag == 0, in which case it represents an underscore, or tag == 1, in
  519|       |     * which case it represents system-missing.
  520|       |     */
  521|  13.6k|    if (tag == 0) {
  ------------------
  |  Branch (521:9): [True: 7.09k, False: 6.60k]
  ------------------
  522|  7.09k|        tag = '_';
  523|  7.09k|    } else if (tag >= 2 && tag < 28) {
  ------------------
  |  Branch (523:16): [True: 5.59k, False: 1.01k]
  |  Branch (523:28): [True: 1.17k, False: 4.41k]
  ------------------
  524|  1.17k|        tag = 'A' + (tag - 2);
  525|  1.17k|    }
  526|  13.6k|    if (sas_validate_tag(tag) == READSTAT_OK) {
  ------------------
  |  Branch (526:9): [True: 8.34k, False: 5.35k]
  ------------------
  527|  8.34k|        value->tag = tag;
  528|  8.34k|        value->is_tagged_missing = 1;
  529|  8.34k|    } else {
  530|  5.35k|        value->tag = 0;
  531|  5.35k|        value->is_system_missing = 1;
  532|  5.35k|    }
  533|  13.6k|}
readstat_sas.c:sas_epoch:
  123|  3.75k|static time_t sas_epoch(void) {
  124|  3.75k|    return - 3653 * 86400; // seconds between 01-01-1960 and 01-01-1970
  125|  3.75k|}
readstat_sas.c:sas_convert_time:
  127|  7.09k|static time_t sas_convert_time(double time, double time_diff, time_t epoch) {
  128|  7.09k|    time -= time_diff;
  129|  7.09k|    time += epoch;
  130|  7.09k|    if (isnan(time))
  ------------------
  |  Branch (130:9): [True: 867, False: 6.22k]
  ------------------
  131|    867|        return 0;
  132|  6.22k|    if (time > (double)LONG_MAX)
  ------------------
  |  Branch (132:9): [True: 1.79k, False: 4.43k]
  ------------------
  133|  1.79k|        return LONG_MAX;
  134|  4.43k|    if (time < (double)LONG_MIN)
  ------------------
  |  Branch (134:9): [True: 1.34k, False: 3.09k]
  ------------------
  135|  1.34k|        return LONG_MIN;
  136|  3.09k|    return time;
  137|  4.43k|}

readstat_parse_sas7bdat:
 1206|  3.75k|readstat_error_t readstat_parse_sas7bdat(readstat_parser_t *parser, const char *path, void *user_ctx) {
 1207|  3.75k|    int64_t last_examined_page_pass1 = 0;
 1208|  3.75k|    readstat_error_t retval = READSTAT_OK;
 1209|  3.75k|    readstat_io_t *io = parser->io;
 1210|       |
 1211|  3.75k|    sas7bdat_ctx_t  *ctx = calloc(1, sizeof(sas7bdat_ctx_t));
 1212|  3.75k|    sas_header_info_t  *hinfo = calloc(1, sizeof(sas_header_info_t));
 1213|       |
 1214|  3.75k|    ctx->handle = parser->handlers;
 1215|  3.75k|    ctx->input_encoding = parser->input_encoding;
 1216|  3.75k|    ctx->output_encoding = parser->output_encoding;
 1217|  3.75k|    ctx->user_ctx = user_ctx;
 1218|  3.75k|    ctx->io = parser->io;
 1219|  3.75k|    ctx->row_limit = parser->row_limit;
 1220|  3.75k|    if (parser->row_offset > 0)
  ------------------
  |  Branch (1220:9): [True: 0, False: 3.75k]
  ------------------
 1221|      0|        ctx->row_offset = parser->row_offset;
 1222|       |
 1223|  3.75k|    if (io->open(path, io->io_ctx) == -1) {
  ------------------
  |  Branch (1223:9): [True: 0, False: 3.75k]
  ------------------
 1224|      0|        retval = READSTAT_ERROR_OPEN;
 1225|      0|        goto cleanup;
 1226|      0|    }
 1227|       |
 1228|  3.75k|    if ((ctx->file_size = io->seek(0, READSTAT_SEEK_END, io->io_ctx)) == -1) {
  ------------------
  |  Branch (1228:9): [True: 0, False: 3.75k]
  ------------------
 1229|      0|        retval = READSTAT_ERROR_SEEK;
 1230|      0|        if (ctx->handle.error) {
  ------------------
  |  Branch (1230:13): [True: 0, False: 0]
  ------------------
 1231|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to end of file");
 1232|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1233|      0|        }
 1234|      0|        goto cleanup;
 1235|      0|    }
 1236|       |
 1237|  3.75k|    if (io->seek(0, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1237:9): [True: 0, False: 3.75k]
  ------------------
 1238|      0|        retval = READSTAT_ERROR_SEEK;
 1239|      0|        if (ctx->handle.error) {
  ------------------
  |  Branch (1239:13): [True: 0, False: 0]
  ------------------
 1240|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to beginning of file");
 1241|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1242|      0|        }
 1243|      0|        goto cleanup;
 1244|      0|    }
 1245|       |
 1246|  3.75k|    if ((retval = sas_read_header(io, hinfo, ctx->handle.error, user_ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1246:9): [True: 547, False: 3.20k]
  ------------------
 1247|    547|        goto cleanup;
 1248|    547|    }
 1249|       |
 1250|  3.20k|    ctx->u64 = hinfo->u64;
 1251|  3.20k|    ctx->little_endian = hinfo->little_endian;
 1252|  3.20k|    ctx->vendor = hinfo->vendor;
 1253|  3.20k|    ctx->bswap = machine_is_little_endian() ^ hinfo->little_endian;
 1254|  3.20k|    ctx->header_size = hinfo->header_size;
 1255|  3.20k|    ctx->page_count = hinfo->page_count;
 1256|  3.20k|    ctx->page_size = hinfo->page_size;
 1257|  3.20k|    ctx->page_header_size = hinfo->page_header_size;
 1258|  3.20k|    ctx->subheader_pointer_size = hinfo->subheader_pointer_size;
 1259|  3.20k|    ctx->subheader_signature_size = ctx->u64 ? 8 : 4;
  ------------------
  |  Branch (1259:37): [True: 1.54k, False: 1.66k]
  ------------------
 1260|  3.20k|    ctx->ctime = hinfo->creation_time;
 1261|  3.20k|    ctx->mtime = hinfo->modification_time;
 1262|  3.20k|    ctx->version = hinfo->major_version;
 1263|  3.20k|    if (ctx->input_encoding == NULL) {
  ------------------
  |  Branch (1263:9): [True: 3.20k, False: 0]
  ------------------
 1264|  3.20k|        ctx->input_encoding = hinfo->encoding;
 1265|  3.20k|    }
 1266|  3.20k|    if ((ctx->page = readstat_malloc(ctx->page_size)) == NULL) {
  ------------------
  |  Branch (1266:9): [True: 0, False: 3.20k]
  ------------------
 1267|      0|        retval = READSTAT_ERROR_MALLOC;
 1268|      0|        goto cleanup;
 1269|      0|    }
 1270|       |
 1271|  3.20k|    if (ctx->input_encoding && ctx->output_encoding && strcmp(ctx->input_encoding, ctx->output_encoding) != 0) {
  ------------------
  |  Branch (1271:9): [True: 3.20k, False: 0]
  |  Branch (1271:32): [True: 3.20k, False: 0]
  |  Branch (1271:56): [True: 2.31k, False: 893]
  ------------------
 1272|  2.31k|        iconv_t converter = iconv_open(ctx->output_encoding, ctx->input_encoding);
 1273|  2.31k|        if (converter == (iconv_t)-1) {
  ------------------
  |  Branch (1273:13): [True: 1, False: 2.31k]
  ------------------
 1274|      1|            retval = READSTAT_ERROR_UNSUPPORTED_CHARSET;
 1275|      1|            goto cleanup;
 1276|      1|        }
 1277|  2.31k|        ctx->converter = converter;
 1278|  2.31k|    }
 1279|       |
 1280|  3.20k|    if ((retval = readstat_convert(ctx->table_name, sizeof(ctx->table_name),
  ------------------
  |  Branch (1280:9): [True: 5, False: 3.20k]
  ------------------
 1281|  3.20k|                hinfo->table_name, sizeof(hinfo->table_name), ctx->converter)) != READSTAT_OK) {
 1282|      5|        goto cleanup;
 1283|      5|    }
 1284|       |
 1285|  3.20k|    if ((retval = sas7bdat_parse_meta_pages_pass1(ctx, &last_examined_page_pass1)) != READSTAT_OK) {
  ------------------
  |  Branch (1285:9): [True: 233, False: 2.96k]
  ------------------
 1286|    233|        goto cleanup;
 1287|    233|    }
 1288|       |
 1289|  2.96k|    if ((retval = sas7bdat_parse_amd_pages_pass1(last_examined_page_pass1, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1289:9): [True: 1.03k, False: 1.93k]
  ------------------
 1290|  1.03k|        goto cleanup;
 1291|  1.03k|    }
 1292|       |
 1293|  1.93k|    if (io->seek(ctx->header_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1293:9): [True: 0, False: 1.93k]
  ------------------
 1294|      0|        retval = READSTAT_ERROR_SEEK;
 1295|      0|        if (ctx->handle.error) {
  ------------------
  |  Branch (1295:13): [True: 0, False: 0]
  ------------------
 1296|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to position %" PRId64, 
 1297|      0|                    ctx->header_size);
 1298|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1299|      0|        }
 1300|      0|        goto cleanup;
 1301|      0|    }
 1302|       |
 1303|  1.93k|    if ((retval = sas7bdat_parse_all_pages_pass2(ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1303:9): [True: 1.58k, False: 343]
  ------------------
 1304|  1.58k|        goto cleanup;
 1305|  1.58k|    }
 1306|       |    
 1307|    343|    if ((retval = sas7bdat_submit_columns_if_needed(ctx, 0)) != READSTAT_OK) {
  ------------------
  |  Branch (1307:9): [True: 77, False: 266]
  ------------------
 1308|     77|        goto cleanup;
 1309|     77|    }
 1310|       |
 1311|    266|    if (ctx->handle.value && ctx->parsed_row_count != ctx->row_limit) {
  ------------------
  |  Branch (1311:9): [True: 266, False: 0]
  |  Branch (1311:30): [True: 110, False: 156]
  ------------------
 1312|    110|        retval = READSTAT_ERROR_ROW_COUNT_MISMATCH;
 1313|    110|        if (ctx->handle.error) {
  ------------------
  |  Branch (1313:13): [True: 0, False: 110]
  ------------------
 1314|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Expected %d rows in file, found %d",
 1315|      0|                    ctx->row_limit, ctx->parsed_row_count);
 1316|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1317|      0|        }
 1318|    110|        goto cleanup;
 1319|    110|    }
 1320|       |
 1321|    156|    if ((retval = sas7bdat_update_progress(ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1321:9): [True: 0, False: 156]
  ------------------
 1322|      0|        goto cleanup;
 1323|      0|    }
 1324|       |
 1325|  3.75k|cleanup:
 1326|  3.75k|    io->close(io->io_ctx);
 1327|       |
 1328|  3.75k|    if (retval == READSTAT_ERROR_OPEN ||
  ------------------
  |  Branch (1328:9): [True: 0, False: 3.75k]
  ------------------
 1329|  3.75k|            retval == READSTAT_ERROR_READ ||
  ------------------
  |  Branch (1329:13): [True: 451, False: 3.30k]
  ------------------
 1330|  3.30k|            retval == READSTAT_ERROR_SEEK) {
  ------------------
  |  Branch (1330:13): [True: 377, False: 2.92k]
  ------------------
 1331|    828|        if (ctx->handle.error) {
  ------------------
  |  Branch (1331:13): [True: 0, False: 828]
  ------------------
 1332|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: %s (retval = %d): %s (errno = %d)", 
 1333|      0|                    readstat_error_message(retval), retval, strerror(errno), errno);
 1334|      0|            ctx->handle.error(ctx->error_buf, user_ctx);
 1335|      0|        }
 1336|    828|    }
 1337|       |
 1338|  3.75k|    if (ctx)
  ------------------
  |  Branch (1338:9): [True: 3.75k, False: 0]
  ------------------
 1339|  3.75k|        sas7bdat_ctx_free(ctx);
 1340|  3.75k|    if (hinfo)
  ------------------
  |  Branch (1340:9): [True: 3.75k, False: 0]
  ------------------
 1341|  3.75k|        free(hinfo);
 1342|       |
 1343|  3.75k|    return retval;
 1344|    156|}
readstat_sas7bdat_read.c:sas7bdat_parse_meta_pages_pass1:
 1047|  3.20k|static readstat_error_t sas7bdat_parse_meta_pages_pass1(sas7bdat_ctx_t *ctx, int64_t *outLastExaminedPage) {
 1048|  3.20k|    readstat_error_t retval = READSTAT_OK;
 1049|  3.20k|    readstat_io_t *io = ctx->io;
 1050|  3.20k|    int64_t i;
 1051|       |
 1052|       |    /* look for META and MIX pages at beginning... */
 1053|  8.08k|    for (i=0; i<ctx->page_count; i++) {
  ------------------
  |  Branch (1053:15): [True: 5.71k, False: 2.36k]
  ------------------
 1054|  5.71k|        if (io->seek(ctx->header_size + i*ctx->page_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1054:13): [True: 8, False: 5.70k]
  ------------------
 1055|      8|            retval = READSTAT_ERROR_SEEK;
 1056|      8|            if (ctx->handle.error) {
  ------------------
  |  Branch (1056:17): [True: 0, False: 8]
  ------------------
 1057|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to position %" PRId64 
 1058|      0|                        " (= %" PRId64 " + %" PRId64 "*%" PRId64 ")",
 1059|      0|                        ctx->header_size + i*ctx->page_size, ctx->header_size, i, ctx->page_size);
 1060|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1061|      0|            }
 1062|      8|            goto cleanup;
 1063|      8|        }
 1064|       |
 1065|  5.70k|        readstat_off_t off = 0;
 1066|  5.70k|        if (ctx->u64)
  ------------------
  |  Branch (1066:13): [True: 3.74k, False: 1.96k]
  ------------------
 1067|  3.74k|            off = 16;
 1068|       |
 1069|  5.70k|        size_t head_len = off + 16 + 2;
 1070|  5.70k|        size_t tail_len = ctx->page_size - head_len;
 1071|       |
 1072|  5.70k|        if (io->read(ctx->page, head_len, io->io_ctx) < head_len) {
  ------------------
  |  Branch (1072:13): [True: 149, False: 5.55k]
  ------------------
 1073|    149|            retval = READSTAT_ERROR_READ;
 1074|    149|            goto cleanup;
 1075|    149|        }
 1076|       |
 1077|  5.55k|        uint16_t page_type = sas_read2(&ctx->page[off+16], ctx->bswap);
 1078|       |
 1079|  5.55k|        if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA)
  ------------------
  |  |  112|  5.55k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                      if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA)
  ------------------
  |  |  109|  5.55k|#define SAS_PAGE_TYPE_DATA   0x0100
  ------------------
  |  Branch (1079:13): [True: 600, False: 4.95k]
  ------------------
 1080|    600|            break;
 1081|  4.95k|        if ((page_type & SAS_PAGE_TYPE_COMP))
  ------------------
  |  |  115|  4.95k|#define SAS_PAGE_TYPE_COMP   0x9000
  ------------------
  |  Branch (1081:13): [True: 1.22k, False: 3.73k]
  ------------------
 1082|  1.22k|            continue;
 1083|       |
 1084|  3.73k|        if (io->read(ctx->page + head_len, tail_len, io->io_ctx) < tail_len) {
  ------------------
  |  Branch (1084:13): [True: 28, False: 3.70k]
  ------------------
 1085|     28|            retval = READSTAT_ERROR_READ;
 1086|     28|            goto cleanup;
 1087|     28|        }
 1088|       |
 1089|  3.70k|        if ((retval = sas7bdat_parse_page_pass1(ctx->page, ctx->page_size, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1089:13): [True: 48, False: 3.65k]
  ------------------
 1090|     48|            if (ctx->handle.error && retval != READSTAT_ERROR_USER_ABORT) {
  ------------------
  |  Branch (1090:17): [True: 0, False: 48]
  |  Branch (1090:38): [True: 0, False: 0]
  ------------------
 1091|      0|                int64_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
 1092|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
 1093|      0|                        "ReadStat: Error parsing page %" PRId64 ", bytes %" PRId64 "-%" PRId64, 
 1094|      0|                        i, pos - ctx->page_size, pos-1);
 1095|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1096|      0|            }
 1097|     48|            goto cleanup;
 1098|     48|        }
 1099|  3.70k|    }
 1100|       |
 1101|  3.20k|cleanup:
 1102|  3.20k|    if (outLastExaminedPage)
  ------------------
  |  Branch (1102:9): [True: 3.20k, False: 0]
  ------------------
 1103|  3.20k|        *outLastExaminedPage = i;
 1104|       |
 1105|  3.20k|    return retval;
 1106|  3.20k|}
readstat_sas7bdat_read.c:sas7bdat_parse_page_pass1:
  903|  6.49k|static readstat_error_t sas7bdat_parse_page_pass1(const char *page, size_t page_size, sas7bdat_ctx_t *ctx) {
  904|  6.49k|    readstat_error_t retval = READSTAT_OK;
  905|       |
  906|  6.49k|    uint16_t subheader_count = sas_read2(&page[ctx->page_header_size-4], ctx->bswap);
  907|       |
  908|  6.49k|    int i;
  909|  6.49k|    const char *shp = &page[ctx->page_header_size];
  910|  6.49k|    int lshp = ctx->subheader_pointer_size;
  911|       |
  912|  6.49k|    if (ctx->page_header_size + subheader_count*lshp > page_size) {
  ------------------
  |  Branch (912:9): [True: 34, False: 6.45k]
  ------------------
  913|     34|        retval = READSTAT_ERROR_PARSE;
  914|     34|        goto cleanup;
  915|     34|    }
  916|       |
  917|  69.3k|    for (i=0; i<subheader_count; i++) {
  ------------------
  |  Branch (917:15): [True: 63.7k, False: 5.65k]
  ------------------
  918|  63.7k|        subheader_pointer_t shp_info = { 0 };
  919|  63.7k|        if ((retval = sas7bdat_parse_subheader_pointer(shp, page + page_size - shp, &shp_info, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (919:13): [True: 0, False: 63.7k]
  ------------------
  920|      0|            goto cleanup;
  921|      0|        }
  922|  63.7k|        if (shp_info.len > 0 && shp_info.compression != SAS_COMPRESSION_TRUNC) {
  ------------------
  |  |  124|  40.6k|#define SAS_COMPRESSION_TRUNC  0x01
  ------------------
  |  Branch (922:13): [True: 40.6k, False: 23.0k]
  |  Branch (922:33): [True: 34.6k, False: 6.00k]
  ------------------
  923|  34.6k|            if ((retval = sas7bdat_validate_subheader_pointer(&shp_info, page_size, subheader_count, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (923:17): [True: 727, False: 33.9k]
  ------------------
  924|    727|                goto cleanup;
  925|    727|            }
  926|  33.9k|            if (shp_info.compression == SAS_COMPRESSION_NONE) {
  ------------------
  |  |  123|  33.9k|#define SAS_COMPRESSION_NONE   0x00
  ------------------
  |  Branch (926:17): [True: 31.2k, False: 2.63k]
  ------------------
  927|  31.2k|                sas_subheader_type_t subheader_type = sas7bdat_parse_subheader_type(page + shp_info.offset, ctx);
  928|  31.2k|                if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_TEXT) {
  ------------------
  |  Branch (928:21): [True: 2.79k, False: 28.5k]
  ------------------
  929|  2.79k|                    if ((retval = sas7bdat_parse_subheader(subheader_type, page + shp_info.offset, shp_info.len, ctx))
  ------------------
  |  Branch (929:25): [True: 58, False: 2.73k]
  ------------------
  930|  2.79k|                            != READSTAT_OK) {
  931|     58|                        goto cleanup;
  932|     58|                    }
  933|  2.79k|                }
  934|  31.2k|            } else if (shp_info.compression == SAS_COMPRESSION_ROW) {
  ------------------
  |  |  125|  2.63k|#define SAS_COMPRESSION_ROW    0x04
  ------------------
  |  Branch (934:24): [True: 2.61k, False: 17]
  ------------------
  935|       |                /* void */
  936|  2.61k|            } else {
  937|     17|                retval = READSTAT_ERROR_UNSUPPORTED_COMPRESSION;
  938|     17|                goto cleanup;
  939|     17|            }
  940|  33.9k|        }
  941|       |
  942|  62.9k|        shp += lshp;
  943|  62.9k|    }
  944|       |
  945|  6.49k|cleanup:
  946|       |
  947|  6.49k|    return retval;
  948|  6.45k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_pointer:
  857|  99.9k|        subheader_pointer_t *info, sas7bdat_ctx_t *ctx) {
  858|  99.9k|    readstat_error_t retval = READSTAT_OK;
  859|  99.9k|    if (ctx->u64) {
  ------------------
  |  Branch (859:9): [True: 17.6k, False: 82.3k]
  ------------------
  860|  17.6k|        if (shp_size <= 17) {
  ------------------
  |  Branch (860:13): [True: 0, False: 17.6k]
  ------------------
  861|      0|            retval = READSTAT_ERROR_PARSE;
  862|      0|            goto cleanup;
  863|      0|        }
  864|  17.6k|        info->offset = sas_read8(&shp[0], ctx->bswap);
  865|  17.6k|        info->len = sas_read8(&shp[8], ctx->bswap);
  866|  17.6k|        info->compression = shp[16];
  867|  17.6k|        info->is_compressed_data = shp[17];
  868|  82.3k|    } else {
  869|  82.3k|        if (shp_size <= 9) {
  ------------------
  |  Branch (869:13): [True: 0, False: 82.3k]
  ------------------
  870|      0|            retval = READSTAT_ERROR_PARSE;
  871|      0|            goto cleanup;
  872|      0|        }
  873|  82.3k|        info->offset = sas_read4(&shp[0], ctx->bswap);
  874|  82.3k|        info->len = sas_read4(&shp[4], ctx->bswap);
  875|  82.3k|        info->compression = shp[8];
  876|  82.3k|        info->is_compressed_data = shp[9];
  877|  82.3k|    }
  878|  99.9k|cleanup:
  879|  99.9k|    return retval;
  880|  99.9k|}
readstat_sas7bdat_read.c:sas7bdat_validate_subheader_pointer:
  883|  53.0k|        uint16_t subheader_count, sas7bdat_ctx_t *ctx) {
  884|  53.0k|    if (shp_info->offset > page_size)
  ------------------
  |  Branch (884:9): [True: 547, False: 52.4k]
  ------------------
  885|    547|        return READSTAT_ERROR_PARSE;
  886|  52.4k|    if (shp_info->len > page_size)
  ------------------
  |  Branch (886:9): [True: 320, False: 52.1k]
  ------------------
  887|    320|        return READSTAT_ERROR_PARSE;
  888|  52.1k|    if (shp_info->offset + shp_info->len > page_size)
  ------------------
  |  Branch (888:9): [True: 56, False: 52.0k]
  ------------------
  889|     56|        return READSTAT_ERROR_PARSE;
  890|  52.0k|    if (shp_info->offset < ctx->page_header_size + subheader_count*ctx->subheader_pointer_size)
  ------------------
  |  Branch (890:9): [True: 17, False: 52.0k]
  ------------------
  891|     17|        return READSTAT_ERROR_PARSE;
  892|  52.0k|    if (shp_info->compression == SAS_COMPRESSION_NONE) {
  ------------------
  |  |  123|  52.0k|#define SAS_COMPRESSION_NONE   0x00
  ------------------
  |  Branch (892:9): [True: 48.1k, False: 3.88k]
  ------------------
  893|  48.1k|        if (shp_info->len < ctx->subheader_signature_size)
  ------------------
  |  Branch (893:13): [True: 6, False: 48.1k]
  ------------------
  894|      6|            return READSTAT_ERROR_PARSE;
  895|  48.1k|        if (shp_info->offset + ctx->subheader_signature_size > page_size)
  ------------------
  |  Branch (895:13): [True: 0, False: 48.1k]
  ------------------
  896|      0|            return READSTAT_ERROR_PARSE;
  897|  48.1k|    }
  898|       |    
  899|  52.0k|    return READSTAT_OK;
  900|  52.0k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_type:
  837|  48.1k|static sas_subheader_type_t sas7bdat_parse_subheader_type(const char* subheader, sas7bdat_ctx_t* ctx) {
  838|  48.1k|    if (!ctx->u64) {
  ------------------
  |  Branch (838:9): [True: 37.8k, False: 10.3k]
  ------------------
  839|  37.8k|        uint32_t signature_32 = sas_read4(subheader, ctx->bswap);
  840|  37.8k|        return sas7bdat_parse_subheader_type_32(signature_32);
  841|  37.8k|    }
  842|       |
  843|  10.3k|    uint64_t signature = sas_read8(subheader, ctx->bswap);
  844|  10.3k|    if (signature == SAS_SUBHEADER_SIGNATURE_ROW_SIZE) {
  ------------------
  |  |   92|  10.3k|#define SAS_SUBHEADER_SIGNATURE_ROW_SIZE       0xF7F7F7F7
  ------------------
  |  Branch (844:9): [True: 1.98k, False: 8.33k]
  ------------------
  845|  1.98k|        return SAS_SUBHEADER_TYPE_ROW_SIZE;
  846|  8.33k|    } else if (signature == SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE) {
  ------------------
  |  |   93|  8.33k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE    0xF6F6F6F6
  ------------------
  |  Branch (846:16): [True: 467, False: 7.86k]
  ------------------
  847|    467|        return SAS_SUBHEADER_TYPE_COLUMN_SIZE;
  848|  7.86k|    } else if ((signature & SAS_SUBHEADER_SIGNATURE_64BIT_MASK) != SAS_SUBHEADER_SIGNATURE_64BIT_MASK) {
  ------------------
  |  |  105|  7.86k|#define SAS_SUBHEADER_SIGNATURE_64BIT_MASK     0xFFFFFFFF00000000
  ------------------
                  } else if ((signature & SAS_SUBHEADER_SIGNATURE_64BIT_MASK) != SAS_SUBHEADER_SIGNATURE_64BIT_MASK) {
  ------------------
  |  |  105|  7.86k|#define SAS_SUBHEADER_SIGNATURE_64BIT_MASK     0xFFFFFFFF00000000
  ------------------
  |  Branch (848:16): [True: 2.02k, False: 5.84k]
  ------------------
  849|  2.02k|        return SAS_SUBHEADER_TYPE_DATA;
  850|  2.02k|    }
  851|       |
  852|  5.84k|    uint32_t lower_bytes = (uint32_t)(signature & SAS_SUBHEADER_SIGNATURE_32BIT_MASK);
  ------------------
  |  |  106|  5.84k|#define SAS_SUBHEADER_SIGNATURE_32BIT_MASK     0x00000000FFFFFFFF
  ------------------
  853|  5.84k|    return sas7bdat_parse_subheader_type_32(lower_bytes);
  854|  10.3k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_type_32:
  811|  43.6k|static sas_subheader_type_t sas7bdat_parse_subheader_type_32(uint32_t signature) {
  812|  43.6k|    switch (signature) {
  813|  7.23k|        case SAS_SUBHEADER_SIGNATURE_ROW_SIZE:
  ------------------
  |  |   92|  7.23k|#define SAS_SUBHEADER_SIGNATURE_ROW_SIZE       0xF7F7F7F7
  ------------------
  |  Branch (813:9): [True: 7.23k, False: 36.4k]
  ------------------
  814|  7.23k|            return SAS_SUBHEADER_TYPE_ROW_SIZE;
  815|  3.99k|        case SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE:
  ------------------
  |  |   93|  3.99k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_SIZE    0xF6F6F6F6
  ------------------
  |  Branch (815:9): [True: 3.99k, False: 39.7k]
  ------------------
  816|  3.99k|            return SAS_SUBHEADER_TYPE_COLUMN_SIZE;
  817|  2.74k|        case SAS_SUBHEADER_SIGNATURE_COUNTS:
  ------------------
  |  |   94|  2.74k|#define SAS_SUBHEADER_SIGNATURE_COUNTS         0xFFFFFC00
  ------------------
  |  Branch (817:9): [True: 2.74k, False: 40.9k]
  ------------------
  818|  2.74k|            return SAS_SUBHEADER_TYPE_COUNTS;
  819|  8.81k|        case SAS_SUBHEADER_SIGNATURE_COLUMN_FORMAT:
  ------------------
  |  |   95|  8.81k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_FORMAT  0xFFFFFBFE
  ------------------
  |  Branch (819:9): [True: 8.81k, False: 34.8k]
  ------------------
  820|  8.81k|            return SAS_SUBHEADER_TYPE_COLUMN_FORMAT;
  821|  5.27k|        case SAS_SUBHEADER_SIGNATURE_COLUMN_ATTRS:
  ------------------
  |  |  100|  5.27k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_ATTRS   0xFFFFFFFC
  ------------------
  |  Branch (821:9): [True: 5.27k, False: 38.4k]
  ------------------
  822|  5.27k|            return SAS_SUBHEADER_TYPE_COLUMN_ATTRS;
  823|  4.26k|        case SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT:
  ------------------
  |  |  101|  4.26k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_TEXT    0xFFFFFFFD
  ------------------
  |  Branch (823:9): [True: 4.26k, False: 39.4k]
  ------------------
  824|  4.26k|            return SAS_SUBHEADER_TYPE_COLUMN_TEXT;
  825|  1.66k|        case SAS_SUBHEADER_SIGNATURE_COLUMN_LIST:
  ------------------
  |  |  102|  1.66k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_LIST    0xFFFFFFFE
  ------------------
  |  Branch (825:9): [True: 1.66k, False: 42.0k]
  ------------------
  826|  1.66k|            return SAS_SUBHEADER_TYPE_COLUMN_LIST;
  827|  3.72k|        case SAS_SUBHEADER_SIGNATURE_COLUMN_NAME:
  ------------------
  |  |  103|  3.72k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_NAME    0xFFFFFFFF
  ------------------
  |  Branch (827:9): [True: 3.72k, False: 39.9k]
  ------------------
  828|  3.72k|            return SAS_SUBHEADER_TYPE_COLUMN_NAME;
  829|  5.97k|        default:
  ------------------
  |  Branch (829:9): [True: 5.97k, False: 37.7k]
  ------------------
  830|  5.97k|            if ((signature & SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) == SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) {
  ------------------
  |  |   97|  5.97k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_MASK    0xFFFFFFF8
  ------------------
                          if ((signature & SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) == SAS_SUBHEADER_SIGNATURE_COLUMN_MASK) {
  ------------------
  |  |   97|  5.97k|#define SAS_SUBHEADER_SIGNATURE_COLUMN_MASK    0xFFFFFFF8
  ------------------
  |  Branch (830:17): [True: 1.74k, False: 4.22k]
  ------------------
  831|  1.74k|                return SAS_SUBHEADER_TYPE_UNKNOWN;
  832|  1.74k|            }
  833|  4.22k|            return SAS_SUBHEADER_TYPE_DATA;
  834|  43.6k|    }
  835|  43.6k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader:
  633|  17.3k|        size_t len, sas7bdat_ctx_t *ctx) {
  634|  17.3k|    readstat_error_t retval = READSTAT_OK;
  635|       |
  636|  17.3k|    if (len < 2 + ctx->subheader_signature_size) {
  ------------------
  |  Branch (636:9): [True: 8, False: 17.3k]
  ------------------
  637|      8|        retval = READSTAT_ERROR_PARSE;
  638|      8|        goto cleanup;
  639|      8|    }
  640|  17.3k|    if (subheader_type == SAS_SUBHEADER_TYPE_ROW_SIZE) {
  ------------------
  |  Branch (640:9): [True: 3.61k, False: 13.7k]
  ------------------
  641|  3.61k|        retval = sas7bdat_parse_row_size_subheader(subheader, len, ctx);
  642|  13.7k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_SIZE) {
  ------------------
  |  Branch (642:16): [True: 1.38k, False: 12.3k]
  ------------------
  643|  1.38k|        retval = sas7bdat_parse_column_size_subheader(subheader, len, ctx);
  644|  12.3k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COUNTS) {
  ------------------
  |  Branch (644:16): [True: 1.12k, False: 11.2k]
  ------------------
  645|       |        /* void */
  646|  11.2k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_TEXT) {
  ------------------
  |  Branch (646:16): [True: 2.79k, False: 8.42k]
  ------------------
  647|  2.79k|        retval = sas7bdat_parse_column_text_subheader(subheader, len, ctx);
  648|  8.42k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_NAME) {
  ------------------
  |  Branch (648:16): [True: 1.36k, False: 7.06k]
  ------------------
  649|  1.36k|        retval = sas7bdat_parse_column_name_subheader(subheader, len, ctx);
  650|  7.06k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_ATTRS) {
  ------------------
  |  Branch (650:16): [True: 1.97k, False: 5.08k]
  ------------------
  651|  1.97k|        retval = sas7bdat_parse_column_attributes_subheader(subheader, len, ctx);
  652|  5.08k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_FORMAT) {
  ------------------
  |  Branch (652:16): [True: 3.72k, False: 1.36k]
  ------------------
  653|  3.72k|        retval = sas7bdat_parse_column_format_subheader(subheader, len, ctx);
  654|  3.72k|    } else if (subheader_type == SAS_SUBHEADER_TYPE_COLUMN_LIST) {
  ------------------
  |  Branch (654:16): [True: 624, False: 742]
  ------------------
  655|       |        /* void */
  656|    742|    } else if (subheader_type == SAS_SUBHEADER_TYPE_UNKNOWN) {
  ------------------
  |  Branch (656:16): [True: 698, False: 44]
  ------------------
  657|       |        /* void */
  658|    698|    } else {
  659|     44|        retval = READSTAT_ERROR_PARSE;
  660|     44|    }
  661|       |
  662|  17.3k|cleanup:
  663|       |
  664|  17.3k|    return retval;
  665|  17.3k|}
readstat_sas7bdat_read.c:sas7bdat_parse_row_size_subheader:
  232|  3.61k|static readstat_error_t sas7bdat_parse_row_size_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  233|  3.61k|    readstat_error_t retval = READSTAT_OK;
  234|  3.61k|    uint64_t total_row_count;
  235|  3.61k|    uint64_t row_length, page_row_count;
  236|       |
  237|  3.61k|    if (len < (ctx->u64 ? 250: 190)) {
  ------------------
  |  Branch (237:9): [True: 17, False: 3.60k]
  |  Branch (237:16): [True: 919, False: 2.69k]
  ------------------
  238|     17|        retval = READSTAT_ERROR_PARSE;
  239|     17|        goto cleanup;
  240|     17|    }
  241|       |
  242|  3.60k|    if (ctx->u64) {
  ------------------
  |  Branch (242:9): [True: 918, False: 2.68k]
  ------------------
  243|    918|        row_length = sas_read8(&subheader[40], ctx->bswap);
  244|    918|        total_row_count = sas_read8(&subheader[48], ctx->bswap);
  245|    918|        page_row_count = sas_read8(&subheader[120], ctx->bswap);
  246|  2.68k|    } else {
  247|  2.68k|        row_length = sas_read4(&subheader[20], ctx->bswap);
  248|  2.68k|        total_row_count = sas_read4(&subheader[24], ctx->bswap);
  249|  2.68k|        page_row_count = sas_read4(&subheader[60], ctx->bswap);
  250|  2.68k|    }
  251|       |
  252|  3.60k|    sas_text_ref_t file_label_ref = sas7bdat_parse_text_ref(&subheader[len-130], ctx);
  253|  3.60k|    if (file_label_ref.length) {
  ------------------
  |  Branch (253:9): [True: 927, False: 2.67k]
  ------------------
  254|    927|        if ((retval = sas7bdat_copy_text_ref(ctx->file_label, sizeof(ctx->file_label),
  ------------------
  |  Branch (254:13): [True: 45, False: 882]
  ------------------
  255|    927|                        file_label_ref, ctx)) != READSTAT_OK) {
  256|     45|            goto cleanup;
  257|     45|        }
  258|    927|    }
  259|       |
  260|  3.55k|    sas_text_ref_t compression_ref = sas7bdat_parse_text_ref(&subheader[len-118], ctx);
  261|  3.55k|    if (compression_ref.length) {
  ------------------
  |  Branch (261:9): [True: 1.44k, False: 2.10k]
  ------------------
  262|  1.44k|        char compression[9];
  263|  1.44k|        if ((retval = sas7bdat_copy_text_ref(compression, sizeof(compression),
  ------------------
  |  Branch (263:13): [True: 42, False: 1.40k]
  ------------------
  264|  1.44k|                        compression_ref, ctx)) != READSTAT_OK) {
  265|     42|            goto cleanup;
  266|     42|        }
  267|  1.40k|        ctx->rdc_compression = (memcmp(compression, SAS_COMPRESSION_SIGNATURE_RDC, 8) == 0);
  ------------------
  |  |  128|  1.40k|#define SAS_COMPRESSION_SIGNATURE_RDC  "SASYZCR2"
  ------------------
  268|  1.40k|    }
  269|       |
  270|  3.51k|    ctx->row_length = row_length;
  271|  3.51k|    ctx->row = readstat_realloc(ctx->row, ctx->row_length);
  272|  3.51k|    if (ctx->row == NULL) {
  ------------------
  |  Branch (272:9): [True: 9, False: 3.50k]
  ------------------
  273|      9|        retval = READSTAT_ERROR_MALLOC;
  274|      9|        goto cleanup;
  275|      9|    }
  276|       |
  277|  3.50k|    ctx->page_row_count = page_row_count;
  278|  3.50k|    uint64_t total_row_count_after_skipping = total_row_count;
  279|  3.50k|    if (total_row_count > ctx->row_offset) {
  ------------------
  |  Branch (279:9): [True: 3.28k, False: 218]
  ------------------
  280|  3.28k|        total_row_count_after_skipping -= ctx->row_offset;
  281|  3.28k|    } else {
  282|    218|        total_row_count_after_skipping = 0;
  283|    218|        ctx->row_offset = total_row_count;
  284|    218|    }
  285|  3.50k|    if (ctx->row_limit == 0 || total_row_count_after_skipping < ctx->row_limit)
  ------------------
  |  Branch (285:9): [True: 1.28k, False: 2.22k]
  |  Branch (285:32): [True: 156, False: 2.06k]
  ------------------
  286|  1.43k|        ctx->row_limit = total_row_count_after_skipping;
  287|       |
  288|  3.61k|cleanup:
  289|  3.61k|    return retval;
  290|  3.50k|}
readstat_sas7bdat_read.c:sas7bdat_parse_text_ref:
  133|  54.0k|static sas_text_ref_t sas7bdat_parse_text_ref(const char *data, sas7bdat_ctx_t *ctx) {
  134|  54.0k|    sas_text_ref_t  ref;
  135|       |
  136|  54.0k|    ref.index = sas_read2(&data[0], ctx->bswap);
  137|  54.0k|    ref.offset = sas_read2(&data[2], ctx->bswap);
  138|  54.0k|    ref.length = sas_read2(&data[4], ctx->bswap);
  139|       |
  140|  54.0k|    return ref;
  141|  54.0k|}
readstat_sas7bdat_read.c:sas7bdat_copy_text_ref:
  143|  10.7M|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) {
  144|  10.7M|    if (text_ref.index >= ctx->text_blob_count)
  ------------------
  |  Branch (144:9): [True: 140, False: 10.7M]
  ------------------
  145|    140|        return READSTAT_ERROR_PARSE;
  146|       |    
  147|  10.7M|    if (text_ref.length == 0) {
  ------------------
  |  Branch (147:9): [True: 10.7M, False: 4.04k]
  ------------------
  148|  10.7M|        out_buffer[0] = '\0';
  149|  10.7M|        return READSTAT_OK;
  150|  10.7M|    }
  151|       |
  152|  4.04k|    char *blob = ctx->text_blobs[text_ref.index];
  153|       |
  154|  4.04k|    if (text_ref.offset + text_ref.length > ctx->text_blob_lengths[text_ref.index])
  ------------------
  |  Branch (154:9): [True: 82, False: 3.95k]
  ------------------
  155|     82|        return READSTAT_ERROR_PARSE;
  156|       |
  157|  3.95k|    return readstat_convert(out_buffer, out_buffer_len, &blob[text_ref.offset], text_ref.length,
  158|  3.95k|            ctx->converter);
  159|  4.04k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_size_subheader:
  204|  1.38k|static readstat_error_t sas7bdat_parse_column_size_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  205|  1.38k|    uint64_t col_count;
  206|  1.38k|    readstat_error_t retval = READSTAT_OK;
  207|       |
  208|  1.38k|    if (ctx->column_count || ctx->did_submit_columns) {
  ------------------
  |  Branch (208:9): [True: 23, False: 1.36k]
  |  Branch (208:30): [True: 3, False: 1.36k]
  ------------------
  209|     26|        retval = READSTAT_ERROR_PARSE;
  210|     26|        goto cleanup;
  211|     26|    }
  212|       |
  213|  1.36k|    if (len < (ctx->u64 ? 16 : 8)) {
  ------------------
  |  Branch (213:9): [True: 2, False: 1.36k]
  |  Branch (213:16): [True: 441, False: 922]
  ------------------
  214|      2|        retval = READSTAT_ERROR_PARSE;
  215|      2|        goto cleanup;
  216|      2|    }
  217|       |
  218|  1.36k|    if (ctx->u64) {
  ------------------
  |  Branch (218:9): [True: 441, False: 920]
  ------------------
  219|    441|        col_count = sas_read8(&subheader[8], ctx->bswap);
  220|    920|    } else {
  221|    920|        col_count = sas_read4(&subheader[4], ctx->bswap);
  222|    920|    }
  223|       |
  224|  1.36k|    ctx->column_count = col_count;
  225|       |
  226|  1.36k|    retval = sas7bdat_realloc_col_info(ctx, ctx->column_count);
  227|       |
  228|  1.38k|cleanup:
  229|  1.38k|    return retval;
  230|  1.36k|}
readstat_sas7bdat_read.c:sas7bdat_realloc_col_info:
  191|  8.30k|static readstat_error_t sas7bdat_realloc_col_info(sas7bdat_ctx_t *ctx, size_t count) {
  192|  8.30k|    if (ctx->col_info_count < count) {
  ------------------
  |  Branch (192:9): [True: 3.36k, False: 4.94k]
  ------------------
  193|  3.36k|        size_t old_count = ctx->col_info_count;
  194|  3.36k|        ctx->col_info_count = count;
  195|  3.36k|        ctx->col_info = readstat_realloc(ctx->col_info, ctx->col_info_count * sizeof(col_info_t));
  196|  3.36k|        if (ctx->col_info == NULL) {
  ------------------
  |  Branch (196:13): [True: 84, False: 3.28k]
  ------------------
  197|     84|            return READSTAT_ERROR_MALLOC;
  198|     84|        }
  199|  3.28k|        memset(ctx->col_info + old_count, 0, (count - old_count) * sizeof(col_info_t));
  200|  3.28k|    }
  201|  8.22k|    return READSTAT_OK;
  202|  8.30k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_text_subheader:
  161|  2.79k|static readstat_error_t sas7bdat_parse_column_text_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  162|  2.79k|    readstat_error_t retval = READSTAT_OK;
  163|  2.79k|    size_t signature_len = ctx->subheader_signature_size;
  164|  2.79k|    uint16_t remainder = sas_read2(&subheader[signature_len], ctx->bswap);
  165|  2.79k|    char *blob = NULL;
  166|  2.79k|    if (remainder != sas_subheader_remainder(len, signature_len)) {
  ------------------
  |  Branch (166:9): [True: 56, False: 2.73k]
  ------------------
  167|     56|        retval = READSTAT_ERROR_PARSE;
  168|     56|        goto cleanup;
  169|     56|    }
  170|  2.73k|    ctx->text_blob_count++;
  171|  2.73k|    ctx->text_blobs = readstat_realloc(ctx->text_blobs, ctx->text_blob_count * sizeof(char *));
  172|  2.73k|    ctx->text_blob_lengths = readstat_realloc(ctx->text_blob_lengths,
  173|  2.73k|            ctx->text_blob_count * sizeof(ctx->text_blob_lengths[0]));
  174|  2.73k|    if (ctx->text_blobs == NULL || ctx->text_blob_lengths == NULL) {
  ------------------
  |  Branch (174:9): [True: 0, False: 2.73k]
  |  Branch (174:36): [True: 0, False: 2.73k]
  ------------------
  175|      0|        retval = READSTAT_ERROR_MALLOC;
  176|      0|        goto cleanup;
  177|      0|    }
  178|       |
  179|  2.73k|    if ((blob = readstat_malloc(len-signature_len)) == NULL) {
  ------------------
  |  Branch (179:9): [True: 0, False: 2.73k]
  ------------------
  180|      0|        retval = READSTAT_ERROR_MALLOC;
  181|      0|        goto cleanup;
  182|      0|    }
  183|  2.73k|    memcpy(blob, subheader+signature_len, len-signature_len);
  184|  2.73k|    ctx->text_blob_lengths[ctx->text_blob_count-1] = len-signature_len;
  185|  2.73k|    ctx->text_blobs[ctx->text_blob_count-1] = blob;
  186|       |
  187|  2.79k|cleanup:
  188|  2.79k|    return retval;
  189|  2.73k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_name_subheader:
  292|  1.36k|static readstat_error_t sas7bdat_parse_column_name_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  293|  1.36k|    readstat_error_t retval = READSTAT_OK;
  294|  1.36k|    size_t signature_len = ctx->subheader_signature_size;
  295|  1.36k|    int cmax = ctx->u64 ? (len-28)/8 : (len-20)/8;
  ------------------
  |  Branch (295:16): [True: 336, False: 1.02k]
  ------------------
  296|  1.36k|    int i;
  297|  1.36k|    const char *cnp = &subheader[signature_len+8];
  298|  1.36k|    uint16_t remainder = sas_read2(&subheader[signature_len], ctx->bswap);
  299|       |
  300|  1.36k|    if (remainder != sas_subheader_remainder(len, signature_len)) {
  ------------------
  |  Branch (300:9): [True: 58, False: 1.30k]
  ------------------
  301|     58|        retval = READSTAT_ERROR_PARSE;
  302|     58|        goto cleanup;
  303|     58|    }
  304|       |
  305|  1.30k|    ctx->col_names_count += cmax;
  306|       |
  307|  1.30k|    if ((retval = sas7bdat_realloc_col_info(ctx, ctx->col_names_count)) != READSTAT_OK)
  ------------------
  |  Branch (307:9): [True: 15, False: 1.29k]
  ------------------
  308|     15|        goto cleanup;
  309|       |
  310|  40.7k|    for (i=ctx->col_names_count-cmax; i<ctx->col_names_count; i++) {
  ------------------
  |  Branch (310:39): [True: 39.4k, False: 1.29k]
  ------------------
  311|  39.4k|        ctx->col_info[i].name_ref = sas7bdat_parse_text_ref(cnp, ctx);
  312|  39.4k|        cnp += 8;
  313|  39.4k|    }
  314|       |
  315|  1.36k|cleanup:
  316|       |
  317|  1.36k|    return retval;
  318|  1.29k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_attributes_subheader:
  320|  1.97k|static readstat_error_t sas7bdat_parse_column_attributes_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  321|  1.97k|    readstat_error_t retval = READSTAT_OK;
  322|  1.97k|    size_t signature_len = ctx->subheader_signature_size;
  323|  1.97k|    int cmax = ctx->u64 ? (len-28)/16 : (len-20)/12;
  ------------------
  |  Branch (323:16): [True: 105, False: 1.86k]
  ------------------
  324|  1.97k|    int i;
  325|  1.97k|    const char *cap = &subheader[signature_len+8];
  326|  1.97k|    uint16_t remainder = sas_read2(&subheader[signature_len], ctx->bswap);
  327|       |
  328|  1.97k|    if (remainder != sas_subheader_remainder(len, signature_len)) {
  ------------------
  |  Branch (328:9): [True: 54, False: 1.92k]
  ------------------
  329|     54|        retval = READSTAT_ERROR_PARSE;
  330|     54|        goto cleanup;
  331|     54|    }
  332|  1.92k|    ctx->col_attrs_count += cmax;
  333|  1.92k|    if ((retval = sas7bdat_realloc_col_info(ctx, ctx->col_attrs_count)) != READSTAT_OK)
  ------------------
  |  Branch (333:9): [True: 9, False: 1.91k]
  ------------------
  334|      9|        goto cleanup;
  335|       |
  336|  9.32k|    for (i=ctx->col_attrs_count-cmax; i<ctx->col_attrs_count; i++) {
  ------------------
  |  Branch (336:39): [True: 7.43k, False: 1.89k]
  ------------------
  337|  7.43k|        if (ctx->u64) {
  ------------------
  |  Branch (337:13): [True: 605, False: 6.82k]
  ------------------
  338|    605|            ctx->col_info[i].offset = sas_read8(&cap[0], ctx->bswap);
  339|  6.82k|        } else {
  340|  6.82k|            ctx->col_info[i].offset = sas_read4(&cap[0], ctx->bswap);
  341|  6.82k|        }
  342|       |
  343|  7.43k|        readstat_off_t off=4;
  344|  7.43k|        if (ctx->u64)
  ------------------
  |  Branch (344:13): [True: 605, False: 6.82k]
  ------------------
  345|    605|            off=8;
  346|       |
  347|  7.43k|        ctx->col_info[i].width = sas_read4(&cap[off], ctx->bswap);
  348|  7.43k|        if (ctx->col_info[i].width > ctx->max_col_width)
  ------------------
  |  Branch (348:13): [True: 861, False: 6.57k]
  ------------------
  349|    861|            ctx->max_col_width = ctx->col_info[i].width;
  350|       |
  351|  7.43k|        if (cap[off+6] == SAS_COLUMN_TYPE_NUM) {
  ------------------
  |  |   89|  7.43k|#define SAS_COLUMN_TYPE_NUM  0x01
  ------------------
  |  Branch (351:13): [True: 4.30k, False: 3.12k]
  ------------------
  352|  4.30k|            ctx->col_info[i].type = READSTAT_TYPE_DOUBLE;
  353|  4.30k|        } else if (cap[off+6] == SAS_COLUMN_TYPE_CHR) {
  ------------------
  |  |   90|  3.12k|#define SAS_COLUMN_TYPE_CHR  0x02
  ------------------
  |  Branch (353:20): [True: 3.10k, False: 17]
  ------------------
  354|  3.10k|            ctx->col_info[i].type = READSTAT_TYPE_STRING;
  355|  3.10k|        } else {
  356|     17|            retval = READSTAT_ERROR_PARSE;
  357|     17|            goto cleanup;
  358|     17|        }
  359|  7.41k|        ctx->col_info[i].index = i;
  360|  7.41k|        cap += off+8;
  361|  7.41k|    }
  362|       |
  363|  1.97k|cleanup:
  364|       |
  365|  1.97k|    return retval;
  366|  1.91k|}
readstat_sas7bdat_read.c:sas7bdat_parse_column_format_subheader:
  368|  3.72k|static readstat_error_t sas7bdat_parse_column_format_subheader(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  369|  3.72k|    readstat_error_t retval = READSTAT_OK;
  370|       |
  371|  3.72k|    if (len < (ctx->u64 ? 58 : 46)) {
  ------------------
  |  Branch (371:9): [True: 5, False: 3.71k]
  |  Branch (371:16): [True: 333, False: 3.39k]
  ------------------
  372|      5|        retval = READSTAT_ERROR_PARSE;
  373|      5|        goto cleanup;
  374|      5|    }
  375|       |
  376|  3.71k|    ctx->col_formats_count++;
  377|  3.71k|    if ((retval = sas7bdat_realloc_col_info(ctx, ctx->col_formats_count)) != READSTAT_OK)
  ------------------
  |  Branch (377:9): [True: 0, False: 3.71k]
  ------------------
  378|      0|        goto cleanup;
  379|       |
  380|  3.71k|    if (ctx->u64) {
  ------------------
  |  Branch (380:9): [True: 333, False: 3.38k]
  ------------------
  381|    333|        ctx->col_info[ctx->col_formats_count-1].format_width = sas_read2(&subheader[24], ctx->bswap);
  382|    333|        ctx->col_info[ctx->col_formats_count-1].format_digits = sas_read2(&subheader[26], ctx->bswap);
  383|  3.38k|    } else {
  384|  3.38k|        ctx->col_info[ctx->col_formats_count-1].format_width = sas_read2(&subheader[12], ctx->bswap);
  385|  3.38k|        ctx->col_info[ctx->col_formats_count-1].format_digits = sas_read2(&subheader[14], ctx->bswap);
  386|  3.38k|    }
  387|  3.71k|    ctx->col_info[ctx->col_formats_count-1].format_ref = sas7bdat_parse_text_ref(
  388|  3.71k|            ctx->u64 ? &subheader[46] : &subheader[34], ctx);
  ------------------
  |  Branch (388:13): [True: 333, False: 3.38k]
  ------------------
  389|  3.71k|    ctx->col_info[ctx->col_formats_count-1].label_ref = sas7bdat_parse_text_ref(
  390|  3.71k|            ctx->u64 ? &subheader[52] : &subheader[40], ctx);
  ------------------
  |  Branch (390:13): [True: 333, False: 3.38k]
  ------------------
  391|       |
  392|  3.72k|cleanup:
  393|  3.72k|    return retval;
  394|  3.71k|}
readstat_sas7bdat_read.c:sas7bdat_parse_amd_pages_pass1:
 1108|  2.96k|static readstat_error_t sas7bdat_parse_amd_pages_pass1(int64_t last_examined_page_pass1, sas7bdat_ctx_t *ctx) {
 1109|  2.96k|    readstat_error_t retval = READSTAT_OK;
 1110|  2.96k|    readstat_io_t *io = ctx->io;
 1111|  2.96k|    uint64_t i;
 1112|  2.96k|    uint64_t amd_page_count = 0;
 1113|       |
 1114|       |    /* ...then AMD pages at the end */
 1115|  6.80k|    for (i=ctx->page_count-1; i>last_examined_page_pass1; i--) {
  ------------------
  |  Branch (1115:31): [True: 5.27k, False: 1.53k]
  ------------------
 1116|  5.27k|        if (io->seek(ctx->header_size + i*ctx->page_size, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (1116:13): [True: 226, False: 5.04k]
  ------------------
 1117|    226|            retval = READSTAT_ERROR_SEEK;
 1118|    226|            if (ctx->handle.error) {
  ------------------
  |  Branch (1118:17): [True: 0, False: 226]
  ------------------
 1119|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), "ReadStat: Failed to seek to position %" PRId64 
 1120|      0|                        " (= %" PRId64 " + %" PRId64 "*%" PRId64 ")",
 1121|      0|                        ctx->header_size + i*ctx->page_size, ctx->header_size, i, ctx->page_size);
 1122|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1123|      0|            }
 1124|    226|            goto cleanup;
 1125|    226|        }
 1126|       |
 1127|  5.04k|        readstat_off_t off = 0;
 1128|  5.04k|        if (ctx->u64)
  ------------------
  |  Branch (1128:13): [True: 4.06k, False: 978]
  ------------------
 1129|  4.06k|            off = 16;
 1130|       |
 1131|  5.04k|        size_t head_len = off + 16 + 2;
 1132|  5.04k|        size_t tail_len = ctx->page_size - head_len;
 1133|       |
 1134|  5.04k|        if (io->read(ctx->page, head_len, io->io_ctx) < head_len) {
  ------------------
  |  Branch (1134:13): [True: 6, False: 5.04k]
  ------------------
 1135|      6|            retval = READSTAT_ERROR_READ;
 1136|      6|            goto cleanup;
 1137|      6|        }
 1138|       |
 1139|  5.04k|        uint16_t page_type = sas_read2(&ctx->page[off+16], ctx->bswap);
 1140|       |
 1141|  5.04k|        if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |  112|  5.04k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                      if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |  109|  5.04k|#define SAS_PAGE_TYPE_DATA   0x0100
  ------------------
  |  Branch (1141:13): [True: 1.22k, False: 3.81k]
  ------------------
 1142|       |            /* Usually AMD pages are at the end but sometimes data pages appear after them */
 1143|  1.22k|            if (amd_page_count > 0)
  ------------------
  |  Branch (1143:17): [True: 400, False: 824]
  ------------------
 1144|    400|                break;
 1145|    824|            continue;
 1146|  1.22k|        }
 1147|  3.81k|        if ((page_type & SAS_PAGE_TYPE_COMP))
  ------------------
  |  |  115|  3.81k|#define SAS_PAGE_TYPE_COMP   0x9000
  ------------------
  |  Branch (1147:13): [True: 1.01k, False: 2.80k]
  ------------------
 1148|  1.01k|            continue;
 1149|       |
 1150|  2.80k|        if (io->read(ctx->page + head_len, tail_len, io->io_ctx) < tail_len) {
  ------------------
  |  Branch (1150:13): [True: 17, False: 2.78k]
  ------------------
 1151|     17|            retval = READSTAT_ERROR_READ;
 1152|     17|            goto cleanup;
 1153|     17|        }
 1154|       |
 1155|  2.78k|        if ((retval = sas7bdat_parse_page_pass1(ctx->page, ctx->page_size, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1155:13): [True: 788, False: 1.99k]
  ------------------
 1156|    788|            if (ctx->handle.error && retval != READSTAT_ERROR_USER_ABORT) {
  ------------------
  |  Branch (1156:17): [True: 0, False: 788]
  |  Branch (1156:38): [True: 0, False: 0]
  ------------------
 1157|      0|                int64_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
 1158|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
 1159|      0|                        "ReadStat: Error parsing page %" PRId64 ", bytes %" PRId64 "-%" PRId64, 
 1160|      0|                        i, pos - ctx->page_size, pos-1);
 1161|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1162|      0|            }
 1163|    788|            goto cleanup;
 1164|    788|        }
 1165|       |
 1166|  1.99k|        amd_page_count++;
 1167|  1.99k|    }
 1168|       |
 1169|  2.96k|cleanup:
 1170|       |
 1171|  2.96k|    return retval;
 1172|  2.96k|}
readstat_sas7bdat_read.c:sas7bdat_parse_all_pages_pass2:
 1174|  1.93k|static readstat_error_t sas7bdat_parse_all_pages_pass2(sas7bdat_ctx_t *ctx) {
 1175|  1.93k|    readstat_error_t retval = READSTAT_OK;
 1176|  1.93k|    readstat_io_t *io = ctx->io;
 1177|  1.93k|    int64_t i;
 1178|       |
 1179|  4.32k|    for (i=0; i<ctx->page_count; i++) {
  ------------------
  |  Branch (1179:15): [True: 4.20k, False: 120]
  ------------------
 1180|  4.20k|        if ((retval = sas7bdat_update_progress(ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1180:13): [True: 0, False: 4.20k]
  ------------------
 1181|      0|            goto cleanup;
 1182|      0|        }
 1183|  4.20k|        if (io->read(ctx->page, ctx->page_size, io->io_ctx) < ctx->page_size) {
  ------------------
  |  Branch (1183:13): [True: 130, False: 4.07k]
  ------------------
 1184|    130|            retval = READSTAT_ERROR_READ;
 1185|    130|            goto cleanup;
 1186|    130|        }
 1187|       |
 1188|  4.07k|        if ((retval = sas7bdat_parse_page_pass2(ctx->page, ctx->page_size, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1188:13): [True: 1.45k, False: 2.61k]
  ------------------
 1189|  1.45k|            if (ctx->handle.error && retval != READSTAT_ERROR_USER_ABORT) {
  ------------------
  |  Branch (1189:17): [True: 0, False: 1.45k]
  |  Branch (1189:38): [True: 0, False: 0]
  ------------------
 1190|      0|                int64_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
 1191|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
 1192|      0|                        "ReadStat: Error parsing page %" PRId64 ", bytes %" PRId64 "-%" PRId64, 
 1193|      0|                        i, pos - ctx->page_size, pos-1);
 1194|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
 1195|      0|            }
 1196|  1.45k|            goto cleanup;
 1197|  1.45k|        }
 1198|  2.61k|        if (ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (1198:13): [True: 223, False: 2.39k]
  ------------------
 1199|    223|            break;
 1200|  2.61k|    }
 1201|  1.93k|cleanup:
 1202|       |
 1203|  1.93k|    return retval;
 1204|  1.93k|}
readstat_sas7bdat_read.c:sas7bdat_parse_page_pass2:
  950|  4.07k|static readstat_error_t sas7bdat_parse_page_pass2(const char *page, size_t page_size, sas7bdat_ctx_t *ctx) {
  951|  4.07k|    uint16_t page_type;
  952|       |
  953|  4.07k|    readstat_error_t retval = READSTAT_OK;
  954|       |
  955|  4.07k|    page_type = sas_read2(&page[ctx->page_header_size-8], ctx->bswap);
  956|       |
  957|  4.07k|    const char *data = NULL;
  958|       |
  959|  4.07k|    if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |  112|  4.07k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                  if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_DATA) {
  ------------------
  |  |  109|  4.07k|#define SAS_PAGE_TYPE_DATA   0x0100
  ------------------
  |  Branch (959:9): [True: 562, False: 3.51k]
  ------------------
  960|    562|        ctx->page_row_count = sas_read2(&page[ctx->page_header_size-6], ctx->bswap);
  961|    562|        data = &page[ctx->page_header_size];
  962|  3.51k|    } else if (!(page_type & SAS_PAGE_TYPE_COMP)) {
  ------------------
  |  |  115|  3.51k|#define SAS_PAGE_TYPE_COMP   0x9000
  ------------------
  |  Branch (962:16): [True: 3.14k, False: 364]
  ------------------
  963|  3.14k|        uint16_t subheader_count = sas_read2(&page[ctx->page_header_size-4], ctx->bswap);
  964|       |
  965|  3.14k|        int i;
  966|  3.14k|        const char *shp = &page[ctx->page_header_size];
  967|  3.14k|        int lshp = ctx->subheader_pointer_size;
  968|       |
  969|  3.14k|        if (ctx->page_header_size + subheader_count*lshp > page_size) {
  ------------------
  |  Branch (969:13): [True: 13, False: 3.13k]
  ------------------
  970|     13|            retval = READSTAT_ERROR_PARSE;
  971|     13|            goto cleanup;
  972|     13|        }
  973|       |
  974|  38.2k|        for (i=0; i<subheader_count; i++) {
  ------------------
  |  Branch (974:19): [True: 36.2k, False: 2.00k]
  ------------------
  975|  36.2k|            subheader_pointer_t shp_info = { 0 };
  976|  36.2k|            if ((retval = sas7bdat_parse_subheader_pointer(shp, page + page_size - shp, &shp_info, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (976:17): [True: 0, False: 36.2k]
  ------------------
  977|      0|                goto cleanup;
  978|      0|            }
  979|  36.2k|            if (shp_info.len > 0 && shp_info.compression != SAS_COMPRESSION_TRUNC) {
  ------------------
  |  |  124|  22.0k|#define SAS_COMPRESSION_TRUNC  0x01
  ------------------
  |  Branch (979:17): [True: 22.0k, False: 14.2k]
  |  Branch (979:37): [True: 18.3k, False: 3.67k]
  ------------------
  980|  18.3k|                if ((retval = sas7bdat_validate_subheader_pointer(&shp_info, page_size, subheader_count, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (980:21): [True: 219, False: 18.1k]
  ------------------
  981|    219|                    goto cleanup;
  982|    219|                }
  983|  18.1k|                if (shp_info.compression == SAS_COMPRESSION_NONE) {
  ------------------
  |  |  123|  18.1k|#define SAS_COMPRESSION_NONE   0x00
  ------------------
  |  Branch (983:21): [True: 16.8k, False: 1.24k]
  ------------------
  984|  16.8k|                    sas_subheader_type_t subheader_type = sas7bdat_parse_subheader_type(page + shp_info.offset, ctx);
  985|  16.8k|                    if (shp_info.is_compressed_data && subheader_type == SAS_SUBHEADER_TYPE_DATA) {
  ------------------
  |  Branch (985:25): [True: 12.6k, False: 4.20k]
  |  Branch (985:56): [True: 833, False: 11.8k]
  ------------------
  986|    833|                        if (shp_info.len != ctx->row_length) {
  ------------------
  |  Branch (986:29): [True: 169, False: 664]
  ------------------
  987|    169|                            retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  988|    169|                            goto cleanup;
  989|    169|                        }
  990|    664|                        if ((retval = sas7bdat_submit_columns_if_needed(ctx, 1)) != READSTAT_OK) {
  ------------------
  |  Branch (990:29): [True: 12, False: 652]
  ------------------
  991|     12|                            goto cleanup;
  992|     12|                        }
  993|    652|                        if ((retval = sas7bdat_parse_single_row(page + shp_info.offset, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (993:29): [True: 8, False: 644]
  ------------------
  994|      8|                            goto cleanup;
  995|      8|                        }
  996|  16.0k|                    } else {
  997|  16.0k|                        if (subheader_type != SAS_SUBHEADER_TYPE_COLUMN_TEXT) {
  ------------------
  |  Branch (997:29): [True: 14.5k, False: 1.47k]
  ------------------
  998|  14.5k|                            if ((retval = sas7bdat_parse_subheader(subheader_type, page + shp_info.offset, shp_info.len, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (998:33): [True: 409, False: 14.1k]
  ------------------
  999|    409|                                goto cleanup;
 1000|    409|                            }
 1001|  14.5k|                        }
 1002|  16.0k|                    }
 1003|  16.8k|                } else if (shp_info.compression == SAS_COMPRESSION_ROW) {
  ------------------
  |  |  125|  1.24k|#define SAS_COMPRESSION_ROW    0x04
  ------------------
  |  Branch (1003:28): [True: 1.23k, False: 10]
  ------------------
 1004|  1.23k|                    if ((retval = sas7bdat_submit_columns_if_needed(ctx, 1)) != READSTAT_OK) {
  ------------------
  |  Branch (1004:25): [True: 39, False: 1.19k]
  ------------------
 1005|     39|                        goto cleanup;
 1006|     39|                    }
 1007|  1.19k|                    if ((retval = sas7bdat_parse_subheader_compressed(page + shp_info.offset, shp_info.len, ctx)) != READSTAT_OK) {
  ------------------
  |  Branch (1007:25): [True: 266, False: 933]
  ------------------
 1008|    266|                        goto cleanup;
 1009|    266|                    }
 1010|  1.19k|                } else {
 1011|     10|                    retval = READSTAT_ERROR_UNSUPPORTED_COMPRESSION;
 1012|     10|                    goto cleanup;
 1013|     10|                }
 1014|  18.1k|            }
 1015|       |
 1016|  35.1k|            shp += lshp;
 1017|  35.1k|        }
 1018|       |
 1019|  2.00k|        if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_MIX) {
  ------------------
  |  |  112|  2.00k|#define SAS_PAGE_TYPE_MASK   0x0F00
  ------------------
                      if ((page_type & SAS_PAGE_TYPE_MASK) == SAS_PAGE_TYPE_MIX) {
  ------------------
  |  |  110|  2.00k|#define SAS_PAGE_TYPE_MIX    0x0200
  ------------------
  |  Branch (1019:13): [True: 1.12k, False: 876]
  ------------------
 1020|       |            /* HACK - this is supposed to obey 8-byte boundaries but
 1021|       |             * some files created by Stat/Transfer don't. So verify that the
 1022|       |             * padding is { 0, 0, 0, 0 } or { ' ', ' ', ' ', ' ' } (or that
 1023|       |             * the file is not from Stat/Transfer) before skipping it */
 1024|  1.12k|            if ((shp-page)%8 == 4 && shp + 4 <= page + page_size &&
  ------------------
  |  Branch (1024:17): [True: 304, False: 823]
  |  Branch (1024:38): [True: 300, False: 4]
  ------------------
 1025|    300|                    (*(uint32_t *)shp == 0x00000000 ||
  ------------------
  |  Branch (1025:22): [True: 41, False: 259]
  ------------------
 1026|    259|                     *(uint32_t *)shp == 0x20202020 ||
  ------------------
  |  Branch (1026:22): [True: 26, False: 233]
  ------------------
 1027|    261|                     ctx->vendor != READSTAT_VENDOR_STAT_TRANSFER)) {
  ------------------
  |  Branch (1027:22): [True: 194, False: 39]
  ------------------
 1028|    261|                data = shp + 4;
 1029|    866|            } else {
 1030|    866|                data = shp;
 1031|    866|            }
 1032|  1.12k|        }
 1033|  2.00k|    }
 1034|  2.92k|    if (data) {
  ------------------
  |  Branch (1034:9): [True: 1.68k, False: 1.24k]
  ------------------
 1035|  1.68k|        if ((retval = sas7bdat_submit_columns_if_needed(ctx, 0)) != READSTAT_OK) {
  ------------------
  |  Branch (1035:13): [True: 130, False: 1.55k]
  ------------------
 1036|    130|            goto cleanup;
 1037|    130|        }
 1038|  1.55k|        if (ctx->handle.value) {
  ------------------
  |  Branch (1038:13): [True: 1.55k, False: 0]
  ------------------
 1039|  1.55k|            retval = sas7bdat_parse_rows(data, page + page_size - data, ctx);
 1040|  1.55k|        }
 1041|  1.55k|    } 
 1042|  4.07k|cleanup:
 1043|       |
 1044|  4.07k|    return retval;
 1045|  2.92k|}
readstat_sas7bdat_read.c:sas7bdat_parse_single_row:
  453|   169k|static readstat_error_t sas7bdat_parse_single_row(const char *data, sas7bdat_ctx_t *ctx) {
  454|   169k|    if (ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (454:9): [True: 335, False: 169k]
  ------------------
  455|    335|        return READSTAT_OK;
  456|   169k|    if (ctx->row_offset) {
  ------------------
  |  Branch (456:9): [True: 0, False: 169k]
  ------------------
  457|      0|        ctx->row_offset--;
  458|      0|        return READSTAT_OK;
  459|      0|    }
  460|       |
  461|   169k|    readstat_error_t retval = READSTAT_OK;
  462|   169k|    int j;
  463|   169k|    if (ctx->handle.value) {
  ------------------
  |  Branch (463:9): [True: 169k, False: 0]
  ------------------
  464|   169k|        ctx->scratch_buffer_len = 4*ctx->max_col_width+1;
  465|   169k|        ctx->scratch_buffer = readstat_realloc(ctx->scratch_buffer, ctx->scratch_buffer_len);
  466|   169k|        if (ctx->scratch_buffer == NULL) {
  ------------------
  |  Branch (466:13): [True: 3, False: 169k]
  ------------------
  467|      3|            retval = READSTAT_ERROR_MALLOC;
  468|      3|            goto cleanup;
  469|      3|        }
  470|       |
  471|  23.6M|        for (j=0; j<ctx->column_count; j++) {
  ------------------
  |  Branch (471:19): [True: 23.4M, False: 168k]
  ------------------
  472|  23.4M|            col_info_t *col_info = &ctx->col_info[j];
  473|  23.4M|            readstat_variable_t *variable = ctx->variables[j];
  474|  23.4M|            if (variable->skip)
  ------------------
  |  Branch (474:17): [True: 0, False: 23.4M]
  ------------------
  475|      0|                continue;
  476|       |
  477|  23.4M|            if (col_info->offset > ctx->row_length || col_info->offset + col_info->width > ctx->row_length) {
  ------------------
  |  Branch (477:17): [True: 86, False: 23.4M]
  |  Branch (477:55): [True: 16, False: 23.4M]
  ------------------
  478|    102|                retval = READSTAT_ERROR_PARSE;
  479|    102|                goto cleanup;
  480|    102|            }
  481|  23.4M|            retval = sas7bdat_handle_data_value(variable, col_info, &data[col_info->offset], ctx);
  482|  23.4M|            if (retval != READSTAT_OK) {
  ------------------
  |  Branch (482:17): [True: 12, False: 23.4M]
  ------------------
  483|     12|                goto cleanup;
  484|     12|            }
  485|  23.4M|        }
  486|   169k|    }
  487|   168k|    ctx->parsed_row_count++;
  488|       |
  489|   169k|cleanup:
  490|   169k|    return retval;
  491|   168k|}
readstat_sas7bdat_read.c:sas7bdat_handle_data_value:
  397|  23.4M|        col_info_t *col_info, const char *col_data, sas7bdat_ctx_t *ctx) {
  398|  23.4M|    readstat_error_t retval = READSTAT_OK;
  399|  23.4M|    int cb_retval = 0;
  400|  23.4M|    readstat_value_t value;
  401|  23.4M|    memset(&value, 0, sizeof(readstat_value_t));
  402|       |
  403|  23.4M|    value.type = col_info->type;
  404|       |
  405|  23.4M|    if (col_info->type == READSTAT_TYPE_STRING) {
  ------------------
  |  Branch (405:9): [True: 23.3M, False: 113k]
  ------------------
  406|  23.3M|        retval = readstat_convert(ctx->scratch_buffer, ctx->scratch_buffer_len,
  407|  23.3M|                col_data, col_info->width, ctx->converter);
  408|  23.3M|        if (retval != READSTAT_OK) {
  ------------------
  |  Branch (408:13): [True: 12, False: 23.3M]
  ------------------
  409|     12|            if (ctx->handle.error) {
  ------------------
  |  Branch (409:17): [True: 0, False: 12]
  ------------------
  410|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf),
  411|      0|                        "ReadStat: Error converting string (row=%u, col=%u) to specified encoding: %.*s",
  412|      0|                        ctx->parsed_row_count+1, col_info->index+1, col_info->width, col_data);
  413|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
  414|      0|            }
  415|     12|            goto cleanup;
  416|     12|        }
  417|       |
  418|  23.3M|        value.v.string_value = ctx->scratch_buffer;
  419|  23.3M|    } else if (col_info->type == READSTAT_TYPE_DOUBLE) {
  ------------------
  |  Branch (419:16): [True: 113k, False: 0]
  ------------------
  420|   113k|        uint64_t  val = 0;
  421|   113k|        double dval = NAN;
  422|   113k|        if (ctx->little_endian) {
  ------------------
  |  Branch (422:13): [True: 113k, False: 0]
  ------------------
  423|   113k|            int k;
  424|   695k|            for (k=0; k<col_info->width; k++) {
  ------------------
  |  Branch (424:23): [True: 581k, False: 113k]
  ------------------
  425|   581k|                val = (val << 8) | (unsigned char)col_data[col_info->width-1-k];
  426|   581k|            }
  427|   113k|        } else {
  428|      0|            int k;
  429|      0|            for (k=0; k<col_info->width; k++) {
  ------------------
  |  Branch (429:23): [True: 0, False: 0]
  ------------------
  430|      0|                val = (val << 8) | (unsigned char)col_data[k];
  431|      0|            }
  432|      0|        }
  433|   113k|        val <<= (8-col_info->width)*8;
  434|       |
  435|   113k|        memcpy(&dval, &val, 8);
  436|       |
  437|   113k|        if (isnan(dval)) {
  ------------------
  |  Branch (437:13): [True: 13.6k, False: 99.5k]
  ------------------
  438|  13.6k|            value.v.double_value = NAN;
  439|  13.6k|            sas_assign_tag(&value, ~((val >> 40) & 0xFF));
  440|  99.5k|        } else {
  441|  99.5k|            value.v.double_value = dval;
  442|  99.5k|        }
  443|   113k|    }
  444|  23.4M|    cb_retval = ctx->handle.value(ctx->parsed_row_count, variable, value, ctx->user_ctx);
  445|       |
  446|  23.4M|    if (cb_retval != READSTAT_HANDLER_OK)
  ------------------
  |  Branch (446:9): [True: 0, False: 23.4M]
  ------------------
  447|      0|        retval = READSTAT_ERROR_USER_ABORT;
  448|       |
  449|  23.4M|cleanup:
  450|  23.4M|    return retval;
  451|  23.4M|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_compressed:
  625|  1.19k|static readstat_error_t sas7bdat_parse_subheader_compressed(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  626|  1.19k|    if (ctx->rdc_compression)
  ------------------
  |  Branch (626:9): [True: 321, False: 878]
  ------------------
  627|    321|        return sas7bdat_parse_subheader_rdc(subheader, len, ctx);
  628|       |
  629|    878|    return sas7bdat_parse_subheader_rle(subheader, len, ctx);
  630|  1.19k|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_rdc:
  512|    321|static readstat_error_t sas7bdat_parse_subheader_rdc(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  513|    321|    readstat_error_t retval = READSTAT_OK;
  514|    321|    const unsigned char *input = (const unsigned char *)subheader;
  515|    321|    char *buffer = malloc(ctx->row_length);
  516|    321|    char *output = buffer;
  517|  1.91k|    while (input + 2 <= (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (517:12): [True: 1.63k, False: 279]
  ------------------
  518|  1.63k|        int i;
  519|  1.63k|        unsigned short prefix = (input[0] << 8) + input[1];
  520|  1.63k|        input += 2;
  521|  24.4k|        for (i=0; i<16; i++) {
  ------------------
  |  Branch (521:19): [True: 23.1k, False: 1.33k]
  ------------------
  522|  23.1k|            if ((prefix & (1 << (15 - i))) == 0) {
  ------------------
  |  Branch (522:17): [True: 16.1k, False: 6.97k]
  ------------------
  523|  16.1k|                if (input + 1 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (523:21): [True: 263, False: 15.8k]
  ------------------
  524|    263|                    break;
  525|    263|                }
  526|  15.8k|                if (output + 1 > buffer + ctx->row_length) {
  ------------------
  |  Branch (526:21): [True: 4, False: 15.8k]
  ------------------
  527|      4|                    retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  528|      4|                    goto cleanup;
  529|      4|                }
  530|  15.8k|                *output++ = *input++;
  531|  15.8k|                continue;
  532|  15.8k|            }
  533|       |
  534|  6.97k|            if (input + 2 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (534:17): [True: 1, False: 6.97k]
  ------------------
  535|      1|                retval = READSTAT_ERROR_PARSE;
  536|      1|                goto cleanup;
  537|      1|            }
  538|       |
  539|  6.97k|            unsigned char marker_byte = *input++;
  540|  6.97k|            unsigned char next_byte = *input++;
  541|  6.97k|            size_t insert_len = 0, copy_len = 0;
  542|  6.97k|            unsigned char insert_byte = 0x00;
  543|  6.97k|            size_t back_offset = 0;
  544|       |
  545|  6.97k|            if (marker_byte <= 0x0F) {
  ------------------
  |  Branch (545:17): [True: 2.97k, False: 3.99k]
  ------------------
  546|  2.97k|                insert_len = 3 + marker_byte;
  547|  2.97k|                insert_byte = next_byte;
  548|  3.99k|            } else if ((marker_byte >> 4) == 1) {
  ------------------
  |  Branch (548:24): [True: 1.07k, False: 2.92k]
  ------------------
  549|  1.07k|                if (input + 1 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (549:21): [True: 1, False: 1.07k]
  ------------------
  550|      1|                    retval = READSTAT_ERROR_PARSE;
  551|      1|                    goto cleanup;
  552|      1|                }
  553|  1.07k|                insert_len = 19 + (marker_byte & 0x0F) + next_byte * 16;
  554|  1.07k|                insert_byte = *input++;
  555|  2.92k|            } else if ((marker_byte >> 4) == 2) {
  ------------------
  |  Branch (555:24): [True: 299, False: 2.62k]
  ------------------
  556|    299|                if (input + 1 > (const unsigned char *)subheader + len) {
  ------------------
  |  Branch (556:21): [True: 2, False: 297]
  ------------------
  557|      2|                    retval = READSTAT_ERROR_PARSE;
  558|      2|                    goto cleanup;
  559|      2|                }
  560|    297|                copy_len = 16 + (*input++);
  561|    297|                back_offset = 3 + (marker_byte & 0x0F) + next_byte * 16;
  562|  2.62k|            } else {
  563|  2.62k|                copy_len = (marker_byte >> 4);
  564|  2.62k|                back_offset = 3 + (marker_byte & 0x0F) + next_byte * 16;
  565|  2.62k|            }
  566|       |
  567|  6.97k|            if (insert_len) {
  ------------------
  |  Branch (567:17): [True: 4.05k, False: 2.91k]
  ------------------
  568|  4.05k|                if (output + insert_len > buffer + ctx->row_length) {
  ------------------
  |  Branch (568:21): [True: 2, False: 4.05k]
  ------------------
  569|      2|                    retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  570|      2|                    goto cleanup;
  571|      2|                }
  572|  4.05k|                memset(output, insert_byte, insert_len);
  573|  4.05k|                output += insert_len;
  574|  4.05k|            } else if (copy_len) {
  ------------------
  |  Branch (574:24): [True: 2.91k, False: 0]
  ------------------
  575|  2.91k|                if (output - buffer < back_offset || copy_len > back_offset) {
  ------------------
  |  Branch (575:21): [True: 14, False: 2.90k]
  |  Branch (575:54): [True: 17, False: 2.88k]
  ------------------
  576|     31|                    retval = READSTAT_ERROR_PARSE;
  577|     31|                    goto cleanup;
  578|     31|                }
  579|  2.88k|                if (output + copy_len > buffer + ctx->row_length) {
  ------------------
  |  Branch (579:21): [True: 1, False: 2.88k]
  ------------------
  580|      1|                    retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  581|      1|                    goto cleanup;
  582|      1|                }
  583|  2.88k|                memcpy(output, output - back_offset, copy_len);
  584|  2.88k|                output += copy_len;
  585|  2.88k|            }
  586|  6.97k|        }
  587|  1.63k|    }
  588|       |
  589|    279|    if (output - buffer != ctx->row_length) {
  ------------------
  |  Branch (589:9): [True: 29, False: 250]
  ------------------
  590|     29|        retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  591|     29|        goto cleanup;
  592|     29|    }
  593|    250|    retval = sas7bdat_parse_single_row(buffer, ctx);
  594|    321|cleanup:
  595|    321|    free(buffer);
  596|       |
  597|    321|    return retval;
  598|    250|}
readstat_sas7bdat_read.c:sas7bdat_parse_subheader_rle:
  600|    878|static readstat_error_t sas7bdat_parse_subheader_rle(const char *subheader, size_t len, sas7bdat_ctx_t *ctx) {
  601|    878|    if (ctx->row_limit == ctx->parsed_row_count)
  ------------------
  |  Branch (601:9): [True: 531, False: 347]
  ------------------
  602|    531|        return READSTAT_OK;
  603|       |
  604|    347|    readstat_error_t retval = READSTAT_OK;
  605|    347|    ssize_t bytes_decompressed = 0;
  606|       |
  607|    347|    bytes_decompressed = sas_rle_decompress(ctx->row, ctx->row_length, subheader, len);
  608|       |
  609|    347|    if (bytes_decompressed != ctx->row_length) {
  ------------------
  |  Branch (609:9): [True: 155, False: 192]
  ------------------
  610|    155|        retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  611|    155|        if (ctx->handle.error) {
  ------------------
  |  Branch (611:13): [True: 0, False: 155]
  ------------------
  612|      0|            snprintf(ctx->error_buf, sizeof(ctx->error_buf), 
  613|      0|                    "ReadStat: Row #%d decompressed to %ld bytes (expected %d bytes)",
  614|      0|                    ctx->parsed_row_count, (long)(bytes_decompressed), ctx->row_length);
  615|      0|            ctx->handle.error(ctx->error_buf, ctx->user_ctx);
  616|      0|        }
  617|    155|        goto cleanup;
  618|    155|    }
  619|    192|    retval = sas7bdat_parse_single_row(ctx->row, ctx);
  620|       |
  621|    347|cleanup:
  622|    347|    return retval;
  623|    192|}
readstat_sas7bdat_read.c:sas7bdat_parse_rows:
  493|  1.55k|static readstat_error_t sas7bdat_parse_rows(const char *data, size_t len, sas7bdat_ctx_t *ctx) {
  494|  1.55k|    readstat_error_t retval = READSTAT_OK;
  495|  1.55k|    int i;
  496|  1.55k|    size_t row_offset=0;
  497|   169k|    for (i=0; i<ctx->page_row_count && ctx->parsed_row_count < ctx->row_limit; i++) {
  ------------------
  |  Branch (497:15): [True: 168k, False: 1.35k]
  |  Branch (497:40): [True: 168k, False: 22]
  ------------------
  498|   168k|        if (row_offset + ctx->row_length > len) {
  ------------------
  |  Branch (498:13): [True: 115, False: 168k]
  ------------------
  499|    115|            retval = READSTAT_ERROR_ROW_WIDTH_MISMATCH;
  500|    115|            goto cleanup;
  501|    115|        }
  502|   168k|        if ((retval = sas7bdat_parse_single_row(&data[row_offset], ctx)) != READSTAT_OK)
  ------------------
  |  Branch (502:13): [True: 69, False: 168k]
  ------------------
  503|     69|            goto cleanup;
  504|       |
  505|   168k|        row_offset += ctx->row_length;
  506|   168k|    }
  507|       |
  508|  1.55k|cleanup:
  509|  1.55k|    return retval;
  510|  1.55k|}
readstat_sas7bdat_read.c:sas7bdat_submit_columns_if_needed:
  799|  3.93k|static readstat_error_t sas7bdat_submit_columns_if_needed(sas7bdat_ctx_t *ctx, int compressed) {
  800|  3.93k|    readstat_error_t retval = READSTAT_OK;
  801|  3.93k|    if (!ctx->did_submit_columns) {
  ------------------
  |  Branch (801:9): [True: 1.40k, False: 2.53k]
  ------------------
  802|  1.40k|        if ((retval = sas7bdat_submit_columns(ctx, compressed)) != READSTAT_OK) {
  ------------------
  |  Branch (802:13): [True: 258, False: 1.14k]
  ------------------
  803|    258|            goto cleanup;
  804|    258|        }
  805|  1.14k|        ctx->did_submit_columns = 1;
  806|  1.14k|    }
  807|  3.93k|cleanup:
  808|  3.93k|    return retval;
  809|  3.93k|}
readstat_sas7bdat_read.c:sas7bdat_submit_columns:
  738|  1.40k|static readstat_error_t sas7bdat_submit_columns(sas7bdat_ctx_t *ctx, int compressed) {
  739|  1.40k|    readstat_error_t retval = READSTAT_OK;
  740|  1.40k|    if (ctx->handle.metadata) {
  ------------------
  |  Branch (740:9): [True: 1.40k, False: 0]
  ------------------
  741|  1.40k|        readstat_metadata_t metadata = {
  742|  1.40k|            .row_count = ctx->row_limit,
  743|  1.40k|            .var_count = ctx->column_count,
  744|  1.40k|            .table_name = ctx->table_name,
  745|  1.40k|            .file_label = ctx->file_label,
  746|  1.40k|            .file_encoding = ctx->input_encoding, /* orig encoding? */
  747|  1.40k|            .creation_time = ctx->ctime,
  748|  1.40k|            .modified_time = ctx->mtime,
  749|  1.40k|            .file_format_version = ctx->version,
  750|  1.40k|            .compression = READSTAT_COMPRESS_NONE,
  751|  1.40k|            .endianness = ctx->little_endian ? READSTAT_ENDIAN_LITTLE : READSTAT_ENDIAN_BIG,
  ------------------
  |  Branch (751:27): [True: 255, False: 1.14k]
  ------------------
  752|  1.40k|            .is64bit = ctx->u64
  753|  1.40k|        };
  754|  1.40k|        if (compressed) {
  ------------------
  |  Branch (754:13): [True: 578, False: 824]
  ------------------
  755|    578|            if (ctx->rdc_compression) {
  ------------------
  |  Branch (755:17): [True: 68, False: 510]
  ------------------
  756|     68|                metadata.compression = READSTAT_COMPRESS_BINARY;
  757|    510|            } else {
  758|    510|                metadata.compression = READSTAT_COMPRESS_ROWS;
  759|    510|            }
  760|    578|        }
  761|  1.40k|        if (ctx->handle.metadata(&metadata, ctx->user_ctx) != READSTAT_HANDLER_OK) {
  ------------------
  |  Branch (761:13): [True: 0, False: 1.40k]
  ------------------
  762|      0|            retval = READSTAT_ERROR_USER_ABORT;
  763|      0|            goto cleanup;
  764|      0|        }
  765|  1.40k|    }
  766|  1.40k|    if (ctx->column_count == 0)
  ------------------
  |  Branch (766:9): [True: 919, False: 483]
  ------------------
  767|    919|        goto cleanup;
  768|       |
  769|    483|    if ((ctx->variables = readstat_calloc(ctx->column_count, sizeof(readstat_variable_t *))) == NULL) {
  ------------------
  |  Branch (769:9): [True: 0, False: 483]
  ------------------
  770|      0|        retval = READSTAT_ERROR_MALLOC;
  771|      0|        goto cleanup;
  772|      0|    }
  773|    483|    int i;
  774|    483|    int index_after_skipping = 0;
  775|  3.57M|    for (i=0; i<ctx->column_count; i++) {
  ------------------
  |  Branch (775:15): [True: 3.57M, False: 225]
  ------------------
  776|  3.57M|        ctx->variables[i] = sas7bdat_init_variable(ctx, i, index_after_skipping, &retval);
  777|  3.57M|        if (ctx->variables[i] == NULL)
  ------------------
  |  Branch (777:13): [True: 258, False: 3.57M]
  ------------------
  778|    258|            break;
  779|       |
  780|  3.57M|        int cb_retval = READSTAT_HANDLER_OK;
  781|  3.57M|        if (ctx->handle.variable) {
  ------------------
  |  Branch (781:13): [True: 3.57M, False: 0]
  ------------------
  782|  3.57M|            cb_retval = ctx->handle.variable(i, ctx->variables[i], ctx->variables[i]->format, ctx->user_ctx);
  783|  3.57M|        }
  784|  3.57M|        if (cb_retval == READSTAT_HANDLER_ABORT) {
  ------------------
  |  Branch (784:13): [True: 0, False: 3.57M]
  ------------------
  785|      0|            retval = READSTAT_ERROR_USER_ABORT;
  786|      0|            goto cleanup;
  787|      0|        }
  788|       |
  789|  3.57M|        if (cb_retval == READSTAT_HANDLER_SKIP_VARIABLE) {
  ------------------
  |  Branch (789:13): [True: 0, False: 3.57M]
  ------------------
  790|      0|            ctx->variables[i]->skip = 1;
  791|  3.57M|        } else {
  792|  3.57M|            index_after_skipping++;
  793|  3.57M|        }
  794|  3.57M|    }
  795|  1.40k|cleanup:
  796|  1.40k|    return retval;
  797|    483|}
readstat_sas7bdat_read.c:sas7bdat_init_variable:
  682|  3.57M|        int index_after_skipping, readstat_error_t *out_retval) {
  683|  3.57M|    readstat_error_t retval = READSTAT_OK;
  684|  3.57M|    readstat_variable_t *variable = readstat_calloc(1, sizeof(readstat_variable_t));
  685|       |
  686|  3.57M|    variable->index = i;
  687|  3.57M|    variable->index_after_skipping = index_after_skipping;
  688|  3.57M|    variable->type = ctx->col_info[i].type;
  689|  3.57M|    variable->storage_width = ctx->col_info[i].width;
  690|       |
  691|  3.57M|    if ((retval = sas7bdat_validate_column(&ctx->col_info[i])) != READSTAT_OK) {
  ------------------
  |  Branch (691:9): [True: 90, False: 3.57M]
  ------------------
  692|     90|        goto cleanup;
  693|     90|    }
  694|  3.57M|    if ((retval = sas7bdat_copy_text_ref(variable->name, sizeof(variable->name), 
  ------------------
  |  Branch (694:9): [True: 60, False: 3.57M]
  ------------------
  695|  3.57M|                    ctx->col_info[i].name_ref, ctx)) != READSTAT_OK) {
  696|     60|        goto cleanup;
  697|     60|    }
  698|  3.57M|    if ((retval = sas7bdat_copy_text_ref(variable->format, sizeof(variable->format),
  ------------------
  |  Branch (698:9): [True: 51, False: 3.57M]
  ------------------
  699|  3.57M|                    ctx->col_info[i].format_ref, ctx)) != READSTAT_OK) {
  700|     51|        goto cleanup;
  701|     51|    }
  702|  3.57M|    size_t len = strlen(variable->format);
  703|  3.57M|    if (ctx->col_info[i].format_width) {
  ------------------
  |  Branch (703:9): [True: 521, False: 3.57M]
  ------------------
  704|    521|        len += snprintf(variable->format + len, sizeof(variable->format) - len,
  705|    521|                "%d", ctx->col_info[i].format_width);
  706|    521|    }
  707|  3.57M|    if (len && ctx->col_info[i].format_digits) {
  ------------------
  |  Branch (707:9): [True: 545, False: 3.57M]
  |  Branch (707:16): [True: 358, False: 187]
  ------------------
  708|    358|        len += snprintf(variable->format + len, sizeof(variable->format) - len,
  709|    358|                ".%d", ctx->col_info[i].format_digits);
  710|    358|    }
  711|  3.57M|    if ((retval = sas7bdat_copy_text_ref(variable->label, sizeof(variable->label), 
  ------------------
  |  Branch (711:9): [True: 57, False: 3.57M]
  ------------------
  712|  3.57M|                    ctx->col_info[i].label_ref, ctx)) != READSTAT_OK) {
  713|     57|        goto cleanup;
  714|     57|    }
  715|       |
  716|  3.57M|cleanup:
  717|  3.57M|    if (retval != READSTAT_OK) {
  ------------------
  |  Branch (717:9): [True: 258, False: 3.57M]
  ------------------
  718|    258|        if (out_retval)
  ------------------
  |  Branch (718:13): [True: 258, False: 0]
  ------------------
  719|    258|            *out_retval = retval;
  720|       |
  721|    258|        if (retval == READSTAT_ERROR_CONVERT_BAD_STRING) {
  ------------------
  |  Branch (721:13): [True: 8, False: 250]
  ------------------
  722|      8|            if (ctx->handle.error) {
  ------------------
  |  Branch (722:17): [True: 0, False: 8]
  ------------------
  723|      0|                snprintf(ctx->error_buf, sizeof(ctx->error_buf),
  724|      0|                        "ReadStat: Error converting variable #%d info to specified encoding: %s %s (%s)",
  725|      0|                        i, variable->name, variable->format, variable->label);
  726|      0|                ctx->handle.error(ctx->error_buf, ctx->user_ctx);
  727|      0|            }
  728|      8|        }
  729|       |
  730|    258|        free(variable);
  731|       |
  732|    258|        return NULL;
  733|    258|    }
  734|       |
  735|  3.57M|    return variable;
  736|  3.57M|}
readstat_sas7bdat_read.c:sas7bdat_validate_column:
  667|  3.57M|static readstat_error_t sas7bdat_validate_column(col_info_t *col_info) {
  668|  3.57M|    if (col_info->type == READSTAT_TYPE_DOUBLE) {
  ------------------
  |  Branch (668:9): [True: 833, False: 3.57M]
  ------------------
  669|    833|        if (col_info->width > 8 || col_info->width < 3) {
  ------------------
  |  Branch (669:13): [True: 47, False: 786]
  |  Branch (669:36): [True: 2, False: 784]
  ------------------
  670|     49|            return READSTAT_ERROR_PARSE;
  671|     49|        }
  672|    833|    }
  673|  3.57M|    if (col_info->type == READSTAT_TYPE_STRING) {
  ------------------
  |  Branch (673:9): [True: 3.57M, False: 784]
  ------------------
  674|  3.57M|        if (col_info->width > INT16_MAX) {
  ------------------
  |  Branch (674:13): [True: 41, False: 3.57M]
  ------------------
  675|     41|            return READSTAT_ERROR_PARSE;
  676|     41|        }
  677|  3.57M|    }
  678|  3.57M|    return READSTAT_OK;
  679|  3.57M|}
readstat_sas7bdat_read.c:sas7bdat_update_progress:
  128|  4.36k|static readstat_error_t sas7bdat_update_progress(sas7bdat_ctx_t *ctx) {
  129|  4.36k|    readstat_io_t *io = ctx->io;
  130|  4.36k|    return io->update(ctx->file_size, ctx->handle.progress, ctx->user_ctx, io->io_ctx);
  131|  4.36k|}
readstat_sas7bdat_read.c:sas7bdat_ctx_free:
   94|  3.75k|static void sas7bdat_ctx_free(sas7bdat_ctx_t *ctx) {
   95|  3.75k|    int i;
   96|  3.75k|    if (ctx->text_blobs) {
  ------------------
  |  Branch (96:9): [True: 901, False: 2.85k]
  ------------------
   97|  3.63k|        for (i=0; i<ctx->text_blob_count; i++) {
  ------------------
  |  Branch (97:19): [True: 2.73k, False: 901]
  ------------------
   98|  2.73k|            free(ctx->text_blobs[i]);
   99|  2.73k|        }
  100|    901|        free(ctx->text_blobs);
  101|    901|        free(ctx->text_blob_lengths);
  102|    901|    }
  103|  3.75k|    if (ctx->variables) {
  ------------------
  |  Branch (103:9): [True: 483, False: 3.27k]
  ------------------
  104|  19.3M|        for (i=0; i<ctx->column_count; i++) {
  ------------------
  |  Branch (104:19): [True: 19.3M, False: 483]
  ------------------
  105|  19.3M|            if (ctx->variables[i])
  ------------------
  |  Branch (105:17): [True: 3.57M, False: 15.7M]
  ------------------
  106|  3.57M|                free(ctx->variables[i]);
  107|  19.3M|        }
  108|    483|        free(ctx->variables);
  109|    483|    }
  110|  3.75k|    if (ctx->col_info)
  ------------------
  |  Branch (110:9): [True: 632, False: 3.12k]
  ------------------
  111|    632|        free(ctx->col_info);
  112|       |
  113|  3.75k|    if (ctx->scratch_buffer)
  ------------------
  |  Branch (113:9): [True: 547, False: 3.20k]
  ------------------
  114|    547|        free(ctx->scratch_buffer);
  115|       |
  116|  3.75k|    if (ctx->page)
  ------------------
  |  Branch (116:9): [True: 3.20k, False: 547]
  ------------------
  117|  3.20k|        free(ctx->page);
  118|       |
  119|  3.75k|    if (ctx->row)
  ------------------
  |  Branch (119:9): [True: 1.04k, False: 2.71k]
  ------------------
  120|  1.04k|        free(ctx->row);
  121|       |
  122|  3.75k|    if (ctx->converter)
  ------------------
  |  Branch (122:9): [True: 2.31k, False: 1.44k]
  ------------------
  123|  2.31k|        iconv_close(ctx->converter);
  124|       |
  125|  3.75k|    free(ctx);
  126|  3.75k|}

sas_rle_decompress:
   47|    347|        const void *input_buf, size_t input_len) {
   48|    347|    unsigned char *buffer = (unsigned char *)output_buf;
   49|    347|    unsigned char *output = buffer;
   50|    347|    size_t output_written = 0;
   51|       |
   52|    347|    const unsigned char *input = (const unsigned char *)input_buf;
   53|       |
   54|  30.9k|    while (input < (const unsigned char *)input_buf + input_len) {
  ------------------
  |  Branch (54:12): [True: 30.7k, False: 216]
  ------------------
   55|  30.7k|        unsigned char control = *input++;
   56|  30.7k|        unsigned char command = (control & 0xF0) >> 4;
   57|  30.7k|        unsigned char length = (control & 0x0F);
   58|  30.7k|        int copy_len = 0;
   59|  30.7k|        int insert_len = 0;
   60|  30.7k|        unsigned char insert_byte = '\0';
   61|  30.7k|        if (input + command_lengths[command] > (const unsigned char *)input_buf + input_len) {
  ------------------
  |  Branch (61:13): [True: 8, False: 30.7k]
  ------------------
   62|      8|            return -1;
   63|      8|        }
   64|  30.7k|        switch (command) {
   65|  3.38k|            case SAS_RLE_COMMAND_COPY64:
  ------------------
  |  |   13|  3.38k|#define SAS_RLE_COMMAND_COPY64          0
  ------------------
  |  Branch (65:13): [True: 3.38k, False: 27.3k]
  ------------------
   66|  3.38k|                copy_len = (*input++) + 64 + length * 256;
   67|  3.38k|                break;
   68|    119|            case SAS_RLE_COMMAND_COPY64_PLUS_4096:
  ------------------
  |  |   14|    119|#define SAS_RLE_COMMAND_COPY64_PLUS_4096 1
  ------------------
  |  Branch (68:13): [True: 119, False: 30.6k]
  ------------------
   69|    119|                copy_len = (*input++) + 64 + length * 256 + 4096;
   70|    119|                break;
   71|    724|            case SAS_RLE_COMMAND_COPY96: copy_len = length + 96; break;
  ------------------
  |  |   15|    724|#define SAS_RLE_COMMAND_COPY96          2
  ------------------
  |  Branch (71:13): [True: 724, False: 30.0k]
  ------------------
   72|    726|            case SAS_RLE_COMMAND_INSERT_BYTE18:
  ------------------
  |  |   16|    726|#define SAS_RLE_COMMAND_INSERT_BYTE18   4
  ------------------
  |  Branch (72:13): [True: 726, False: 30.0k]
  ------------------
   73|    726|                insert_len = (*input++) + 18 + length * 256;
   74|    726|                insert_byte = *input++;
   75|    726|                break;
   76|    688|            case SAS_RLE_COMMAND_INSERT_AT17:
  ------------------
  |  |   17|    688|#define SAS_RLE_COMMAND_INSERT_AT17     5
  ------------------
  |  Branch (76:13): [True: 688, False: 30.0k]
  ------------------
   77|    688|                insert_len = (*input++) + 17 + length * 256;
   78|    688|                insert_byte = '@';
   79|    688|                break;
   80|    753|            case SAS_RLE_COMMAND_INSERT_BLANK17:
  ------------------
  |  |   18|    753|#define SAS_RLE_COMMAND_INSERT_BLANK17  6
  ------------------
  |  Branch (80:13): [True: 753, False: 29.9k]
  ------------------
   81|    753|                insert_len = (*input++) + 17 + length * 256;
   82|    753|                insert_byte = ' ';
   83|    753|                break;
   84|  1.75k|            case SAS_RLE_COMMAND_INSERT_ZERO17:
  ------------------
  |  |   19|  1.75k|#define SAS_RLE_COMMAND_INSERT_ZERO17   7
  ------------------
  |  Branch (84:13): [True: 1.75k, False: 28.9k]
  ------------------
   85|  1.75k|                insert_len = (*input++) + 17 + length * 256;
   86|  1.75k|                insert_byte = '\0';
   87|  1.75k|                break;
   88|    820|            case SAS_RLE_COMMAND_COPY1:  copy_len = length + 1; break;
  ------------------
  |  |   20|    820|#define SAS_RLE_COMMAND_COPY1           8
  ------------------
  |  Branch (88:13): [True: 820, False: 29.9k]
  ------------------
   89|    313|            case SAS_RLE_COMMAND_COPY17: copy_len = length + 17; break;
  ------------------
  |  |   21|    313|#define SAS_RLE_COMMAND_COPY17          9
  ------------------
  |  Branch (89:13): [True: 313, False: 30.4k]
  ------------------
   90|    603|            case SAS_RLE_COMMAND_COPY33: copy_len = length + 33; break;
  ------------------
  |  |   22|    603|#define SAS_RLE_COMMAND_COPY33         10
  ------------------
  |  Branch (90:13): [True: 603, False: 30.1k]
  ------------------
   91|    361|            case SAS_RLE_COMMAND_COPY49: copy_len = length + 49; break;
  ------------------
  |  |   23|    361|#define SAS_RLE_COMMAND_COPY49         11
  ------------------
  |  Branch (91:13): [True: 361, False: 30.3k]
  ------------------
   92|    788|            case SAS_RLE_COMMAND_INSERT_BYTE3:
  ------------------
  |  |   24|    788|#define SAS_RLE_COMMAND_INSERT_BYTE3   12
  ------------------
  |  Branch (92:13): [True: 788, False: 29.9k]
  ------------------
   93|    788|                insert_byte = *input++;
   94|    788|                insert_len = length + 3;
   95|    788|                break;
   96|    716|            case SAS_RLE_COMMAND_INSERT_AT2:
  ------------------
  |  |   25|    716|#define SAS_RLE_COMMAND_INSERT_AT2     13
  ------------------
  |  Branch (96:13): [True: 716, False: 30.0k]
  ------------------
   97|    716|                insert_byte = '@';
   98|    716|                insert_len = length + 2;
   99|    716|                break;
  100|  12.0k|            case SAS_RLE_COMMAND_INSERT_BLANK2:
  ------------------
  |  |   26|  12.0k|#define SAS_RLE_COMMAND_INSERT_BLANK2  14
  ------------------
  |  Branch (100:13): [True: 12.0k, False: 18.6k]
  ------------------
  101|  12.0k|                insert_byte = ' ';
  102|  12.0k|                insert_len = length + 2;
  103|  12.0k|                break;
  104|  4.35k|            case SAS_RLE_COMMAND_INSERT_ZERO2:
  ------------------
  |  |   27|  4.35k|#define SAS_RLE_COMMAND_INSERT_ZERO2   15
  ------------------
  |  Branch (104:13): [True: 4.35k, False: 26.3k]
  ------------------
  105|  4.35k|                insert_byte = '\0';
  106|  4.35k|                insert_len = length + 2;
  107|  4.35k|                break;
  108|  2.58k|            default:
  ------------------
  |  Branch (108:13): [True: 2.58k, False: 28.1k]
  ------------------
  109|       |                /* error out here? */
  110|  2.58k|                break;
  111|  30.7k|        }
  112|  30.7k|        if (copy_len) {
  ------------------
  |  Branch (112:13): [True: 6.32k, False: 24.3k]
  ------------------
  113|  6.32k|            if (output_written + copy_len > output_len) {
  ------------------
  |  Branch (113:17): [True: 20, False: 6.30k]
  ------------------
  114|     20|                return -1;
  115|     20|            }
  116|  6.30k|            if (input + copy_len > (const unsigned char *)input_buf + input_len) {
  ------------------
  |  Branch (116:17): [True: 88, False: 6.22k]
  ------------------
  117|     88|                return -1;
  118|     88|            }
  119|  6.22k|            if (output) {
  ------------------
  |  Branch (119:17): [True: 6.22k, False: 0]
  ------------------
  120|  6.22k|                memcpy(&output[output_written], input, copy_len);
  121|  6.22k|            }
  122|  6.22k|            input += copy_len;
  123|  6.22k|            output_written += copy_len;
  124|  6.22k|        }
  125|  30.6k|        if (insert_len) {
  ------------------
  |  Branch (125:13): [True: 21.8k, False: 8.80k]
  ------------------
  126|  21.8k|            if (output_written + insert_len > output_len) {
  ------------------
  |  Branch (126:17): [True: 15, False: 21.7k]
  ------------------
  127|     15|                return -1;
  128|     15|            }
  129|  21.7k|            if (output) {
  ------------------
  |  Branch (129:17): [True: 21.7k, False: 0]
  ------------------
  130|  21.7k|                memset(&output[output_written], insert_byte, insert_len);
  131|  21.7k|            }
  132|  21.7k|            output_written += insert_len;
  133|  21.7k|        }
  134|  30.6k|    }
  135|       |
  136|    216|    return output_written;
  137|    347|}

rt_open_handler:
    8|  3.75k|int rt_open_handler(const char *path, void *io_ctx) {
    9|  3.75k|    return 0;
   10|  3.75k|}
rt_close_handler:
   12|  3.75k|int rt_close_handler(void *io_ctx) {
   13|  3.75k|    return 0;
   14|  3.75k|}
rt_seek_handler:
   17|  30.6k|        readstat_io_flags_t whence, void *io_ctx) {
   18|  30.6k|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   19|  30.6k|    readstat_off_t newpos = -1;
   20|  30.6k|    if (whence == READSTAT_SEEK_SET) {
  ------------------
  |  Branch (20:9): [True: 19.9k, False: 10.7k]
  ------------------
   21|  19.9k|        newpos = offset;
   22|  19.9k|    } else if (whence == READSTAT_SEEK_CUR) {
  ------------------
  |  Branch (22:16): [True: 6.99k, False: 3.75k]
  ------------------
   23|  6.99k|        newpos = buffer_ctx->pos + offset;
   24|  6.99k|    } else if (whence == READSTAT_SEEK_END) {
  ------------------
  |  Branch (24:16): [True: 3.75k, False: 0]
  ------------------
   25|  3.75k|        newpos = buffer_ctx->buffer->used + offset;
   26|  3.75k|    }
   27|       |
   28|  30.6k|    if (newpos < 0)
  ------------------
  |  Branch (28:9): [True: 133, False: 30.5k]
  ------------------
   29|    133|        return -1;
   30|       |
   31|  30.5k|    if (newpos > buffer_ctx->buffer->used)
  ------------------
  |  Branch (31:9): [True: 244, False: 30.3k]
  ------------------
   32|    244|        return -1;
   33|       |
   34|  30.3k|    buffer_ctx->pos = newpos;
   35|  30.3k|    return newpos;
   36|  30.5k|}
rt_read_handler:
   38|  53.3k|ssize_t rt_read_handler(void *buf, size_t nbytes, void *io_ctx) {
   39|  53.3k|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   40|  53.3k|    ssize_t bytes_copied = 0;
   41|  53.3k|    ssize_t bytes_left = buffer_ctx->buffer->used - buffer_ctx->pos;
   42|  53.3k|    if (nbytes <= bytes_left) {
  ------------------
  |  Branch (42:9): [True: 52.9k, False: 451]
  ------------------
   43|  52.9k|        memcpy(buf, buffer_ctx->buffer->bytes + buffer_ctx->pos, nbytes);
   44|  52.9k|        bytes_copied = nbytes;
   45|  52.9k|    } else if (bytes_left > 0) {
  ------------------
  |  Branch (45:16): [True: 227, False: 224]
  ------------------
   46|    227|        memcpy(buf, buffer_ctx->buffer->bytes + buffer_ctx->pos, bytes_left);
   47|    227|        bytes_copied = bytes_left;
   48|    227|    }
   49|  53.3k|    buffer_ctx->pos += bytes_copied;
   50|  53.3k|    return bytes_copied;
   51|  53.3k|}
rt_update_handler:
   54|  4.36k|        void *user_ctx, void *io_ctx) {
   55|  4.36k|    if (!progress_handler)
  ------------------
  |  Branch (55:9): [True: 4.36k, False: 0]
  ------------------
   56|  4.36k|        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|}

