2016-08-30 12:07:41 +03:00
|
|
|
/*
|
|
|
|
Copyright (C) 2016 Alexander Borisov
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2.1 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
|
|
License along with this library; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
|
|
|
Author: lex.borisov@gmail.com (Alexander Borisov)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "myfont/cmap.h"
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
myfont_status_t myfont_table_cmap_format_0(myfont_font_t *mf, myfont_tcmap_entry_t *entry, size_t offset)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
2016-09-07 15:29:32 +03:00
|
|
|
if(mf->file_size < (offset + 260)) {
|
|
|
|
entry->header = NULL;
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
myfont_tcmap_format_0_t *f0 = (myfont_tcmap_format_0_t*)myfont_calloc(mf, 1, sizeof(myfont_tcmap_format_0_t));
|
|
|
|
|
|
|
|
if(f0 == NULL) {
|
|
|
|
entry->header = NULL;
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
uint8_t *data = &mf->file_data[offset];
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
f0->length = myfont_read_u16(&data);
|
|
|
|
f0->language = myfont_read_u16(&data);
|
|
|
|
|
|
|
|
memcpy(f0->glyphIdArray, data, 256);
|
2016-08-30 12:07:41 +03:00
|
|
|
|
|
|
|
entry->header = (void *)f0;
|
2016-09-09 15:14:09 +03:00
|
|
|
|
|
|
|
return MyFONT_STATUS_OK;
|
2016-08-30 12:07:41 +03:00
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
myfont_status_t myfont_table_cmap_format_4(myfont_font_t *mf, myfont_tcmap_entry_t *entry, size_t offset)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
2016-09-07 15:29:32 +03:00
|
|
|
uint8_t *data = &mf->file_data[offset];
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
myfont_tcmap_format_4_t *f4 = (myfont_tcmap_format_4_t*)myfont_calloc(mf, 1, sizeof(myfont_tcmap_format_4_t));
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if(f4 == NULL)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
offset += MyFONT_TCMAP_FORMAT_4_FIRST_LENGTH;
|
2016-09-09 15:14:09 +03:00
|
|
|
|
|
|
|
if(mf->file_size < offset) {
|
|
|
|
myfont_free(mf, f4);
|
|
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
|
|
|
}
|
2016-09-07 15:29:32 +03:00
|
|
|
|
|
|
|
f4->length = myfont_read_u16(&data);
|
|
|
|
f4->language = myfont_read_u16(&data);
|
|
|
|
f4->segCountX2 = myfont_read_u16(&data);
|
|
|
|
f4->searchRange = myfont_read_u16(&data);
|
|
|
|
f4->entrySelector = myfont_read_u16(&data);
|
|
|
|
f4->rangeShift = myfont_read_u16(&data);
|
|
|
|
|
|
|
|
f4->segCount = f4->segCountX2 / 2;
|
|
|
|
f4->numGlyphId = ((f4->length - (16L + 8L * f4->segCount)) & 0xffff) / 2;
|
|
|
|
|
|
|
|
offset += sizeof(uint16_t) * (f4->segCount * 5);
|
|
|
|
if(mf->file_size < offset)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
2016-09-07 15:29:32 +03:00
|
|
|
|
|
|
|
/* init mem */
|
|
|
|
if((f4->endCount = (uint16_t *)myfont_calloc(mf, f4->segCount, sizeof(uint16_t))) == NULL)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if((f4->startCount = (uint16_t *)myfont_calloc(mf, f4->segCount, sizeof(uint16_t))) == NULL) {
|
|
|
|
myfont_free(mf, f4->endCount); f4->endCount = NULL;
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if((f4->idDelta = (int16_t *)myfont_calloc(mf, f4->segCount, sizeof(int16_t))) == NULL) {
|
|
|
|
myfont_free(mf, f4->endCount); f4->endCount = NULL;
|
|
|
|
myfont_free(mf, f4->startCount); f4->startCount = NULL;
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if((f4->idRangeOffset = (uint16_t *)myfont_calloc(mf, f4->segCount, sizeof(uint16_t))) == NULL) {
|
|
|
|
myfont_free(mf, f4->endCount); f4->endCount = NULL;
|
|
|
|
myfont_free(mf, f4->startCount); f4->startCount = NULL;
|
|
|
|
myfont_free(mf, f4->idDelta); f4->idDelta = NULL;
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if((f4->glyphIdArray = (uint16_t *)myfont_calloc(mf, f4->numGlyphId, sizeof(uint16_t))) == NULL) {
|
|
|
|
myfont_free(mf, f4->endCount); f4->endCount = NULL;
|
|
|
|
myfont_free(mf, f4->startCount); f4->startCount = NULL;
|
|
|
|
myfont_free(mf, f4->idDelta); f4->idDelta = NULL;
|
|
|
|
myfont_free(mf, f4->idRangeOffset); f4->idRangeOffset = NULL;
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/* read data */
|
|
|
|
for(uint16_t i = 0; i < f4->segCount; i++) {
|
|
|
|
f4->endCount[i] = myfont_read_u16(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
f4->reservedPad = myfont_read_u16(&data);
|
|
|
|
|
|
|
|
for(uint16_t i = 0; i < f4->segCount; i++) {
|
|
|
|
f4->startCount[i] = myfont_read_u16(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint16_t i = 0; i < f4->segCount; i++) {
|
|
|
|
f4->idDelta[i] = myfont_read_16(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint16_t i = 0; i < f4->segCount; i++) {
|
|
|
|
f4->idRangeOffset[i] = myfont_read_u16(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint16_t i = 0; i < f4->numGlyphId; i++) {
|
|
|
|
f4->glyphIdArray[i] = myfont_read_u16(&data);
|
|
|
|
}
|
2016-08-30 12:07:41 +03:00
|
|
|
|
|
|
|
entry->header = (void *)f4;
|
2016-09-09 15:14:09 +03:00
|
|
|
|
|
|
|
return MyFONT_STATUS_OK;
|
2016-08-30 12:07:41 +03:00
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
uint16_t myfont_glyph_index_by_code_format_0(myfont_tcmap_format_0_t *f0, unsigned long codepoint, myfont_status_t* status)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
2016-09-09 15:14:09 +03:00
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_OK;
|
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if(codepoint < 256)
|
|
|
|
return (uint16_t)f0->glyphIdArray[codepoint];
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_ERROR_GLYPH_NOT_FOUND;
|
|
|
|
|
2016-08-30 12:07:41 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
uint16_t myfont_glyph_index_by_code_format_4(myfont_tcmap_format_4_t *f4, unsigned long codepoint, myfont_status_t* status)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
|
|
|
uint16_t i;
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_OK;
|
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
for(i = 0; i < f4->segCount; i++)
|
|
|
|
if(codepoint <= f4->endCount[i])
|
2016-08-30 12:07:41 +03:00
|
|
|
break;
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(i >= f4->segCount || codepoint < f4->startCount[i]) {
|
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_ERROR_GLYPH_NOT_FOUND;
|
|
|
|
|
2016-08-30 12:07:41 +03:00
|
|
|
return 0;
|
2016-09-09 15:14:09 +03:00
|
|
|
}
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if(f4->idRangeOffset[i] == 0) {
|
|
|
|
return (codepoint + (uint16_t)f4->idDelta[i]) & 0xFFFF;
|
2016-08-30 12:07:41 +03:00
|
|
|
}
|
2016-09-07 15:29:32 +03:00
|
|
|
else {
|
|
|
|
uint16_t index = (f4->idRangeOffset[i] / 2) + (codepoint - f4->startCount[i]) - (f4->segCount - i);
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if(index < f4->numGlyphId) {
|
2016-08-30 12:07:41 +03:00
|
|
|
if(f4->glyphIdArray[index] != 0)
|
2016-09-07 15:29:32 +03:00
|
|
|
return (f4->glyphIdArray[index] + (uint16_t)f4->idDelta[i]) & 0xFFFF;
|
2016-08-30 12:07:41 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_ERROR_GLYPH_NOT_FOUND;
|
|
|
|
|
2016-08-30 12:07:41 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
uint16_t myfont_glyph_index_by_codepoint(myfont_font_t *mf, unsigned long codepoint, myfont_status_t* status)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
2016-09-07 15:29:32 +03:00
|
|
|
uint16_t i, index = 0, tcout = mf->table_cmap.header.numTables;
|
2016-09-09 15:14:09 +03:00
|
|
|
myfont_status_t mf_status;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
|
|
|
for(i = 0; i < tcout; i++)
|
|
|
|
{
|
|
|
|
myfont_tcmap_entry_t *entry = &mf->table_cmap.entries[i];
|
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
switch (entry->format) {
|
2016-08-30 12:07:41 +03:00
|
|
|
case 0:
|
2016-09-09 15:14:09 +03:00
|
|
|
index = myfont_glyph_index_by_code_format_0((myfont_tcmap_format_0_t *)(entry->header), codepoint, &mf_status);
|
2016-08-30 12:07:41 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
2016-09-09 15:14:09 +03:00
|
|
|
index = myfont_glyph_index_by_code_format_4((myfont_tcmap_format_4_t *)(entry->header), codepoint, &mf_status);
|
2016-08-30 12:07:41 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2016-09-09 15:14:09 +03:00
|
|
|
mf_status = MyFONT_STATUS_ERROR_GLYPH_NOT_FOUND;
|
2016-08-30 12:07:41 +03:00
|
|
|
break;
|
|
|
|
};
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(mf_status == MyFONT_STATUS_OK) {
|
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_OK;
|
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
2016-08-30 12:07:41 +03:00
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(status)
|
|
|
|
*status = MyFONT_STATUS_ERROR_GLYPH_NOT_FOUND;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
myfont_status_t myfont_load_table_cmap(myfont_font_t *mf)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
|
|
|
myfont_table_cmap_t *tcmap = &mf->table_cmap;
|
2016-09-07 15:29:32 +03:00
|
|
|
const uint32_t table_offset = mf->cache.tables_offset[MyFONT_TKEY_cmap];
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
if(table_offset == 0)
|
|
|
|
return MyFONT_STATUS_OK;
|
|
|
|
|
2016-12-14 22:09:21 +03:00
|
|
|
if((table_offset + 4) > mf->file_size)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
2016-09-07 15:29:32 +03:00
|
|
|
|
|
|
|
/* get current data */
|
|
|
|
uint8_t *data = &mf->file_data[table_offset];
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
/* get header */
|
|
|
|
tcmap->header.version = myfont_read_u16(&data);
|
|
|
|
tcmap->header.numTables = myfont_read_u16(&data);
|
|
|
|
|
|
|
|
if(tcmap->header.numTables == 0)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_OK;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
size_t size_records = sizeof(myfont_tcmap_record_t) * tcmap->header.numTables;
|
|
|
|
size_t size_entries = sizeof(myfont_tcmap_entry_t) * tcmap->header.numTables;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if(mf->file_size < (size_records + size_entries))
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if((tcmap->records = (myfont_tcmap_record_t *)myfont_malloc(mf, size_records)) == NULL)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
|
|
|
|
if((tcmap->entries = (myfont_tcmap_entry_t *)myfont_malloc(mf, size_entries)) == NULL) {
|
|
|
|
tcmap->records = NULL;
|
|
|
|
myfont_free(mf, tcmap->records);
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_MEMORY_ALLOCATION;
|
2016-09-07 15:29:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
for(uint16_t i = 0; i < tcmap->header.numTables; i++) {
|
|
|
|
tcmap->records[i].platformID = myfont_read_u16(&data);
|
|
|
|
tcmap->records[i].encodingID = myfont_read_u16(&data);
|
|
|
|
tcmap->records[i].offset = myfont_read_u32(&data);
|
|
|
|
}
|
|
|
|
|
|
|
|
for(uint16_t i = 0; i < tcmap->header.numTables; i++)
|
2016-08-30 12:07:41 +03:00
|
|
|
{
|
2016-09-07 15:29:32 +03:00
|
|
|
uint32_t offset = tcmap->records[i].offset + table_offset;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
if(mf->file_size <= offset)
|
2016-09-09 15:14:09 +03:00
|
|
|
return MyFONT_STATUS_ERROR_TABLE_UNEXPECTED_ENDING;
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
data = &mf->file_data[offset];
|
|
|
|
tcmap->entries[i].format = myfont_read_u16(&data);
|
2016-08-30 12:07:41 +03:00
|
|
|
|
2016-09-07 15:29:32 +03:00
|
|
|
switch (tcmap->entries[i].format) {
|
2016-08-30 12:07:41 +03:00
|
|
|
case 0:
|
2016-09-07 15:29:32 +03:00
|
|
|
myfont_table_cmap_format_0(mf, &tcmap->entries[i], (offset + 2));
|
2016-08-30 12:07:41 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 4:
|
2016-09-07 15:29:32 +03:00
|
|
|
myfont_table_cmap_format_4(mf, &tcmap->entries[i], (offset + 2));
|
2016-08-30 12:07:41 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-09-09 15:14:09 +03:00
|
|
|
|
|
|
|
return MyFONT_STATUS_OK;
|
2016-08-30 12:07:41 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-09 15:14:09 +03:00
|
|
|
|