#include "ttobjs.h"
#include "ttdebug.h"
#include "ttfile.h"
#include "ttmemory.h"
#include "ttload.h"
#include "ttcmap.h"
#undef TT_COMPONENT
#define TT_COMPONENT trace_cmap
LOCAL_FUNC
TT_Error CharMap_Load( PCMapTable cmap,
TT_Stream input )
{
DEFINE_LOAD_LOCALS( input );
UShort num_SH, num_Seg, i;
UShort u, l;
PCMap0 cmap0;
PCMap2 cmap2;
PCMap4 cmap4;
PCMap6 cmap6;
PCMap2SubHeader cmap2sub;
PCMap4Segment segments;
if ( cmap->loaded )
return TT_Err_Ok;
if ( FILE_Seek( cmap->offset ) )
return error;
switch ( cmap->format )
{
case 0:
cmap0 = &cmap->c.cmap0;
if ( ALLOC( cmap0->glyphIdArray, 256L ) ||
FILE_Read( (void*)cmap0->glyphIdArray, 256L ) )
goto Fail;
break;
case 2:
num_SH = 0;
cmap2 = &cmap->c.cmap2;
if ( ALLOC_ARRAY( cmap2->subHeaderKeys, 256, UShort ) ||
ACCESS_Frame( 512L ) )
goto Fail;
for ( i = 0; i < 256; i++ )
{
u = GET_UShort() / 8;
cmap2->subHeaderKeys[i] = u;
if ( num_SH < u )
num_SH = u;
}
FORGET_Frame();
cmap2->numGlyphId = l =
( ( cmap->length - 2L * (256 + 3) - num_SH * 8L ) & 0xffff) / 2;
if ( ALLOC_ARRAY( cmap2->subHeaders,
num_SH + 1,
TCMap2SubHeader ) ||
ACCESS_Frame( ( num_SH + 1 ) * 8L ) )
goto Fail;
cmap2sub = cmap2->subHeaders;
for ( i = 0; i <= num_SH; i++ )
{
cmap2sub->firstCode = GET_UShort();
cmap2sub->entryCount = GET_UShort();
cmap2sub->idDelta = GET_Short();
cmap2sub->idRangeOffset = GET_UShort() - ( num_SH - i ) * 8 - 2;
cmap2sub++;
}
FORGET_Frame();
if ( ALLOC_ARRAY( cmap2->glyphIdArray, l, UShort ) ||
ACCESS_Frame( l * 2L ) )
goto Fail;
for ( i = 0; i < l; i++ )
cmap2->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
case 4:
cmap4 = &cmap->c.cmap4;
if ( ACCESS_Frame( 8L ) )
goto Fail;
cmap4->segCountX2 = GET_UShort();
cmap4->searchRange = GET_UShort();
cmap4->entrySelector = GET_UShort();
cmap4->rangeShift = GET_UShort();
num_Seg = cmap4->segCountX2 / 2;
FORGET_Frame();
if ( ALLOC_ARRAY( cmap4->segments,
num_Seg,
TCMap4Segment ) ||
ACCESS_Frame( (num_Seg * 4 + 1) * 2L ) )
goto Fail;
segments = cmap4->segments;
for ( i = 0; i < num_Seg; i++ )
segments[i].endCount = GET_UShort();
(void)GET_UShort();
for ( i = 0; i < num_Seg; i++ )
segments[i].startCount = GET_UShort();
for ( i = 0; i < num_Seg; i++ )
segments[i].idDelta = GET_Short();
for ( i = 0; i < num_Seg; i++ )
segments[i].idRangeOffset = GET_UShort();
FORGET_Frame();
cmap4->numGlyphId = l =
( ( cmap->length - ( 16L + 8L * num_Seg ) ) & 0xffff ) / 2;
if ( ALLOC_ARRAY( cmap4->glyphIdArray, l , UShort ) ||
ACCESS_Frame( l * 2L ) )
goto Fail;
for ( i = 0; i < l; i++ )
cmap4->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
case 6:
cmap6 = &cmap->c.cmap6;
if ( ACCESS_Frame( 4L ) )
goto Fail;
cmap6->firstCode = GET_UShort();
cmap6->entryCount = GET_UShort();
FORGET_Frame();
l = cmap6->entryCount;
if ( ALLOC_ARRAY( cmap6->glyphIdArray,
cmap6->entryCount,
Short ) ||
ACCESS_Frame( l * 2L ) )
goto Fail;
for ( i = 0; i < l; i++ )
cmap6->glyphIdArray[i] = GET_UShort();
FORGET_Frame();
break;
default:
return TT_Err_Invalid_CharMap_Format;
}
return TT_Err_Ok;
Fail:
CharMap_Free( cmap );
return error;
}
LOCAL_FUNC
TT_Error CharMap_Free( PCMapTable cmap )
{
if ( !cmap )
return TT_Err_Ok;
switch ( cmap->format )
{
case 0:
FREE( cmap->c.cmap0.glyphIdArray );
break;
case 2:
FREE( cmap->c.cmap2.subHeaderKeys );
FREE( cmap->c.cmap2.subHeaders );
FREE( cmap->c.cmap2.glyphIdArray );
break;
case 4:
FREE( cmap->c.cmap4.segments );
FREE( cmap->c.cmap4.glyphIdArray );
cmap->c.cmap4.segCountX2 = 0;
break;
case 6:
FREE( cmap->c.cmap6.glyphIdArray );
cmap->c.cmap6.entryCount = 0;
break;
default:
;
}
cmap->loaded = FALSE;
return TT_Err_Ok;
}
static UShort code_to_index0( UShort charCode, PCMap0 cmap0 );
static UShort code_to_index2( UShort charCode, PCMap2 cmap2 );
static UShort code_to_index4( UShort charCode, PCMap4 cmap4 );
static UShort code_to_index6( UShort charCode, PCMap6 cmap6 );
LOCAL_FUNC
UShort CharMap_Index( PCMapTable cmap,
UShort charcode )
{
switch ( cmap->format )
{
case 0:
return code_to_index0( charcode, &cmap->c.cmap0 );
case 2:
return code_to_index2( charcode, &cmap->c.cmap2 );
case 4:
return code_to_index4( charcode, &cmap->c.cmap4 );
case 6:
return code_to_index6( charcode, &cmap->c.cmap6 );
default:
return 0;
}
}
static UShort code_to_index0( UShort charCode,
PCMap0 cmap0 )
{
if ( charCode <= 0xFF )
return cmap0->glyphIdArray[charCode];
else
return 0;
}
static UShort code_to_index2( UShort charCode,
PCMap2 cmap2 )
{
UShort index1, idx, offset;
TCMap2SubHeader sh2;
index1 = cmap2->subHeaderKeys[charCode <= 0xFF ?
charCode : (charCode >> 8)];
if ( index1 == 0 )
{
if ( charCode <= 0xFF )
return cmap2->glyphIdArray[charCode];
else
return 0;
}
else
{
if ( charCode <= 0xFF )
return 0;
sh2 = cmap2->subHeaders[index1];
if ( (charCode & 0xFF) < sh2.firstCode )
return 0;
if ( (charCode & 0xFF) >= (sh2.firstCode + sh2.entryCount) )
return 0;
offset = sh2.idRangeOffset / 2 + (charCode & 0xFF) - sh2.firstCode;
if ( offset < cmap2->numGlyphId )
idx = cmap2->glyphIdArray[offset];
else
return 0;
if ( idx )
return (idx + sh2.idDelta) & 0xFFFF;
else
return 0;
}
}
static UShort code_to_index4( UShort charCode,
PCMap4 cmap4 )
{
UShort index1, segCount;
UShort i;
TCMap4Segment seg4;
segCount = cmap4->segCountX2 / 2;
for ( i = 0; i < segCount; i++ )
if ( charCode <= cmap4->segments[i].endCount )
break;
if ( i >= segCount )
return 0;
seg4 = cmap4->segments[i];
if ( charCode < seg4.startCount )
return 0;
if ( seg4.idRangeOffset == 0 )
return ( charCode + seg4.idDelta ) & 0xFFFF;
else
{
index1 = seg4.idRangeOffset / 2 + (charCode - seg4.startCount) -
(segCount - i);
if ( index1 < cmap4->numGlyphId )
{
if ( cmap4->glyphIdArray[index1] == 0 )
return 0;
else
return ( cmap4->glyphIdArray[index1] + seg4.idDelta ) & 0xFFFF;
}
else
return 0;
}
}
static UShort code_to_index6( UShort charCode,
PCMap6 cmap6 )
{
UShort firstCode;
firstCode = cmap6->firstCode;
if ( charCode < firstCode )
return 0;
if ( charCode >= (firstCode + cmap6->entryCount) )
return 0;
return cmap6->glyphIdArray[charCode - firstCode];
}