1/****************************************************************************
2 *
3 * gxvtrak.c
4 *
5 * TrueTypeGX/AAT trak table validation (body).
6 *
7 * Copyright (C) 2004-2023 by
8 * suzuki toshiya, Masatake YAMATO, Red Hat K.K.,
9 * David Turner, Robert Wilhelm, and Werner Lemberg.
10 *
11 * This file is part of the FreeType project, and may only be used,
12 * modified, and distributed under the terms of the FreeType project
13 * license, LICENSE.TXT. By continuing to use, modify, or distribute
14 * this file you indicate that you have read the license and
15 * understand and accept it fully.
16 *
17 */
18
19/****************************************************************************
20 *
21 * gxvalid is derived from both gxlayout module and otvalid module.
22 * Development of gxlayout is supported by the Information-technology
23 * Promotion Agency(IPA), Japan.
24 *
25 */
26
27
28#include "gxvalid.h"
29#include "gxvcommn.h"
30
31
32 /**************************************************************************
33 *
34 * The macro FT_COMPONENT is used in trace mode. It is an implicit
35 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
36 * messages during execution.
37 */
38#undef FT_COMPONENT
39#define FT_COMPONENT gxvtrak
40
41
42 /*************************************************************************/
43 /*************************************************************************/
44 /***** *****/
45 /***** Data and Types *****/
46 /***** *****/
47 /*************************************************************************/
48 /*************************************************************************/
49
50 /*
51 * referred track table format specification:
52 * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6trak.html
53 * last update was 1996.
54 * ----------------------------------------------
55 * [MINIMUM HEADER]: GXV_TRAK_SIZE_MIN
56 * version (fixed: 32bit) = 0x00010000
57 * format (uint16: 16bit) = 0 is only defined (1996)
58 * horizOffset (uint16: 16bit)
59 * vertOffset (uint16: 16bit)
60 * reserved (uint16: 16bit) = 0
61 * ----------------------------------------------
62 * [VARIABLE BODY]:
63 * horizData
64 * header ( 2 + 2 + 4
65 * trackTable + nTracks * ( 4 + 2 + 2 )
66 * sizeTable + nSizes * 4 )
67 * ----------------------------------------------
68 * vertData
69 * header ( 2 + 2 + 4
70 * trackTable + nTracks * ( 4 + 2 + 2 )
71 * sizeTable + nSizes * 4 )
72 * ----------------------------------------------
73 */
74 typedef struct GXV_trak_DataRec_
75 {
76 FT_UShort trackValueOffset_min;
77 FT_UShort trackValueOffset_max;
78
79 } GXV_trak_DataRec, *GXV_trak_Data;
80
81
82#define GXV_TRAK_DATA( FIELD ) GXV_TABLE_DATA( trak, FIELD )
83
84
85 /*************************************************************************/
86 /*************************************************************************/
87 /***** *****/
88 /***** UTILITY FUNCTIONS *****/
89 /***** *****/
90 /*************************************************************************/
91 /*************************************************************************/
92
93 static void
94 gxv_trak_trackTable_validate( FT_Bytes table,
95 FT_Bytes limit,
96 FT_UShort nTracks,
97 GXV_Validator gxvalid )
98 {
99 FT_Bytes p = table;
100
101 FT_Fixed track, t;
102 FT_UShort nameIndex;
103 FT_UShort offset;
104 FT_UShort i, j;
105
106
107 GXV_NAME_ENTER( "trackTable" );
108
109 GXV_TRAK_DATA( trackValueOffset_min ) = 0xFFFFU;
110 GXV_TRAK_DATA( trackValueOffset_max ) = 0x0000;
111
112 GXV_LIMIT_CHECK( nTracks * ( 4 + 2 + 2 ) );
113
114 for ( i = 0; i < nTracks; i++ )
115 {
116 p = table + i * ( 4 + 2 + 2 );
117 track = FT_NEXT_LONG( p );
118 nameIndex = FT_NEXT_USHORT( p );
119 offset = FT_NEXT_USHORT( p );
120
121 if ( offset < GXV_TRAK_DATA( trackValueOffset_min ) )
122 GXV_TRAK_DATA( trackValueOffset_min ) = offset;
123 if ( offset > GXV_TRAK_DATA( trackValueOffset_max ) )
124 GXV_TRAK_DATA( trackValueOffset_max ) = offset;
125
126 gxv_sfntName_validate( nameIndex, 256, 32767, gxvalid );
127
128 for ( j = i; j < nTracks; j++ )
129 {
130 p = table + j * ( 4 + 2 + 2 );
131 t = FT_NEXT_LONG( p );
132 if ( t == track )
133 GXV_TRACE(( "duplicated entries found for track value 0x%lx\n",
134 track ));
135 }
136 }
137
138 gxvalid->subtable_length = (FT_ULong)( p - table );
139 GXV_EXIT;
140 }
141
142
143 static void
144 gxv_trak_trackData_validate( FT_Bytes table,
145 FT_Bytes limit,
146 GXV_Validator gxvalid )
147 {
148 FT_Bytes p = table;
149 FT_UShort nTracks;
150 FT_UShort nSizes;
151 FT_ULong sizeTableOffset;
152
153 GXV_ODTECT( 4, odtect );
154
155
156 GXV_ODTECT_INIT( odtect );
157 GXV_NAME_ENTER( "trackData" );
158
159 /* read the header of trackData */
160 GXV_LIMIT_CHECK( 2 + 2 + 4 );
161 nTracks = FT_NEXT_USHORT( p );
162 nSizes = FT_NEXT_USHORT( p );
163 sizeTableOffset = FT_NEXT_ULONG( p );
164
165 gxv_odtect_add_range( table, (FT_ULong)( p - table ),
166 "trackData header", odtect );
167
168 /* validate trackTable */
169 gxv_trak_trackTable_validate( p, limit, nTracks, gxvalid );
170 gxv_odtect_add_range( p, gxvalid->subtable_length,
171 "trackTable", odtect );
172
173 /* sizeTable is array of FT_Fixed, don't check contents */
174 p = gxvalid->root->base + sizeTableOffset;
175 GXV_LIMIT_CHECK( nSizes * 4 );
176 gxv_odtect_add_range( p, nSizes * 4, "sizeTable", odtect );
177
178 /* validate trackValueOffet */
179 p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_min );
180 if ( limit - p < nTracks * nSizes * 2 )
181 GXV_TRACE(( "too short trackValue array\n" ));
182
183 p = gxvalid->root->base + GXV_TRAK_DATA( trackValueOffset_max );
184 GXV_LIMIT_CHECK( nSizes * 2 );
185
186 gxv_odtect_add_range( gxvalid->root->base
187 + GXV_TRAK_DATA( trackValueOffset_min ),
188 GXV_TRAK_DATA( trackValueOffset_max )
189 - GXV_TRAK_DATA( trackValueOffset_min )
190 + nSizes * 2,
191 "trackValue array", odtect );
192
193 gxv_odtect_validate( odtect, gxvalid );
194
195 GXV_EXIT;
196 }
197
198
199 /*************************************************************************/
200 /*************************************************************************/
201 /***** *****/
202 /***** trak TABLE *****/
203 /***** *****/
204 /*************************************************************************/
205 /*************************************************************************/
206
207 FT_LOCAL_DEF( void )
208 gxv_trak_validate( FT_Bytes table,
209 FT_Face face,
210 FT_Validator ftvalid )
211 {
212 FT_Bytes p = table;
213 FT_Bytes limit = 0;
214
215 GXV_ValidatorRec gxvalidrec;
216 GXV_Validator gxvalid = &gxvalidrec;
217 GXV_trak_DataRec trakrec;
218 GXV_trak_Data trak = &trakrec;
219
220 FT_ULong version;
221 FT_UShort format;
222 FT_UShort horizOffset;
223 FT_UShort vertOffset;
224 FT_UShort reserved;
225
226
227 GXV_ODTECT( 3, odtect );
228
229 GXV_ODTECT_INIT( odtect );
230 gxvalid->root = ftvalid;
231 gxvalid->table_data = trak;
232 gxvalid->face = face;
233
234 limit = gxvalid->root->limit;
235
236 FT_TRACE3(( "validating `trak' table\n" ));
237 GXV_INIT;
238
239 GXV_LIMIT_CHECK( 4 + 2 + 2 + 2 + 2 );
240 version = FT_NEXT_ULONG( p );
241 format = FT_NEXT_USHORT( p );
242 horizOffset = FT_NEXT_USHORT( p );
243 vertOffset = FT_NEXT_USHORT( p );
244 reserved = FT_NEXT_USHORT( p );
245
246 GXV_TRACE(( " (version = 0x%08lx)\n", version ));
247 GXV_TRACE(( " (format = 0x%04x)\n", format ));
248 GXV_TRACE(( " (horizOffset = 0x%04x)\n", horizOffset ));
249 GXV_TRACE(( " (vertOffset = 0x%04x)\n", vertOffset ));
250 GXV_TRACE(( " (reserved = 0x%04x)\n", reserved ));
251
252 /* Version 1.0 (always:1996) */
253 if ( version != 0x00010000UL )
254 FT_INVALID_FORMAT;
255
256 /* format 0 (always:1996) */
257 if ( format != 0x0000 )
258 FT_INVALID_FORMAT;
259
260 GXV_32BIT_ALIGNMENT_VALIDATE( horizOffset );
261 GXV_32BIT_ALIGNMENT_VALIDATE( vertOffset );
262
263 /* Reserved Fixed Value (always) */
264 if ( reserved != 0x0000 )
265 FT_INVALID_DATA;
266
267 /* validate trackData */
268 if ( 0 < horizOffset )
269 {
270 gxv_trak_trackData_validate( table + horizOffset, limit, gxvalid );
271 gxv_odtect_add_range( table + horizOffset, gxvalid->subtable_length,
272 "horizJustData", odtect );
273 }
274
275 if ( 0 < vertOffset )
276 {
277 gxv_trak_trackData_validate( table + vertOffset, limit, gxvalid );
278 gxv_odtect_add_range( table + vertOffset, gxvalid->subtable_length,
279 "vertJustData", odtect );
280 }
281
282 gxv_odtect_validate( odtect, gxvalid );
283
284 FT_TRACE4(( "\n" ));
285 }
286
287
288/* END */
289