/* * YOUR INFO HERE! */ // TOP typedef unsigned int Fixed16_16; struct Offset_Table{ Fixed16_16 version; unsigned short num_tables; unsigned short search_range; unsigned short entry_selector; unsigned short range_shift; }; struct Table_Directory_Entry{ unsigned long tag; unsigned long check_sum; unsigned long offset; unsigned long length; }; #include #include struct Data{ char *data; int size; }; Data open_file(const char *filename){ Data result = {}; FILE *file; file = fopen(filename, "rb"); if (file){ fseek(file, 0, SEEK_END); result.size = ftell(file); fseek(file, 0, SEEK_SET); if (result.size > 0){ result.data = (char*)malloc(result.size); fread(result.data, result.size, 1, file); } fclose(file); } return(result); } void print(Offset_Table *offset){ printf("version %d\n", offset->version >> 16); printf("number of tables %d\n", (int)(offset->num_tables)); printf("search range %d\n", (int)(offset->search_range)); printf("entry selector %d\n", (int)(offset->entry_selector)); printf("range shift %d\n", (int)(offset->range_shift)); } void print(Table_Directory_Entry *entry){ printf("tag %.4s\n", &entry->tag); printf("check sum %08x\n", entry->check_sum); printf("offset %d\n", entry->offset); printf("length %d\n", entry->length); } void byte_reverse(void *ptr, int len){ char *c; int i,j; char t; c = (char*)ptr; for (i = 0, j = len-1; i < j; ++i, --j){ t = c[i]; c[i] = c[j]; c[j] = t; } } void byte_fix(Offset_Table *offset){ byte_reverse(&offset->version, 4); byte_reverse(&offset->num_tables, 2); byte_reverse(&offset->search_range, 2); byte_reverse(&offset->entry_selector, 2); byte_reverse(&offset->range_shift, 2); } void byte_fix(Table_Directory_Entry *entry){ byte_reverse(&entry->check_sum, 4); byte_reverse(&entry->offset, 4); byte_reverse(&entry->length, 4); } struct cmap_Header{ unsigned short version; unsigned short num_subtables; }; struct cmap_Subtable_Entry{ unsigned short plat_id; unsigned short plat_encoding_id; unsigned long offset_from_cmap; }; void byte_fix(cmap_Header *header){ byte_reverse(&header->version, 2); byte_reverse(&header->num_subtables, 2); } void print(cmap_Header *header){ printf("cmap tables:\n"); printf("\tversion %d\n", (int)(header->version)); printf("\tsubtables %d\n", (int)(header->num_subtables)); } void byte_fix(cmap_Subtable_Entry *entry){ byte_reverse(&entry->plat_id, 2); byte_reverse(&entry->plat_encoding_id, 2); byte_reverse(&entry->offset_from_cmap, 4); } struct cmap_Subtable_Format4_Header{ unsigned short format; unsigned short length; unsigned short version; unsigned short segment_count_2; unsigned short search_range; unsigned short entry_selector; unsigned short range_shift; }; void print(cmap_Subtable_Entry *entry){ printf("\tplatform id %d\n", (int)(entry->plat_id)); printf("\tencoding id %d\n", (int)(entry->plat_encoding_id)); printf("\toffset from cmap %d\n", (int)(entry->offset_from_cmap)); } void byte_fix(cmap_Subtable_Format4_Header *header){ byte_reverse(&header->length, 2); byte_reverse(&header->version, 2); byte_reverse(&header->segment_count_2, 2); byte_reverse(&header->search_range, 2); byte_reverse(&header->entry_selector, 2); byte_reverse(&header->range_shift, 2); } void print(cmap_Subtable_Format4_Header *header){ printf("\t\tlength %d\n", header->length); printf("\t\tversion %d\n", header->version); printf("\t\tsegment count doubled %d\n", header->segment_count_2); printf("\t\tsearch range %d\n", header->search_range); printf("\t\tentry selector %d\n", header->entry_selector); printf("\t\trange shift %d\n", header->range_shift); } struct cmap_Subtable_Format4_Segments{ unsigned short *end_code, *start_code; unsigned short *id_delta, *id_range_offset; }; void byte_fix(cmap_Subtable_Format4_Segments segs, int segment_count){ for (int i = 0; i < segment_count; ++i){ byte_reverse(segs.end_code + i, 2); } for (int i = 0; i < segment_count; ++i){ byte_reverse(segs.start_code + i, 2); } for (int i = 0; i < segment_count; ++i){ byte_reverse(segs.id_delta + i, 2); } for (int i = 0; i < segment_count; ++i){ byte_reverse(segs.id_range_offset + i, 2); } } void print(cmap_Subtable_Format4_Segments segs, int i){ printf("\t\tsegment %d\n", i); printf("\t\tend code %d\n", (int)(segs.end_code[i])); printf("\t\tstart code %d\n", (int)(segs.start_code[i])); printf("\t\tid delta %d\n", (int)(segs.id_delta[i])); printf("\t\tid range offset %d\n", (int)(segs.id_range_offset[i])); } void parse_cmap_subtable4(char *start){ char *cursor = start; cmap_Subtable_Format4_Header *header = (cmap_Subtable_Format4_Header*)cursor; cursor = (char*)(header + 1); byte_fix(header); print(header); int segment_count = (header->segment_count_2 >> 1); cmap_Subtable_Format4_Segments segs; segs.end_code = (unsigned short*)cursor; cursor = (char*)(segs.end_code + segment_count); cursor = cursor + sizeof(unsigned short); segs.start_code = (unsigned short*)cursor; cursor = (char*)(segs.start_code + segment_count); segs.id_delta = (unsigned short*)cursor; cursor = (char*)(segs.id_delta + segment_count); segs.id_range_offset = (unsigned short*)cursor; cursor = (char*)(segs.id_range_offset + segment_count); byte_fix(segs, segment_count); for (int i = 0; i < segment_count; ++i){ printf("\n"); print(segs, i); } } void parse_cmap_subtable(char *start){ char *cursor = start; short *format = (short*)cursor; byte_reverse(format, 2); printf("\t\tformat %d\n", (int)(*format)); switch (*format){ case 4: parse_cmap_subtable4(start); break; } } void parse_cmap(char *start){ char *cursor = start; cmap_Header *header = (cmap_Header*)cursor; cursor = (char*)(header + 1); byte_fix(header); print(header); cmap_Subtable_Entry *entry = (cmap_Subtable_Entry*)cursor; for (int i = 0; i < header->num_subtables; ++i, ++entry){ byte_fix(entry); printf("\n"); print(entry); if (entry->plat_id == 3 && entry->plat_encoding_id == 1){ printf("\n\tMicrosoft Unicode table:\n"); parse_cmap_subtable(start + entry->offset_from_cmap); } } } struct glyf_Glyph_Header{ short num_contours; short x_min; short x_max; short y_min; short y_max; }; void byte_fix(glyf_Glyph_Header *header){ byte_reverse(&header->num_contours, 2); byte_reverse(&header->x_min, 2); byte_reverse(&header->x_max, 2); byte_reverse(&header->y_min, 2); byte_reverse(&header->y_max, 2); } void print(glyf_Glyph_Header *header){ printf("\tcontours %d\n", (int)(header->num_contours)); printf("\tx min %d\n", (int)(header->x_min)); printf("\tx max %d\n", (int)(header->x_max)); printf("\ty min %d\n", (int)(header->y_min)); printf("\ty max %d\n", (int)(header->y_max)); } void parse_glyf(char *start){ char *cursor = start; glyf_Glyph_Header *header = (glyf_Glyph_Header*)cursor; cursor = (char*)(header + 1); byte_fix(header); print(header); } #define TTF_Tag(a,b,c,d) ((a) + ((b) << 8) + ((c) << 16) + ((d) << 24)) #define TTF_Tag_cmap TTF_Tag('c', 'm', 'a', 'p') #define TTF_Tag_glyf TTF_Tag('g', 'l', 'y', 'f') #define TTF_Tag_fpgm TTF_Tag('f', 'p', 'g', 'm') #define TTF_Tag_prep TTF_Tag('p', 'r', 'e', 'p') #define TTF_Tag_cvt TTF_Tag('c', 'v', 't', ' ') #define TTF_Tag_maxp TTF_Tag('m', 'a', 'x', 'p') int main(){ Data file; char *filename; filename = "test.ttf"; file = open_file(filename); if (file.data == 0){ printf("could not open %s\n", filename); return (1); } char *cursor; Offset_Table *offset; cursor = file.data; offset = (Offset_Table*)cursor; cursor = (char*)(offset + 1); Table_Directory_Entry *directory_entries = (Table_Directory_Entry*)cursor; byte_fix(offset); print(offset); int table_number = offset->num_tables; Table_Directory_Entry *entry = directory_entries; for (int i = 0; i < table_number; ++i, ++entry){ printf("\n"); byte_fix(entry); print(entry); switch (entry->tag){ case TTF_Tag_cmap: parse_cmap(file.data + entry->offset); break; case TTF_Tag_glyf: parse_glyf(file.data + entry->offset); break; } } return (0); } // BOTTOM