最近分析字体文件格式,是时候搭个稍微过得去的框架来整理一下代码。
主要处理几个需求:
1,跨平台。
2,只分析TrueType格式
3,解析几个表:cmap(编码,图元索引映射),glyf(仅取数据),os/2表。绘制图元指令有时候就再看看。
初步的设计:
1,用户管理几个主要的数据Memory, Face。
2,最底层是system,封装一些与平台相关的api;倒数第二层是stream,主要封装一些对数据流的操作,同级的是数据层,真正有意义的数据,存储关于字体相关的信息,以及数据流,都是由用户来管理。最上层是对各个表的解析。
3,主要提供数据的操作,不提供数据的管理,管理由使用者处理。
底层system初步代码如下:
TTSystem.h
#include "TrueTypeConfig.h" #include "TrueTypeData.h" #define TT_MEM_COPY(dest, src, length) / memcpy(dest, src, length) void TT_Close_Stream_Free(TT_Stream stream); void TT_Close_Stream_Munmap(TT_Stream stream); TT_RESULT TT_Open_Stream(TT_Stream stream, const char* filename); TT_RESULT TT_Close_Stream(TT_Stream stream);
TTSystem.c
#include <sys/types.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #include <sys/stat.h> #include <stdlib.h> #include <stdio.h> #include "TrueTypeSystem.h" TT_RESULT TT_Open_Stream(TT_Stream stream, const char* filename) { if (stream == NULL || filename == NULL) return TT_ERROR; int file = open(filename, O_RDONLY); if (file < 0) return TT_ERROR; struct stat stat_buff; if (fstat(file, &buff) < 0) { close(file); return TT_ERROR; } stream->size = buff.st_size; stream->pos = 0; stream->head = (unsigned char*)mmap(NULL, stream->size, PROT_READ, MAP_FILE | MAP_PRIVATE, file, 0); if ((long)stream->head > 0) { stream->close = TT_Close_Stream_Munmap; } else { stream->close = TT_Close_Stream_Free; stream->head = (unsigned char*)malloc(stream->size); if (stream->head == NULL) { close(file); return TT_ERROR; } ssize_t total_buff_size = 0; do { ssize_t curr_read_buff_size = 0; curr_read_buff_size = read(file, stream->head + total_buff_size, stream->size - total_buff_size); if (curr_read_buff_size <= 0) { close(file); stream->close(stream); return TT_ERROR; } total_buff_size += curr_read_buff_size; }while ((TT_LONG)total_buff_size != stream->size); } close(file); return TT_OK; } TT_RESULT TT_Close_Stream(TT_Stream stream) { if (stream == NULL || stream->close == NULL) return TT_ERROR; stream->close(stream); return TT_OK; } void TT_Close_Stream_Free(TT_Stream stream) { if (stream != NULL) free(stream->head); } void TT_Close_Stream_Munmap(TT_Stream stream) { if (stream != NULL) munmap((MUNMAP_ARG_CAST)stream->head, stream->size); }
数据流操作初步代码如下:
TTStream.h
//xuexuankr //2011.2.5 8:27PM //bytes stream operator #include "TrueTypeConfig.h" #include "TrueTypeData.h" //next bytes in buff #define BUFF_NEXT_SHORT(buff) / (buff += 2) #define BUFF_NEXT_USHORT(buff) / (buff += 2) #define BUFF_NEXT_LONG(buff) / (buff += 4) #define BUFF_NEXT_ULONG(buff) / (buff += 4) //get bytes from stream #define STREAM_GET_USHORT(value, a, b) / (value = ( (TT_USHORT)(a) << 8 ) | / (TT_USHORT)(b) ) #define STREAM_GET_SHORT(value, a, b) / (value = ( (TT_SHORT)(a) << 8) | / (TT_SHORT)(b) ) #define STREAM_GET_ULONG(value, a, b, c, d) / (value = ( (TT_ULONG)(a) << 24) | / ( (TT_ULONG)(b) << 16) | / ( (TT_ULONG)(c) << 8) | / (TT_ULONG)(d) ) #define STREAM_GET_LONG(value, a, b, c, d) / (value = ( (TT_LONG)(a) << 24) | / ( (TT_LONG)(b) << 16) | / ( (TT_LONG)(c) << 8) | / (TT_LONG)(d) ) //bytes operation TT_Result TT_Stream_Read(TT_Stream stream, TT_BYTE* buff, TT_LONG length); TT_Result TT_Stream_Seek(TT_Stream stream, TT_LONG pos);
TTStream.c
#include <math.h> #include "TrueTypeStream.h" TT_RESULT TT_Stream_Read(TT_Stream stream, TT_BYTE* buff, TT_LONG length) { if (stream == NULL || buff == NULL) return TT_ERROR; if (length > stream->size) return TT_ERROR; TT_ULONG buff_rest_len = stream->size - stream->pos; if (length > buff_rest_len) return TT_ERROR; TT_MEM_COPY(buff, stream->head + stream->pos, length); stream->pos += length; return TT_OK; } TT_RESULT TT_Stream_Seek(TT_Stream stream, TT_LONG pos) { if (stream == NULL) return TT_ERROR; if (stream->size < (stream->pos + pos) || (stream->pos + pos) < stream->head) return TT_ERROR; stream->pos += pos; return TT_OK; }
目前只有TT_Stream 的数据
TTData.h
#include "TrueTypeConfig.h" typedef void (*TT_Close_Stream)(TT_Stream stream); typedef struct { TT_BYTE* head; TT_LONG curr_pos; TT_LONG size; TT_Close_Stream close; }TT_StreamRec; typedef TT_StreamRec* TT_Stream;