361 lines
8.7 KiB
C++
361 lines
8.7 KiB
C++
|
/*
|
||
|
* 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 <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
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
|