Example #1
0
static clj_Result read_comment(clj_Reader *r, wint_t initch) {
  wint_t c;
  do {
    c = pop_char(r);
  } while (!ends_line(c) && c != WEOF);
  return ok_read(c);
}
Example #2
0
static clj_Result read_token(clj_Type type, clj_Reader *r, wint_t initch,
                             size_t initial_capacity, char_pred terminates) {
  wint_t c;
  StringBuffer strbuf;
  strbuf_init(&strbuf, initial_capacity);
  strbuf_append(&strbuf, initch);
  while (1) {
    c = pop_char(r);
    if (WEOF == c || is_clj_whitespace(c) || terminates(c)) {
      push_char(r, c);
      emit(r, type, strbuf.chars);
      strbuf_free(&strbuf);
      break;
    } else {
      strbuf_append(&strbuf, c);
    }
  }
  return ok_read(c);
}
Example #3
0
static void decode_fnt2(fnt_decoder *decoder) {
    ok_fnt *fnt = decoder->fnt;

    uint8_t header[4];
    if (!ok_read(decoder, header, sizeof(header))) {
        return;
    }
    if (memcmp("BMF", header, 3) != 0) {
        ok_fnt_error(fnt, "Not an AngelCode binary FNT file.");
        return;
    }
    if (header[3] != 3) {
        ok_fnt_error(fnt, "Version %i of AngelCode binary FNT file not supported (only version 3 supported).",
                     header[3]);
        return;
    }

    uint32_t block_types_found = 0;
    while (true) {

        uint8_t block_header[5];
        if (decoder->input_func(decoder->input_data, block_header, sizeof(block_header)) != sizeof(block_header)) {
            // Don't give an error if all required blocks have been found.
            const bool all_required_blocks_found = (block_types_found & 0x1E) == 0x1E;
            if (!all_required_blocks_found) {
                ok_fnt_error(decoder->fnt, "Read error: error calling input function.");
            }
            return;
        }

        block_type block_type = block_header[0];
        uint32_t block_length = readLE32(block_header + 1);

        block_types_found |= (1 << block_type);
        switch (block_type) {

        case BLOCK_TYPE_INFO: {
            uint8_t info_header[14];
            const int name_buffer_length = block_length - sizeof(info_header);
            if (name_buffer_length <= 0) {
                ok_fnt_error(fnt, "Invalid info block");
                return;
            }
            if (!ok_read(decoder, info_header, sizeof(info_header))) {
                return;
            }
            // Get the fnt size, ignore the rest
            fnt->size = readLE16(info_header);

            // Get the fnt name
            fnt->name = malloc(name_buffer_length);
            if (!fnt->name) {
                ok_fnt_error(fnt, "Couldn't allocate font name");
                return;
            }
            if (!ok_read(decoder, (uint8_t*)fnt->name, name_buffer_length)) {
                return;
            }
            // Sanity check - make sure the string has a null-terminator
            fnt->name[name_buffer_length - 1] = 0;
            break;
        }

        case BLOCK_TYPE_COMMON: {
            uint8_t common[15];
            if (block_length != sizeof(common)) {
                ok_fnt_error(fnt, "Invalid common block");
                return;
            }
            if (!ok_read(decoder, common, sizeof(common))) {
                return;
            }
            // Get the line height, base, and page count; ignore the rest
            fnt->line_height = readLE16(common);
            fnt->base = readLE16(common + 2);
            fnt->num_pages = readLE16(common + 8);
            break;
        }

        case BLOCK_TYPE_PAGES: {
            if (fnt->num_pages <= 0 || block_length == 0) {
                ok_fnt_error(fnt, "Couldn't get page names");
                return;
            }
            else {
                fnt->page_names = calloc(fnt->num_pages, sizeof(char *));
                if (!fnt->page_names) {
                    fnt->num_pages = 0;
                    ok_fnt_error(fnt, "Couldn't allocate memory for page name array");
                    return;
                }
                // Load everything into the first item; setup pointers below.
                fnt->page_names[0] = malloc(block_length);
                if (!fnt->page_names[0]) {
                    fnt->num_pages = 0;
                    ok_fnt_error(fnt, "Couldn't allocate memory for page names");
                    return;
                }
                if (!ok_read(decoder, (uint8_t*)fnt->page_names[0], block_length)) {
                    return;
                }
                char *pos = fnt->page_names[0];
                char * const end_pos = pos + block_length;
                // Sanity check - make sure there is a null terminator
                *(end_pos - 1) = 0;

                // Set up pointers for each page name
                int next_index = 1;
                while (pos + 1 < end_pos && next_index < fnt->num_pages) {
                    if (*pos == 0) {
                        fnt->page_names[next_index] = pos + 1;
                        next_index++;
                    }
                    pos++;
                }
                // Sanity check - make sure the remaining page names, if any, point somewhere
                for (int i = next_index; i < fnt->num_pages; i++) {
                    fnt->page_names[i] = end_pos - 1;
                }
            }
            break;
        }

        case BLOCK_TYPE_CHARS: {
            uint8_t data[20];
            fnt->num_glyphs = block_length / sizeof(data);
            fnt->glyphs = malloc(fnt->num_glyphs * sizeof(ok_fnt_glyph));
            if (!fnt->glyphs) {
                fnt->num_glyphs = 0;
                ok_fnt_error(fnt, "Couldn't allocate memory for glyphs");
                return;
            }
            // On little-endian systems we could just load the entire block into memory, but we'll assume
            // the byte order is unknown here.
            for (int i = 0; i < fnt->num_glyphs; i++) {
                if (!ok_read(decoder, data, sizeof(data))) {
                    return;
                }
                ok_fnt_glyph *glyph = &fnt->glyphs[i];
                glyph->ch = readLE32(data);
                glyph->x = readLE16(data + 4);
                glyph->y = readLE16(data + 6);
                glyph->width = readLE16(data + 8);
                glyph->height = readLE16(data + 10);
                glyph->offset_x = readLE16(data + 12);
                glyph->offset_y = readLE16(data + 14);
                glyph->advance_x = readLE16(data + 16);
                glyph->page = data[18];
                glyph->channel = data[19];
            }
            break;
        }

        case BLOCK_TYPE_KERNING: {
            uint8_t data[10];
            fnt->num_kerning_pairs = block_length / sizeof(data);
            fnt->kerning_pairs = malloc(fnt->num_kerning_pairs * sizeof(ok_fnt_kerning));
            if (!fnt->kerning_pairs) {
                fnt->num_kerning_pairs = 0;
                ok_fnt_error(fnt, "Couldn't allocate memory for kerning");
                return;
            }
            // On little-endian systems we could just load the entire block into memory, but we'll assume
            // the byte order is unknown here.
            for (int i = 0; i < fnt->num_kerning_pairs; i++) {
                if (!ok_read(decoder, data, sizeof(data))) {
                    return;
                }
                ok_fnt_kerning *kerning = &fnt->kerning_pairs[i];
                kerning->first_char = readLE32(data);
                kerning->second_char = readLE32(data + 4);
                kerning->amount = readLE16(data + 8);
            }
            break;
        }

        default:
            ok_fnt_error(fnt, "Unknown block type: %i", block_type);
            return;
        }
    }
}