blob: 1a11426ccbd337364d544b665294b061d135f9cf [file] [log] [blame]
/****************************************************************************
*
* gxvmod.c
*
* FreeType's TrueTypeGX/AAT validation module implementation (body).
*
* Copyright (C) 2004-2021 by
* suzuki toshiya, Masatake YAMATO, Red Hat K.K.,
* David Turner, Robert Wilhelm, and Werner Lemberg.
*
* This file is part of the FreeType project, and may only be used,
* modified, and distributed under the terms of the FreeType project
* license, LICENSE.TXT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*
*/
/****************************************************************************
*
* gxvalid is derived from both gxlayout module and otvalid module.
* Development of gxlayout is supported by the Information-technology
* Promotion Agency(IPA), Japan.
*
*/
#include <freetype/tttables.h>
#include <freetype/tttags.h>
#include <freetype/ftgxval.h>
#include <freetype/internal/ftobjs.h>
#include <freetype/internal/services/svgxval.h>
#include "gxvmod.h"
#include "gxvalid.h"
#include "gxvcommn.h"
/**************************************************************************
*
* The macro FT_COMPONENT is used in trace mode. It is an implicit
* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
* messages during execution.
*/
#undef FT_COMPONENT
#define FT_COMPONENT gxvmodule
static FT_Error
gxv_load_table( FT_Face face,
FT_Tag tag,
FT_Byte* volatile* table,
FT_ULong* table_len )
{
FT_Error error;
FT_Memory memory = FT_FACE_MEMORY( face );
error = FT_Load_Sfnt_Table( face, tag, 0, NULL, table_len );
if ( FT_ERR_EQ( error, Table_Missing ) )
return FT_Err_Ok;
if ( error )
goto Exit;
if ( FT_QALLOC( *table, *table_len ) )
goto Exit;
error = FT_Load_Sfnt_Table( face, tag, 0, *table, table_len );
Exit:
return error;
}
#define GXV_TABLE_DECL( _sfnt ) \
FT_Byte* volatile _sfnt = NULL; \
FT_ULong len_ ## _sfnt = 0
#define GXV_TABLE_LOAD( _sfnt ) \
FT_BEGIN_STMNT \
if ( ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) && \
( gx_flags & FT_VALIDATE_ ## _sfnt ) ) \
{ \
error = gxv_load_table( face, TTAG_ ## _sfnt, \
&_sfnt, &len_ ## _sfnt ); \
if ( error ) \
goto Exit; \
} \
FT_END_STMNT
#define GXV_TABLE_VALIDATE( _sfnt ) \
FT_BEGIN_STMNT \
if ( _sfnt ) \
{ \
ft_validator_init( &valid, _sfnt, _sfnt + len_ ## _sfnt, \
FT_VALIDATE_DEFAULT ); \
if ( ft_setjmp( valid.jump_buffer ) == 0 ) \
gxv_ ## _sfnt ## _validate( _sfnt, face, &valid ); \
error = valid.error; \
if ( error ) \
goto Exit; \
} \
FT_END_STMNT
#define GXV_TABLE_SET( _sfnt ) \
if ( FT_VALIDATE_ ## _sfnt ## _INDEX < table_count ) \
tables[FT_VALIDATE_ ## _sfnt ## _INDEX] = (FT_Bytes)_sfnt
static FT_Error
gxv_validate( FT_Face face,
FT_UInt gx_flags,
FT_Bytes tables[FT_VALIDATE_GX_LENGTH],
FT_UInt table_count )
{
FT_Memory volatile memory = FT_FACE_MEMORY( face );
FT_Error error = FT_Err_Ok;
FT_ValidatorRec volatile valid;
FT_UInt i;
GXV_TABLE_DECL( feat );
GXV_TABLE_DECL( bsln );
GXV_TABLE_DECL( trak );
GXV_TABLE_DECL( just );
GXV_TABLE_DECL( mort );
GXV_TABLE_DECL( morx );
GXV_TABLE_DECL( kern );
GXV_TABLE_DECL( opbd );
GXV_TABLE_DECL( prop );
GXV_TABLE_DECL( lcar );
for ( i = 0; i < table_count; i++ )
tables[i] = 0;
/* load tables */
GXV_TABLE_LOAD( feat );
GXV_TABLE_LOAD( bsln );
GXV_TABLE_LOAD( trak );
GXV_TABLE_LOAD( just );
GXV_TABLE_LOAD( mort );
GXV_TABLE_LOAD( morx );
GXV_TABLE_LOAD( kern );
GXV_TABLE_LOAD( opbd );
GXV_TABLE_LOAD( prop );
GXV_TABLE_LOAD( lcar );
/* validate tables */
GXV_TABLE_VALIDATE( feat );
GXV_TABLE_VALIDATE( bsln );
GXV_TABLE_VALIDATE( trak );
GXV_TABLE_VALIDATE( just );
GXV_TABLE_VALIDATE( mort );
GXV_TABLE_VALIDATE( morx );
GXV_TABLE_VALIDATE( kern );
GXV_TABLE_VALIDATE( opbd );
GXV_TABLE_VALIDATE( prop );
GXV_TABLE_VALIDATE( lcar );
/* Set results */
GXV_TABLE_SET( feat );
GXV_TABLE_SET( mort );
GXV_TABLE_SET( morx );
GXV_TABLE_SET( bsln );
GXV_TABLE_SET( just );
GXV_TABLE_SET( kern );
GXV_TABLE_SET( opbd );
GXV_TABLE_SET( trak );
GXV_TABLE_SET( prop );
GXV_TABLE_SET( lcar );
Exit:
if ( error )
{
FT_FREE( feat );
FT_FREE( bsln );
FT_FREE( trak );
FT_FREE( just );
FT_FREE( mort );
FT_FREE( morx );
FT_FREE( kern );
FT_FREE( opbd );
FT_FREE( prop );
FT_FREE( lcar );
}
return error;
}
static FT_Error
classic_kern_validate( FT_Face face,
FT_UInt ckern_flags,
FT_Bytes* ckern_table )
{
FT_Memory volatile memory = FT_FACE_MEMORY( face );
FT_Byte* volatile ckern = NULL;
FT_ULong len_ckern = 0;
/* without volatile on `error' GCC 4.1.1. emits: */
/* warning: variable 'error' might be clobbered by 'longjmp' or 'vfork' */
/* this warning seems spurious but --- */
FT_Error volatile error;
FT_ValidatorRec volatile valid;
*ckern_table = NULL;
error = gxv_load_table( face, TTAG_kern, &ckern, &len_ckern );
if ( error )
goto Exit;
if ( ckern )
{
ft_validator_init( &valid, ckern, ckern + len_ckern,
FT_VALIDATE_DEFAULT );
if ( ft_setjmp( valid.jump_buffer ) == 0 )
gxv_kern_validate_classic( ckern, face,
ckern_flags & FT_VALIDATE_CKERN, &valid );
error = valid.error;
if ( error )
goto Exit;
}
*ckern_table = ckern;
Exit:
if ( error )
FT_FREE( ckern );
return error;
}
static
const FT_Service_GXvalidateRec gxvalid_interface =
{
gxv_validate /* validate */
};
static
const FT_Service_CKERNvalidateRec ckernvalid_interface =
{
classic_kern_validate /* validate */
};
static
const FT_ServiceDescRec gxvalid_services[] =
{
{ FT_SERVICE_ID_GX_VALIDATE, &gxvalid_interface },
{ FT_SERVICE_ID_CLASSICKERN_VALIDATE, &ckernvalid_interface },
{ NULL, NULL }
};
static FT_Pointer
gxvalid_get_service( FT_Module module,
const char* service_id )
{
FT_UNUSED( module );
return ft_service_list_lookup( gxvalid_services, service_id );
}
FT_CALLBACK_TABLE_DEF
const FT_Module_Class gxv_module_class =
{
0,
sizeof ( FT_ModuleRec ),
"gxvalid",
0x10000L,
0x20000L,
NULL, /* module-specific interface */
(FT_Module_Constructor)NULL, /* module_init */
(FT_Module_Destructor) NULL, /* module_done */
(FT_Module_Requester) gxvalid_get_service /* get_interface */
};
/* END */