FT_Error TA_sfnt_update_hmtx_table(SFNT* sfnt, FONT* font) { SFNT_Table* hmtx_table; FT_Byte* buf_new; FT_ULong buf_len; FT_ULong i; if (sfnt->hmtx_idx == MISSING) return TA_Err_Ok; hmtx_table = &font->tables[sfnt->hmtx_idx]; if (hmtx_table->processed) return TA_Err_Ok; /* the metrics of the added composite element doesn't matter; */ /* for this reason, we simply append two zero bytes, */ /* indicating a zero value in the `leftSideBearing' array */ /* (this works because we don't increase the `numberOfHMetrics' field) */ hmtx_table->len += 2; /* make the allocated buffer length a multiple of 4 */ buf_len = (hmtx_table->len + 3) & ~3; buf_new = (FT_Byte*)realloc(hmtx_table->buf, buf_len); if (!buf_new) { hmtx_table->len -= 2; return FT_Err_Out_Of_Memory; } /* pad end of buffer with zeros */ for (i = hmtx_table->len - 2; i < buf_len; i++) buf_new[i] = 0x00; hmtx_table->buf = buf_new; hmtx_table->checksum = TA_table_compute_checksum(hmtx_table->buf, hmtx_table->len); hmtx_table->processed = 1; return TA_Err_Ok; }
FT_Error TA_font_add_table(FONT* font, SFNT_Table_Info* table_info, FT_ULong tag, FT_ULong len, FT_Byte* buf) { SFNT_Table* tables_new; SFNT_Table* table_last; font->num_tables++; tables_new = (SFNT_Table*)realloc(font->tables, font->num_tables * sizeof (SFNT_Table)); if (!tables_new) { font->num_tables--; return FT_Err_Out_Of_Memory; } else font->tables = tables_new; table_last = &font->tables[font->num_tables - 1]; table_last->tag = tag; table_last->len = len; table_last->buf = buf; table_last->checksum = TA_table_compute_checksum(buf, len); table_last->offset = 0; /* set in `TA_font_compute_table_offsets' */ table_last->data = NULL; table_last->processed = 0; /* link table and table info */ *table_info = font->num_tables - 1; return TA_Err_Ok; }
FT_Error TA_sfnt_update_name_table(SFNT* sfnt, FONT* font) { FT_Error error; SFNT_Table* name_table; FT_Byte* buf; FT_ULong buf_len; Naming_Table n; FT_Byte* p; FT_Byte* startp; FT_Byte* endp; FT_UShort i; if (sfnt->name_idx == MISSING) return TA_Err_Ok; name_table = &font->tables[sfnt->name_idx]; buf = name_table->buf; buf_len = name_table->len; if (name_table->processed) return TA_Err_Ok; p = buf; error = parse_name_header(&p, &n, buf_len, &startp, &endp); if (error) return TA_Err_Ok; /* due to the structure of the `name' table, */ /* we must parse it completely, apply our changes, */ /* and rebuild it from scratch */ error = parse_name_records(&p, &n, buf, startp, endp, font); if (error) goto Exit; error = parse_lang_tag_records(&p, &n, buf, startp, endp); if (error) goto Exit; error = build_name_table(&n, name_table); if (error) goto Exit; name_table->checksum = TA_table_compute_checksum(name_table->buf, name_table->len); Exit: for (i = 0; i < n.name_count; i++) free(n.name_records[i].str); for (i = 0; i < n.lang_tag_count; i++) free(n.lang_tag_records[i].str); free(n.name_records); free(n.lang_tag_records); name_table->processed = 1; return error; }
FT_Error TA_sfnt_build_TTF_header(SFNT* sfnt, FONT* font, FT_Byte** header_buf, FT_ULong* header_len, FT_Int do_complete) { SFNT_Table* tables = font->tables; SFNT_Table_Info* table_infos = sfnt->table_infos; FT_ULong num_table_infos = sfnt->num_table_infos; FT_Byte* buf; FT_ULong len; FT_Byte* table_record; FT_Byte* head_buf = NULL; /* pointer to `head' table */ FT_ULong head_checksum; /* checksum in `head' table */ FT_ULong num_tables_in_header; FT_ULong i; num_tables_in_header = 0; for (i = 0; i < num_table_infos; i++) { /* ignore empty tables */ if (table_infos[i] != MISSING) num_tables_in_header++; } len = 12 + 16 * num_tables_in_header; if (!do_complete) { *header_len = len; return TA_Err_Ok; } buf = (FT_Byte*)malloc(len); if (!buf) return FT_Err_Out_Of_Memory; /* SFNT version */ buf[0] = 0x00; buf[1] = 0x01; buf[2] = 0x00; buf[3] = 0x00; /* number of tables */ buf[4] = HIGH(num_tables_in_header); buf[5] = LOW(num_tables_in_header); /* auxiliary data */ { FT_ULong search_range, entry_selector, range_shift; FT_ULong i, j; for (i = 1, j = 2; j <= num_tables_in_header; i++, j <<= 1) ; entry_selector = i - 1; search_range = 0x10 << entry_selector; range_shift = (num_tables_in_header << 4) - search_range; buf[6] = HIGH(search_range); buf[7] = LOW(search_range); buf[8] = HIGH(entry_selector); buf[9] = LOW(entry_selector); buf[10] = HIGH(range_shift); buf[11] = LOW(range_shift); } /* location of the first table info record */ table_record = &buf[12]; head_checksum = 0; /* loop over all tables */ for (i = 0; i < num_table_infos; i++) { SFNT_Table_Info table_info = table_infos[i]; SFNT_Table* table; /* ignore empty slots */ if (table_info == MISSING) continue; table = &tables[table_info]; if (table->tag == TTAG_head) { FT_ULong date_high; FT_ULong date_low; /* we always reach this IF clause since FreeType would */ /* have aborted already if the `head' table were missing */ head_buf = table->buf; /* reset checksum in `head' table for recalculation */ head_buf[8] = 0x00; head_buf[9] = 0x00; head_buf[10] = 0x00; head_buf[11] = 0x00; /* update modification time */ TA_get_current_time(&date_high, &date_low); head_buf[28] = BYTE1(date_high); head_buf[29] = BYTE2(date_high); head_buf[30] = BYTE3(date_high); head_buf[31] = BYTE4(date_high); head_buf[32] = BYTE1(date_low); head_buf[33] = BYTE2(date_low); head_buf[34] = BYTE3(date_low); head_buf[35] = BYTE4(date_low); table->checksum = TA_table_compute_checksum(table->buf, table->len); } head_checksum += table->checksum; table_record[0] = BYTE1(table->tag); table_record[1] = BYTE2(table->tag); table_record[2] = BYTE3(table->tag); table_record[3] = BYTE4(table->tag); table_record[4] = BYTE1(table->checksum); table_record[5] = BYTE2(table->checksum); table_record[6] = BYTE3(table->checksum); table_record[7] = BYTE4(table->checksum); table_record[8] = BYTE1(table->offset); table_record[9] = BYTE2(table->offset); table_record[10] = BYTE3(table->offset); table_record[11] = BYTE4(table->offset); table_record[12] = BYTE1(table->len); table_record[13] = BYTE2(table->len); table_record[14] = BYTE3(table->len); table_record[15] = BYTE4(table->len); table_record += 16; } /* the font header is complete; compute `head' checksum */ head_checksum += TA_table_compute_checksum(buf, len); head_checksum = 0xB1B0AFBAUL - head_checksum; /* store checksum in `head' table; */ head_buf[8] = BYTE1(head_checksum); head_buf[9] = BYTE2(head_checksum); head_buf[10] = BYTE3(head_checksum); head_buf[11] = BYTE4(head_checksum); *header_buf = buf; *header_len = len; return TA_Err_Ok; }