PageRenderTime 47ms CodeModel.GetById 2ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/fontextract/fontdata.c

http://ftk.googlecode.com/
C | 498 lines | 385 code | 84 blank | 29 comment | 81 complexity | bb2c1bffcff67b548f4356ac12379263 MD5 | raw file
  1/*
  2 * File: fontdata.c
  3 * Author:  Li XianJing <xianjimli@hotmail.com>
  4 * Brief:   functions to operate font data. 
  5 *
  6 * Copyright (c) 2009 - 2010  Li XianJing <xianjimli@hotmail.com>
  7 *
  8 * Licensed under the Academic Free License version 2.1
  9 *
 10 * This program is free software; you can redistribute it and/or modify
 11 * it under the terms of the GNU General Public License as published by
 12 * the Free Software Foundation; either version 2 of the License, or
 13 * (at your option) any later version.
 14 *
 15 * This program is distributed in the hope that it will be useful,
 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 18 * GNU General Public License for more details.
 19 *
 20 * You should have received a copy of the GNU General Public License
 21 * along with this program; if not, write to the Free Software
 22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 23 */
 24
 25/*
 26 * History:
 27 * ================================================================
 28 * 2009-09-11 Li XianJing <xianjimli@hotmail.com> created
 29 *
 30 */
 31#include "fontdata.h"
 32
 33#ifdef WITHOUT_FTK 
 34#define FTK_ALLOC malloc
 35#define FTK_FREE free
 36#define FTK_ZALLOC(s) calloc(1, s)
 37#define FTK_REALLOC realloc
 38#else
 39#include "ftk_allocator.h"
 40#endif
 41
 42#define FONT_VERSION 0x00000101 /*1.01*/
 43
 44typedef struct _FontDataHeader
 45{
 46	unsigned int   version;
 47	unsigned int   char_nr;
 48	unsigned char  width;
 49	unsigned char  height;
 50	unsigned short encoding;
 51	unsigned int   unused;
 52	char author[64];
 53	char family[32];
 54	char style[32];
 55}FontDataHeader;
 56
 57struct _FontData
 58{
 59	FontDataHeader header;
 60
 61	Glyph* glyphs;
 62	size_t data_size;
 63	size_t data_buffer_size;
 64	unsigned char* data;
 65
 66	void* org_data;
 67	int   new_created;
 68
 69	char file_name[260];
 70	void* current_glyph_data;
 71	size_t current_glyph_data_size;
 72};
 73
 74static Ret font_data_read_glyph(FontData* thiz, size_t offset, size_t size, Glyph* glyph);
 75
 76FontData* font_data_create(int char_nr, Encoding encoding)
 77{
 78	FontData* thiz = (FontData*)FTK_ZALLOC(sizeof(FontData));
 79
 80	if(thiz != NULL)
 81	{
 82		thiz->header.version  = FONT_VERSION;
 83		thiz->header.char_nr  = char_nr;
 84		thiz->header.encoding = encoding;
 85		
 86		if(char_nr > 0)
 87		{
 88			thiz->new_created = 1;
 89			thiz->glyphs = FTK_ZALLOC(char_nr * sizeof(Glyph));
 90		}
 91	}
 92
 93	return thiz;
 94}
 95
 96FontData* font_data_load(char* data, size_t length)
 97{
 98	FontData* thiz = font_data_create(0, 0);
 99
100	return_val_if_fail(data != NULL && length > sizeof(FontDataHeader), NULL);
101
102	if(thiz != NULL)
103	{
104		int glyph_size = 0;
105		thiz->header = *(FontDataHeader*)data;
106		glyph_size = thiz->header.char_nr * sizeof(Glyph);
107
108		thiz->glyphs = (Glyph*)(data + sizeof(FontDataHeader));
109		thiz->data = (unsigned char*)(data + sizeof(FontDataHeader) + glyph_size);
110		thiz->data_size = length - ((char*)thiz->data - data);
111		thiz->data_buffer_size = thiz->data_size;
112		thiz->new_created = 0;
113		thiz->org_data = data;
114	}
115
116	return thiz;
117}
118
119#ifdef WITHOUT_FTK
120#include <unistd.h>
121#include <sys/types.h>
122#include <sys/stat.h>
123char* read_file(const char* file_name, int* length)
124{
125	struct stat st = {0};
126	if(stat(file_name, &st))
127	{
128		return NULL;
129	}
130	else
131	{
132		char* buffer = malloc(st.st_size + 1);
133		FILE* fp = fopen(file_name, "rb");
134		fread(buffer, 1, st.st_size, fp);
135		fclose(fp);
136		buffer[st.st_size] = '\0';
137		*length = st.st_size;
138
139		return buffer;
140	}
141}
142
143FontData* font_data_load_file(const char* file_name)
144{
145	int length = 0;
146	char* buffer = read_file(file_name, &length);
147	
148	return font_data_load(buffer, length);
149}
150
151static Ret font_data_read_glyph(FontData* thiz, size_t offset, size_t size, Glyph* glyph)
152{
153
154	return RET_FAIL;
155}
156#else
157#include "ftk_file_system.h"
158
159FontData* font_data_load_file(const char* file_name)
160{
161	FontData* thiz = NULL;
162	return_val_if_fail(file_name != NULL, NULL);
163
164	if((thiz = font_data_create(0, 0)) != NULL)
165	{
166		FtkFsHandle fp = ftk_file_open(file_name, "rb");
167		if(fp != NULL)
168		{
169			int ret = 0;
170			size_t glyphs_size = 0;
171			ret = ftk_file_read(fp, &thiz->header, sizeof(thiz->header));
172			assert(ret == sizeof(thiz->header));
173			glyphs_size = thiz->header.char_nr * sizeof(Glyph);
174			thiz->glyphs = FTK_ZALLOC(glyphs_size);
175			assert(thiz->glyphs != NULL);
176			ftk_file_read(fp, thiz->glyphs, glyphs_size);
177			thiz->data = NULL;
178			thiz->data_size = 0;
179			thiz->new_created = 0;
180			thiz->org_data = NULL;
181			ftk_file_close(fp);
182			ftk_strncpy(thiz->file_name, file_name, sizeof(thiz->file_name)-1);
183		}
184		else
185		{
186			FTK_FREE(thiz);
187		}
188	}
189
190	return thiz;
191}
192
193static Ret font_data_read_glyph(FontData* thiz, size_t offset, size_t size, Glyph* glyph)
194{
195	int ret = 0;
196	FtkFsHandle fp = ftk_file_open(thiz->file_name, "rb");
197	size_t skip = sizeof(thiz->header) + thiz->header.char_nr * sizeof(Glyph) + offset;
198	return_val_if_fail(fp != NULL && glyph != NULL, RET_FAIL);
199
200	ret = ftk_file_seek(fp, skip);
201	assert(ret == 0);
202	
203	if(thiz->current_glyph_data_size < size)
204	{
205		FTK_FREE(thiz->current_glyph_data);
206		thiz->current_glyph_data = FTK_ALLOC(size * 2);
207		thiz->current_glyph_data_size = size * 2;
208	}
209
210	ret = ftk_file_read(fp, thiz->current_glyph_data, size);
211	ftk_logd("%s: offset=%d size=%d ret=%d\n", __func__, offset, size, ret);
212	ftk_file_close(fp);
213	assert(ret == size);
214	glyph->data = thiz->current_glyph_data;
215
216	return RET_OK;
217}
218#endif
219
220Ret font_data_add_glyph(FontData* thiz, Glyph* glyph)
221{
222	size_t i = 0;
223	return_val_if_fail(thiz != NULL && glyph != NULL && thiz->new_created, RET_FAIL);
224	
225	for(i = 0; i < thiz->header.char_nr; i++)
226	{
227		if(thiz->glyphs[i].code == glyph->code)
228		{
229			return RET_FOUND;
230		}
231
232		if(thiz->glyphs[i].code > glyph->code || thiz->glyphs[i].code == 0)
233		{
234			size_t size = glyph->w * glyph->h;
235			if(thiz->glyphs[i].code > glyph->code)
236			{
237				size_t k = 0;
238				for(k = thiz->header.char_nr - 1; k > i; k--)
239				{
240					thiz->glyphs[k] = thiz->glyphs[k-1];
241				}
242			}
243
244			if((thiz->data_size + size) >= thiz->data_buffer_size)
245			{
246				size_t data_buffer_size = thiz->data_buffer_size + (thiz->data_buffer_size >> 1) + (size << 4);
247				unsigned char* data = (unsigned char*)FTK_REALLOC(thiz->data, data_buffer_size);
248				if(data != NULL)
249				{
250					thiz->data = data;
251					thiz->data_buffer_size = data_buffer_size;
252				}
253			}
254
255			thiz->glyphs[i] = *glyph;
256			if((thiz->data_size + size) < thiz->data_buffer_size)
257			{
258				memcpy(thiz->data + thiz->data_size, glyph->data, size);
259				thiz->glyphs[i].data = (unsigned char*)thiz->data_size;
260				thiz->data_size += size;
261			}
262
263			return RET_OK;
264		}
265	}
266
267	return RET_FAIL;
268}
269
270Ret font_data_get_glyph(FontData* thiz, unsigned short code, Glyph* glyph)
271{
272    int low    = 0;
273    int mid    = 0;
274    int high   = 0;
275    int result = 0;
276
277    return_val_if_fail(thiz != NULL && glyph != NULL, RET_FAIL);
278
279    high = thiz->header.char_nr;
280    while(low <= high)
281    {
282        mid  = low + ((high - low) >> 1);
283        result = thiz->glyphs[mid].code - code;
284
285        if(result == 0)
286        {
287			*glyph = thiz->glyphs[mid];
288			if(thiz->data != NULL)
289			{
290				glyph->data = (unsigned char*)(thiz->data + (int)(thiz->glyphs[mid].data));
291			}
292			else
293			{
294				font_data_read_glyph(thiz, (size_t)glyph->data, glyph->w * glyph->h, glyph);
295			}
296
297            return RET_OK;
298        }
299        else if(result < 0)
300        {
301            low = mid + 1;
302        }
303        else
304        {
305            high = mid - 1;
306        }
307    }
308
309    return RET_FAIL;
310}
311
312int  font_data_get_version(FontData* thiz)
313{
314	return_val_if_fail(thiz != NULL, 0);
315
316	return thiz->header.version;
317}
318
319int  font_data_get_width(FontData* thiz)
320{
321	return_val_if_fail(thiz != NULL, 0);
322
323	return thiz->header.width;
324}
325
326int  font_data_get_height(FontData* thiz)
327{
328	return_val_if_fail(thiz != NULL, 0);
329
330	return thiz->header.height;
331}
332
333const char* font_data_get_author(FontData* thiz)
334{
335	return_val_if_fail(thiz != NULL, NULL);
336
337	return thiz->header.author;
338}
339
340const char* font_data_get_family(FontData* thiz)
341{
342	return_val_if_fail(thiz != NULL, NULL);
343
344	return thiz->header.family;
345}
346
347const char* font_data_get_style(FontData* thiz)
348{
349	return_val_if_fail(thiz != NULL, NULL);
350
351	return thiz->header.style;
352}
353
354void font_data_set_size(FontData* thiz, int width, int height)
355{
356	return_if_fail(thiz != NULL);
357
358	thiz->header.width  = width;
359	thiz->header.height = height;
360	
361	return;
362}
363
364void font_data_set_author(FontData* thiz, const char* author)
365{
366	return_if_fail(thiz != NULL);
367	
368	ftk_strncpy(thiz->header.author, author, sizeof(thiz->header.author));
369
370	return;
371}
372
373void font_data_set_family(FontData* thiz, const char* family)
374{
375	return_if_fail(thiz != NULL);
376	
377	ftk_strncpy(thiz->header.family, family, sizeof(thiz->header.family));
378
379	return;
380}
381
382void font_data_set_style(FontData* thiz, const char* style)
383{
384	return_if_fail(thiz != NULL);
385	
386	ftk_strncpy(thiz->header.style, style, sizeof(thiz->header.style));
387
388	return;
389}
390
391void font_data_destroy(FontData* thiz)
392{
393	return_if_fail(thiz != NULL);
394
395	if(thiz != NULL)
396	{
397		if(thiz->new_created)
398		{
399			FTK_FREE(thiz->glyphs);
400			FTK_FREE(thiz->data);
401			FTK_FREE(thiz->current_glyph_data);
402		}
403		FTK_FREE(thiz);
404	}
405
406	return;
407}
408
409#ifdef HAS_FONT_DATA_SAVE
410#include <stdio.h>
411Ret font_data_save(FontData* thiz, const char* file_name)
412{
413	FILE* fp = fopen(file_name, "wb+");
414	{
415		fwrite(&thiz->header, 1, sizeof(FontDataHeader), fp);
416		fwrite(thiz->glyphs, 1, sizeof(Glyph) * thiz->header.char_nr, fp);
417		fwrite(thiz->data, 1, thiz->data_size, fp);
418		fclose(fp);
419	}
420
421	return RET_OK;
422}
423#endif
424
425#ifdef FONT_DATA_TEST
426#include <sys/types.h>
427#include <sys/stat.h>
428#include <unistd.h>
429
430int main(int argc, char* argv[])
431{
432	int ch = 'a';
433	int length = 0;
434	char* buffer = NULL;
435	Glyph ret_glyph = {0};
436	FontData* data = font_data_create(36, 0);
437	Glyph* glyph = (Glyph*)FTK_ZALLOC(sizeof(Glyph));
438
439	glyph->w = 7;
440	glyph->h = 9;
441	glyph->x = 5;
442	glyph->y = 5;
443	glyph->data = FTK_ZALLOC(glyph->w * glyph->h);
444
445	for(; ch <= 'z'; ch++)
446	{
447		glyph->code = ch;
448		assert(font_data_add_glyph(data, glyph) == RET_OK);
449	}
450	
451	for(ch='0'; ch <= '9'; ch++)
452	{
453		glyph->code = ch;
454		assert(font_data_add_glyph(data, glyph) == RET_OK);
455	}
456
457	for(ch='a'; ch <= 'z'; ch++)
458	{
459		glyph->code = ch;
460		assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
461		assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
462		assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
463	}
464	
465	for(ch='0'; ch <= '9'; ch++)
466	{
467		glyph->code = ch;
468		assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
469		assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
470		assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
471	}
472
473	font_data_set_size(data, 16, 16);
474	assert(font_data_get_width(data) == 16);
475	assert(font_data_get_height(data) == 16);
476	font_data_set_author(data, "Li XianJing <xianjimli@hotmail.com>");
477	font_data_save(data, "test.fnt");
478	font_data_destroy(data);
479
480	buffer = read_file("test.fnt", &length);
481	data = font_data_load(buffer, length);
482	assert(data != NULL);
483	for(ch='a'; ch <= 'z'; ch++)
484	{
485		glyph->code = ch;
486		assert(font_data_get_glyph(data, ch, &ret_glyph) == RET_OK);
487		assert(memcmp(glyph, &ret_glyph, sizeof(ret_glyph)-sizeof(void*)) == 0);
488		assert(memcmp(glyph->data, ret_glyph.data, ret_glyph.w * ret_glyph.h) == 0);
489	}
490	assert(font_data_get_version(data) == FONT_VERSION);
491	assert(strcmp(font_data_get_author(data), "Li XianJing <xianjimli@hotmail.com>") == 0);
492	font_data_destroy(data);
493	FTK_FREE(glyph->data);
494	FTK_FREE(glyph);
495
496	return 0;
497}
498#endif/*FONT_DATA_TEST*/