Go to most recent revision | Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /***************************************************************************/ |
2 | /* */ |
||
3 | /* otvgpos.c */ |
||
4 | /* */ |
||
5 | /* OpenType GPOS table validation (body). */ |
||
6 | /* */ |
||
7 | /* Copyright 2002, 2004, 2005, 2006, 2007, 2008 by */ |
||
8 | /* David Turner, Robert Wilhelm, and Werner Lemberg. */ |
||
9 | /* */ |
||
10 | /* This file is part of the FreeType project, and may only be used, */ |
||
11 | /* modified, and distributed under the terms of the FreeType project */ |
||
12 | /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ |
||
13 | /* this file you indicate that you have read the license and */ |
||
14 | /* understand and accept it fully. */ |
||
15 | /* */ |
||
16 | /***************************************************************************/ |
||
17 | |||
18 | |||
19 | #include "otvalid.h" |
||
20 | #include "otvcommn.h" |
||
21 | #include "otvgpos.h" |
||
22 | |||
23 | |||
24 | /*************************************************************************/ |
||
25 | /* */ |
||
26 | /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ |
||
27 | /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ |
||
28 | /* messages during execution. */ |
||
29 | /* */ |
||
30 | #undef FT_COMPONENT |
||
31 | #define FT_COMPONENT trace_otvgpos |
||
32 | |||
33 | |||
34 | static void |
||
35 | otv_Anchor_validate( FT_Bytes table, |
||
36 | OTV_Validator valid ); |
||
37 | |||
38 | static void |
||
39 | otv_MarkArray_validate( FT_Bytes table, |
||
40 | OTV_Validator valid ); |
||
41 | |||
42 | |||
43 | /*************************************************************************/ |
||
44 | /*************************************************************************/ |
||
45 | /***** *****/ |
||
46 | /***** UTILITY FUNCTIONS *****/ |
||
47 | /***** *****/ |
||
48 | /*************************************************************************/ |
||
49 | /*************************************************************************/ |
||
50 | |||
51 | #define BaseArrayFunc otv_x_sxy |
||
52 | #define LigatureAttachFunc otv_x_sxy |
||
53 | #define Mark2ArrayFunc otv_x_sxy |
||
54 | |||
55 | /* uses valid->extra1 (counter) */ |
||
56 | /* uses valid->extra2 (boolean to handle NULL anchor field) */ |
||
57 | |||
58 | static void |
||
59 | otv_x_sxy( FT_Bytes table, |
||
60 | OTV_Validator valid ) |
||
61 | { |
||
62 | FT_Bytes p = table; |
||
63 | FT_UInt Count, count1, table_size; |
||
64 | |||
65 | |||
66 | OTV_ENTER; |
||
67 | |||
68 | OTV_LIMIT_CHECK( 2 ); |
||
69 | |||
70 | Count = FT_NEXT_USHORT( p ); |
||
71 | |||
72 | OTV_TRACE(( " (Count = %d)\n", Count )); |
||
73 | |||
74 | OTV_LIMIT_CHECK( Count * valid->extra1 * 2 ); |
||
75 | |||
76 | table_size = Count * valid->extra1 * 2 + 2; |
||
77 | |||
78 | for ( ; Count > 0; Count-- ) |
||
79 | for ( count1 = valid->extra1; count1 > 0; count1-- ) |
||
80 | { |
||
81 | OTV_OPTIONAL_TABLE( anchor_offset ); |
||
82 | |||
83 | |||
84 | OTV_OPTIONAL_OFFSET( anchor_offset ); |
||
85 | |||
86 | if ( valid->extra2 ) |
||
87 | { |
||
88 | OTV_SIZE_CHECK( anchor_offset ); |
||
89 | if ( anchor_offset ) |
||
90 | otv_Anchor_validate( table + anchor_offset, valid ); |
||
91 | } |
||
92 | else |
||
93 | otv_Anchor_validate( table + anchor_offset, valid ); |
||
94 | } |
||
95 | |||
96 | OTV_EXIT; |
||
97 | } |
||
98 | |||
99 | |||
100 | #define MarkBasePosFormat1Func otv_u_O_O_u_O_O |
||
101 | #define MarkLigPosFormat1Func otv_u_O_O_u_O_O |
||
102 | #define MarkMarkPosFormat1Func otv_u_O_O_u_O_O |
||
103 | |||
104 | /* sets valid->extra1 (class count) */ |
||
105 | |||
106 | static void |
||
107 | otv_u_O_O_u_O_O( FT_Bytes table, |
||
108 | OTV_Validator valid ) |
||
109 | { |
||
110 | FT_Bytes p = table; |
||
111 | FT_UInt Coverage1, Coverage2, ClassCount; |
||
112 | FT_UInt Array1, Array2; |
||
113 | OTV_Validate_Func func; |
||
114 | |||
115 | |||
116 | OTV_ENTER; |
||
117 | |||
118 | p += 2; /* skip PosFormat */ |
||
119 | |||
120 | OTV_LIMIT_CHECK( 10 ); |
||
121 | Coverage1 = FT_NEXT_USHORT( p ); |
||
122 | Coverage2 = FT_NEXT_USHORT( p ); |
||
123 | ClassCount = FT_NEXT_USHORT( p ); |
||
124 | Array1 = FT_NEXT_USHORT( p ); |
||
125 | Array2 = FT_NEXT_USHORT( p ); |
||
126 | |||
127 | otv_Coverage_validate( table + Coverage1, valid, -1 ); |
||
128 | otv_Coverage_validate( table + Coverage2, valid, -1 ); |
||
129 | |||
130 | otv_MarkArray_validate( table + Array1, valid ); |
||
131 | |||
132 | valid->nesting_level++; |
||
133 | func = valid->func[valid->nesting_level]; |
||
134 | valid->extra1 = ClassCount; |
||
135 | |||
136 | func( table + Array2, valid ); |
||
137 | |||
138 | valid->nesting_level--; |
||
139 | |||
140 | OTV_EXIT; |
||
141 | } |
||
142 | |||
143 | |||
144 | /*************************************************************************/ |
||
145 | /*************************************************************************/ |
||
146 | /***** *****/ |
||
147 | /***** VALUE RECORDS *****/ |
||
148 | /***** *****/ |
||
149 | /*************************************************************************/ |
||
150 | /*************************************************************************/ |
||
151 | |||
152 | static FT_UInt |
||
153 | otv_value_length( FT_UInt format ) |
||
154 | { |
||
155 | FT_UInt count; |
||
156 | |||
157 | |||
158 | count = ( ( format & 0xAA ) >> 1 ) + ( format & 0x55 ); |
||
159 | count = ( ( count & 0xCC ) >> 2 ) + ( count & 0x33 ); |
||
160 | count = ( ( count & 0xF0 ) >> 4 ) + ( count & 0x0F ); |
||
161 | |||
162 | return count * 2; |
||
163 | } |
||
164 | |||
165 | |||
166 | /* uses valid->extra3 (pointer to base table) */ |
||
167 | |||
168 | static void |
||
169 | otv_ValueRecord_validate( FT_Bytes table, |
||
170 | FT_UInt format, |
||
171 | OTV_Validator valid ) |
||
172 | { |
||
173 | FT_Bytes p = table; |
||
174 | FT_UInt count; |
||
175 | |||
176 | #ifdef FT_DEBUG_LEVEL_TRACE |
||
177 | FT_Int loop; |
||
178 | FT_ULong res = 0; |
||
179 | |||
180 | |||
181 | OTV_NAME_ENTER( "ValueRecord" ); |
||
182 | |||
183 | /* display `format' in dual representation */ |
||
184 | for ( loop = 7; loop >= 0; loop-- ) |
||
185 | { |
||
186 | res <<= 4; |
||
187 | res += ( format >> loop ) & 1; |
||
188 | } |
||
189 | |||
190 | OTV_TRACE(( " (format 0b%08lx)\n", res )); |
||
191 | #endif |
||
192 | |||
193 | if ( format >= 0x100 ) |
||
194 | FT_INVALID_FORMAT; |
||
195 | |||
196 | for ( count = 4; count > 0; count-- ) |
||
197 | { |
||
198 | if ( format & 1 ) |
||
199 | { |
||
200 | /* XPlacement, YPlacement, XAdvance, YAdvance */ |
||
201 | OTV_LIMIT_CHECK( 2 ); |
||
202 | p += 2; |
||
203 | } |
||
204 | |||
205 | format >>= 1; |
||
206 | } |
||
207 | |||
208 | for ( count = 4; count > 0; count-- ) |
||
209 | { |
||
210 | if ( format & 1 ) |
||
211 | { |
||
212 | FT_PtrDist table_size; |
||
213 | |||
214 | OTV_OPTIONAL_TABLE( device ); |
||
215 | |||
216 | |||
217 | /* XPlaDevice, YPlaDevice, XAdvDevice, YAdvDevice */ |
||
218 | OTV_LIMIT_CHECK( 2 ); |
||
219 | OTV_OPTIONAL_OFFSET( device ); |
||
220 | |||
221 | /* XXX: this value is usually too small, especially if the current */ |
||
222 | /* ValueRecord is part of an array -- getting the correct table */ |
||
223 | /* size is probably not worth the trouble */ |
||
224 | |||
225 | table_size = p - valid->extra3; |
||
226 | |||
227 | OTV_SIZE_CHECK( device ); |
||
228 | if ( device ) |
||
229 | otv_Device_validate( valid->extra3 + device, valid ); |
||
230 | } |
||
231 | format >>= 1; |
||
232 | } |
||
233 | |||
234 | OTV_EXIT; |
||
235 | } |
||
236 | |||
237 | |||
238 | /*************************************************************************/ |
||
239 | /*************************************************************************/ |
||
240 | /***** *****/ |
||
241 | /***** ANCHORS *****/ |
||
242 | /***** *****/ |
||
243 | /*************************************************************************/ |
||
244 | /*************************************************************************/ |
||
245 | |||
246 | static void |
||
247 | otv_Anchor_validate( FT_Bytes table, |
||
248 | OTV_Validator valid ) |
||
249 | { |
||
250 | FT_Bytes p = table; |
||
251 | FT_UInt AnchorFormat; |
||
252 | |||
253 | |||
254 | OTV_NAME_ENTER( "Anchor"); |
||
255 | |||
256 | OTV_LIMIT_CHECK( 6 ); |
||
257 | AnchorFormat = FT_NEXT_USHORT( p ); |
||
258 | |||
259 | OTV_TRACE(( " (format %d)\n", AnchorFormat )); |
||
260 | |||
261 | p += 4; /* skip XCoordinate and YCoordinate */ |
||
262 | |||
263 | switch ( AnchorFormat ) |
||
264 | { |
||
265 | case 1: |
||
266 | break; |
||
267 | |||
268 | case 2: |
||
269 | OTV_LIMIT_CHECK( 2 ); /* AnchorPoint */ |
||
270 | break; |
||
271 | |||
272 | case 3: |
||
273 | { |
||
274 | FT_UInt table_size; |
||
275 | |||
276 | OTV_OPTIONAL_TABLE( XDeviceTable ); |
||
277 | OTV_OPTIONAL_TABLE( YDeviceTable ); |
||
278 | |||
279 | |||
280 | OTV_LIMIT_CHECK( 4 ); |
||
281 | OTV_OPTIONAL_OFFSET( XDeviceTable ); |
||
282 | OTV_OPTIONAL_OFFSET( YDeviceTable ); |
||
283 | |||
284 | table_size = 6 + 4; |
||
285 | |||
286 | OTV_SIZE_CHECK( XDeviceTable ); |
||
287 | if ( XDeviceTable ) |
||
288 | otv_Device_validate( table + XDeviceTable, valid ); |
||
289 | |||
290 | OTV_SIZE_CHECK( YDeviceTable ); |
||
291 | if ( YDeviceTable ) |
||
292 | otv_Device_validate( table + YDeviceTable, valid ); |
||
293 | } |
||
294 | break; |
||
295 | |||
296 | default: |
||
297 | FT_INVALID_FORMAT; |
||
298 | } |
||
299 | |||
300 | OTV_EXIT; |
||
301 | } |
||
302 | |||
303 | |||
304 | /*************************************************************************/ |
||
305 | /*************************************************************************/ |
||
306 | /***** *****/ |
||
307 | /***** MARK ARRAYS *****/ |
||
308 | /***** *****/ |
||
309 | /*************************************************************************/ |
||
310 | /*************************************************************************/ |
||
311 | |||
312 | static void |
||
313 | otv_MarkArray_validate( FT_Bytes table, |
||
314 | OTV_Validator valid ) |
||
315 | { |
||
316 | FT_Bytes p = table; |
||
317 | FT_UInt MarkCount; |
||
318 | |||
319 | |||
320 | OTV_NAME_ENTER( "MarkArray" ); |
||
321 | |||
322 | OTV_LIMIT_CHECK( 2 ); |
||
323 | MarkCount = FT_NEXT_USHORT( p ); |
||
324 | |||
325 | OTV_TRACE(( " (MarkCount = %d)\n", MarkCount )); |
||
326 | |||
327 | OTV_LIMIT_CHECK( MarkCount * 4 ); |
||
328 | |||
329 | /* MarkRecord */ |
||
330 | for ( ; MarkCount > 0; MarkCount-- ) |
||
331 | { |
||
332 | p += 2; /* skip Class */ |
||
333 | /* MarkAnchor */ |
||
334 | otv_Anchor_validate( table + FT_NEXT_USHORT( p ), valid ); |
||
335 | } |
||
336 | |||
337 | OTV_EXIT; |
||
338 | } |
||
339 | |||
340 | |||
341 | /*************************************************************************/ |
||
342 | /*************************************************************************/ |
||
343 | /***** *****/ |
||
344 | /***** GPOS LOOKUP TYPE 1 *****/ |
||
345 | /***** *****/ |
||
346 | /*************************************************************************/ |
||
347 | /*************************************************************************/ |
||
348 | |||
349 | /* sets valid->extra3 (pointer to base table) */ |
||
350 | |||
351 | static void |
||
352 | otv_SinglePos_validate( FT_Bytes table, |
||
353 | OTV_Validator valid ) |
||
354 | { |
||
355 | FT_Bytes p = table; |
||
356 | FT_UInt PosFormat; |
||
357 | |||
358 | |||
359 | OTV_NAME_ENTER( "SinglePos" ); |
||
360 | |||
361 | OTV_LIMIT_CHECK( 2 ); |
||
362 | PosFormat = FT_NEXT_USHORT( p ); |
||
363 | |||
364 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
365 | |||
366 | valid->extra3 = table; |
||
367 | |||
368 | switch ( PosFormat ) |
||
369 | { |
||
370 | case 1: /* SinglePosFormat1 */ |
||
371 | { |
||
372 | FT_UInt Coverage, ValueFormat; |
||
373 | |||
374 | |||
375 | OTV_LIMIT_CHECK( 4 ); |
||
376 | Coverage = FT_NEXT_USHORT( p ); |
||
377 | ValueFormat = FT_NEXT_USHORT( p ); |
||
378 | |||
379 | otv_Coverage_validate( table + Coverage, valid, -1 ); |
||
380 | otv_ValueRecord_validate( p, ValueFormat, valid ); /* Value */ |
||
381 | } |
||
382 | break; |
||
383 | |||
384 | case 2: /* SinglePosFormat2 */ |
||
385 | { |
||
386 | FT_UInt Coverage, ValueFormat, ValueCount, len_value; |
||
387 | |||
388 | |||
389 | OTV_LIMIT_CHECK( 6 ); |
||
390 | Coverage = FT_NEXT_USHORT( p ); |
||
391 | ValueFormat = FT_NEXT_USHORT( p ); |
||
392 | ValueCount = FT_NEXT_USHORT( p ); |
||
393 | |||
394 | OTV_TRACE(( " (ValueCount = %d)\n", ValueCount )); |
||
395 | |||
396 | len_value = otv_value_length( ValueFormat ); |
||
397 | |||
398 | otv_Coverage_validate( table + Coverage, valid, ValueCount ); |
||
399 | |||
400 | OTV_LIMIT_CHECK( ValueCount * len_value ); |
||
401 | |||
402 | /* Value */ |
||
403 | for ( ; ValueCount > 0; ValueCount-- ) |
||
404 | { |
||
405 | otv_ValueRecord_validate( p, ValueFormat, valid ); |
||
406 | p += len_value; |
||
407 | } |
||
408 | } |
||
409 | break; |
||
410 | |||
411 | default: |
||
412 | FT_INVALID_FORMAT; |
||
413 | } |
||
414 | |||
415 | OTV_EXIT; |
||
416 | } |
||
417 | |||
418 | |||
419 | /*************************************************************************/ |
||
420 | /*************************************************************************/ |
||
421 | /***** *****/ |
||
422 | /***** GPOS LOOKUP TYPE 2 *****/ |
||
423 | /***** *****/ |
||
424 | /*************************************************************************/ |
||
425 | /*************************************************************************/ |
||
426 | |||
427 | static void |
||
428 | otv_PairSet_validate( FT_Bytes table, |
||
429 | FT_UInt format1, |
||
430 | FT_UInt format2, |
||
431 | OTV_Validator valid ) |
||
432 | { |
||
433 | FT_Bytes p = table; |
||
434 | FT_UInt value_len1, value_len2, PairValueCount; |
||
435 | |||
436 | |||
437 | OTV_NAME_ENTER( "PairSet" ); |
||
438 | |||
439 | OTV_LIMIT_CHECK( 2 ); |
||
440 | PairValueCount = FT_NEXT_USHORT( p ); |
||
441 | |||
442 | OTV_TRACE(( " (PairValueCount = %d)\n", PairValueCount )); |
||
443 | |||
444 | value_len1 = otv_value_length( format1 ); |
||
445 | value_len2 = otv_value_length( format2 ); |
||
446 | |||
447 | OTV_LIMIT_CHECK( PairValueCount * ( value_len1 + value_len2 + 2 ) ); |
||
448 | |||
449 | /* PairValueRecord */ |
||
450 | for ( ; PairValueCount > 0; PairValueCount-- ) |
||
451 | { |
||
452 | p += 2; /* skip SecondGlyph */ |
||
453 | |||
454 | if ( format1 ) |
||
455 | otv_ValueRecord_validate( p, format1, valid ); /* Value1 */ |
||
456 | p += value_len1; |
||
457 | |||
458 | if ( format2 ) |
||
459 | otv_ValueRecord_validate( p, format2, valid ); /* Value2 */ |
||
460 | p += value_len2; |
||
461 | } |
||
462 | |||
463 | OTV_EXIT; |
||
464 | } |
||
465 | |||
466 | |||
467 | /* sets valid->extra3 (pointer to base table) */ |
||
468 | |||
469 | static void |
||
470 | otv_PairPos_validate( FT_Bytes table, |
||
471 | OTV_Validator valid ) |
||
472 | { |
||
473 | FT_Bytes p = table; |
||
474 | FT_UInt PosFormat; |
||
475 | |||
476 | |||
477 | OTV_NAME_ENTER( "PairPos" ); |
||
478 | |||
479 | OTV_LIMIT_CHECK( 2 ); |
||
480 | PosFormat = FT_NEXT_USHORT( p ); |
||
481 | |||
482 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
483 | |||
484 | valid->extra3 = table; |
||
485 | |||
486 | switch ( PosFormat ) |
||
487 | { |
||
488 | case 1: /* PairPosFormat1 */ |
||
489 | { |
||
490 | FT_UInt Coverage, ValueFormat1, ValueFormat2, PairSetCount; |
||
491 | |||
492 | |||
493 | OTV_LIMIT_CHECK( 8 ); |
||
494 | Coverage = FT_NEXT_USHORT( p ); |
||
495 | ValueFormat1 = FT_NEXT_USHORT( p ); |
||
496 | ValueFormat2 = FT_NEXT_USHORT( p ); |
||
497 | PairSetCount = FT_NEXT_USHORT( p ); |
||
498 | |||
499 | OTV_TRACE(( " (PairSetCount = %d)\n", PairSetCount )); |
||
500 | |||
501 | otv_Coverage_validate( table + Coverage, valid, -1 ); |
||
502 | |||
503 | OTV_LIMIT_CHECK( PairSetCount * 2 ); |
||
504 | |||
505 | /* PairSetOffset */ |
||
506 | for ( ; PairSetCount > 0; PairSetCount-- ) |
||
507 | otv_PairSet_validate( table + FT_NEXT_USHORT( p ), |
||
508 | ValueFormat1, ValueFormat2, valid ); |
||
509 | } |
||
510 | break; |
||
511 | |||
512 | case 2: /* PairPosFormat2 */ |
||
513 | { |
||
514 | FT_UInt Coverage, ValueFormat1, ValueFormat2, ClassDef1, ClassDef2; |
||
515 | FT_UInt ClassCount1, ClassCount2, len_value1, len_value2, count; |
||
516 | |||
517 | |||
518 | OTV_LIMIT_CHECK( 14 ); |
||
519 | Coverage = FT_NEXT_USHORT( p ); |
||
520 | ValueFormat1 = FT_NEXT_USHORT( p ); |
||
521 | ValueFormat2 = FT_NEXT_USHORT( p ); |
||
522 | ClassDef1 = FT_NEXT_USHORT( p ); |
||
523 | ClassDef2 = FT_NEXT_USHORT( p ); |
||
524 | ClassCount1 = FT_NEXT_USHORT( p ); |
||
525 | ClassCount2 = FT_NEXT_USHORT( p ); |
||
526 | |||
527 | OTV_TRACE(( " (ClassCount1 = %d)\n", ClassCount1 )); |
||
528 | OTV_TRACE(( " (ClassCount2 = %d)\n", ClassCount2 )); |
||
529 | |||
530 | len_value1 = otv_value_length( ValueFormat1 ); |
||
531 | len_value2 = otv_value_length( ValueFormat2 ); |
||
532 | |||
533 | otv_Coverage_validate( table + Coverage, valid, -1 ); |
||
534 | otv_ClassDef_validate( table + ClassDef1, valid ); |
||
535 | otv_ClassDef_validate( table + ClassDef2, valid ); |
||
536 | |||
537 | OTV_LIMIT_CHECK( ClassCount1 * ClassCount2 * |
||
538 | ( len_value1 + len_value2 ) ); |
||
539 | |||
540 | /* Class1Record */ |
||
541 | for ( ; ClassCount1 > 0; ClassCount1-- ) |
||
542 | { |
||
543 | /* Class2Record */ |
||
544 | for ( count = ClassCount2; count > 0; count-- ) |
||
545 | { |
||
546 | if ( ValueFormat1 ) |
||
547 | /* Value1 */ |
||
548 | otv_ValueRecord_validate( p, ValueFormat1, valid ); |
||
549 | p += len_value1; |
||
550 | |||
551 | if ( ValueFormat2 ) |
||
552 | /* Value2 */ |
||
553 | otv_ValueRecord_validate( p, ValueFormat2, valid ); |
||
554 | p += len_value2; |
||
555 | } |
||
556 | } |
||
557 | } |
||
558 | break; |
||
559 | |||
560 | default: |
||
561 | FT_INVALID_FORMAT; |
||
562 | } |
||
563 | |||
564 | OTV_EXIT; |
||
565 | } |
||
566 | |||
567 | |||
568 | /*************************************************************************/ |
||
569 | /*************************************************************************/ |
||
570 | /***** *****/ |
||
571 | /***** GPOS LOOKUP TYPE 3 *****/ |
||
572 | /***** *****/ |
||
573 | /*************************************************************************/ |
||
574 | /*************************************************************************/ |
||
575 | |||
576 | static void |
||
577 | otv_CursivePos_validate( FT_Bytes table, |
||
578 | OTV_Validator valid ) |
||
579 | { |
||
580 | FT_Bytes p = table; |
||
581 | FT_UInt PosFormat; |
||
582 | |||
583 | |||
584 | OTV_NAME_ENTER( "CursivePos" ); |
||
585 | |||
586 | OTV_LIMIT_CHECK( 2 ); |
||
587 | PosFormat = FT_NEXT_USHORT( p ); |
||
588 | |||
589 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
590 | |||
591 | switch ( PosFormat ) |
||
592 | { |
||
593 | case 1: /* CursivePosFormat1 */ |
||
594 | { |
||
595 | FT_UInt table_size; |
||
596 | FT_UInt Coverage, EntryExitCount; |
||
597 | |||
598 | OTV_OPTIONAL_TABLE( EntryAnchor ); |
||
599 | OTV_OPTIONAL_TABLE( ExitAnchor ); |
||
600 | |||
601 | |||
602 | OTV_LIMIT_CHECK( 4 ); |
||
603 | Coverage = FT_NEXT_USHORT( p ); |
||
604 | EntryExitCount = FT_NEXT_USHORT( p ); |
||
605 | |||
606 | OTV_TRACE(( " (EntryExitCount = %d)\n", EntryExitCount )); |
||
607 | |||
608 | otv_Coverage_validate( table + Coverage, valid, EntryExitCount ); |
||
609 | |||
610 | OTV_LIMIT_CHECK( EntryExitCount * 4 ); |
||
611 | |||
612 | table_size = EntryExitCount * 4 + 4; |
||
613 | |||
614 | /* EntryExitRecord */ |
||
615 | for ( ; EntryExitCount > 0; EntryExitCount-- ) |
||
616 | { |
||
617 | OTV_OPTIONAL_OFFSET( EntryAnchor ); |
||
618 | OTV_OPTIONAL_OFFSET( ExitAnchor ); |
||
619 | |||
620 | OTV_SIZE_CHECK( EntryAnchor ); |
||
621 | if ( EntryAnchor ) |
||
622 | otv_Anchor_validate( table + EntryAnchor, valid ); |
||
623 | |||
624 | OTV_SIZE_CHECK( ExitAnchor ); |
||
625 | if ( ExitAnchor ) |
||
626 | otv_Anchor_validate( table + ExitAnchor, valid ); |
||
627 | } |
||
628 | } |
||
629 | break; |
||
630 | |||
631 | default: |
||
632 | FT_INVALID_FORMAT; |
||
633 | } |
||
634 | |||
635 | OTV_EXIT; |
||
636 | } |
||
637 | |||
638 | |||
639 | /*************************************************************************/ |
||
640 | /*************************************************************************/ |
||
641 | /***** *****/ |
||
642 | /***** GPOS LOOKUP TYPE 4 *****/ |
||
643 | /***** *****/ |
||
644 | /*************************************************************************/ |
||
645 | /*************************************************************************/ |
||
646 | |||
647 | /* UNDOCUMENTED (in OpenType 1.5): */ |
||
648 | /* BaseRecord tables can contain NULL pointers. */ |
||
649 | |||
650 | /* sets valid->extra2 (1) */ |
||
651 | |||
652 | static void |
||
653 | otv_MarkBasePos_validate( FT_Bytes table, |
||
654 | OTV_Validator valid ) |
||
655 | { |
||
656 | FT_Bytes p = table; |
||
657 | FT_UInt PosFormat; |
||
658 | |||
659 | |||
660 | OTV_NAME_ENTER( "MarkBasePos" ); |
||
661 | |||
662 | OTV_LIMIT_CHECK( 2 ); |
||
663 | PosFormat = FT_NEXT_USHORT( p ); |
||
664 | |||
665 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
666 | |||
667 | switch ( PosFormat ) |
||
668 | { |
||
669 | case 1: |
||
670 | valid->extra2 = 1; |
||
671 | OTV_NEST2( MarkBasePosFormat1, BaseArray ); |
||
672 | OTV_RUN( table, valid ); |
||
673 | break; |
||
674 | |||
675 | default: |
||
676 | FT_INVALID_FORMAT; |
||
677 | } |
||
678 | |||
679 | OTV_EXIT; |
||
680 | } |
||
681 | |||
682 | |||
683 | /*************************************************************************/ |
||
684 | /*************************************************************************/ |
||
685 | /***** *****/ |
||
686 | /***** GPOS LOOKUP TYPE 5 *****/ |
||
687 | /***** *****/ |
||
688 | /*************************************************************************/ |
||
689 | /*************************************************************************/ |
||
690 | |||
691 | /* sets valid->extra2 (1) */ |
||
692 | |||
693 | static void |
||
694 | otv_MarkLigPos_validate( FT_Bytes table, |
||
695 | OTV_Validator valid ) |
||
696 | { |
||
697 | FT_Bytes p = table; |
||
698 | FT_UInt PosFormat; |
||
699 | |||
700 | |||
701 | OTV_NAME_ENTER( "MarkLigPos" ); |
||
702 | |||
703 | OTV_LIMIT_CHECK( 2 ); |
||
704 | PosFormat = FT_NEXT_USHORT( p ); |
||
705 | |||
706 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
707 | |||
708 | switch ( PosFormat ) |
||
709 | { |
||
710 | case 1: |
||
711 | valid->extra2 = 1; |
||
712 | OTV_NEST3( MarkLigPosFormat1, LigatureArray, LigatureAttach ); |
||
713 | OTV_RUN( table, valid ); |
||
714 | break; |
||
715 | |||
716 | default: |
||
717 | FT_INVALID_FORMAT; |
||
718 | } |
||
719 | |||
720 | OTV_EXIT; |
||
721 | } |
||
722 | |||
723 | |||
724 | /*************************************************************************/ |
||
725 | /*************************************************************************/ |
||
726 | /***** *****/ |
||
727 | /***** GPOS LOOKUP TYPE 6 *****/ |
||
728 | /***** *****/ |
||
729 | /*************************************************************************/ |
||
730 | /*************************************************************************/ |
||
731 | |||
732 | /* sets valid->extra2 (0) */ |
||
733 | |||
734 | static void |
||
735 | otv_MarkMarkPos_validate( FT_Bytes table, |
||
736 | OTV_Validator valid ) |
||
737 | { |
||
738 | FT_Bytes p = table; |
||
739 | FT_UInt PosFormat; |
||
740 | |||
741 | |||
742 | OTV_NAME_ENTER( "MarkMarkPos" ); |
||
743 | |||
744 | OTV_LIMIT_CHECK( 2 ); |
||
745 | PosFormat = FT_NEXT_USHORT( p ); |
||
746 | |||
747 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
748 | |||
749 | switch ( PosFormat ) |
||
750 | { |
||
751 | case 1: |
||
752 | valid->extra2 = 0; |
||
753 | OTV_NEST2( MarkMarkPosFormat1, Mark2Array ); |
||
754 | OTV_RUN( table, valid ); |
||
755 | break; |
||
756 | |||
757 | default: |
||
758 | FT_INVALID_FORMAT; |
||
759 | } |
||
760 | |||
761 | OTV_EXIT; |
||
762 | } |
||
763 | |||
764 | |||
765 | /*************************************************************************/ |
||
766 | /*************************************************************************/ |
||
767 | /***** *****/ |
||
768 | /***** GPOS LOOKUP TYPE 7 *****/ |
||
769 | /***** *****/ |
||
770 | /*************************************************************************/ |
||
771 | /*************************************************************************/ |
||
772 | |||
773 | /* sets valid->extra1 (lookup count) */ |
||
774 | |||
775 | static void |
||
776 | otv_ContextPos_validate( FT_Bytes table, |
||
777 | OTV_Validator valid ) |
||
778 | { |
||
779 | FT_Bytes p = table; |
||
780 | FT_UInt PosFormat; |
||
781 | |||
782 | |||
783 | OTV_NAME_ENTER( "ContextPos" ); |
||
784 | |||
785 | OTV_LIMIT_CHECK( 2 ); |
||
786 | PosFormat = FT_NEXT_USHORT( p ); |
||
787 | |||
788 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
789 | |||
790 | switch ( PosFormat ) |
||
791 | { |
||
792 | case 1: |
||
793 | /* no need to check glyph indices/classes used as input for these */ |
||
794 | /* context rules since even invalid glyph indices/classes return */ |
||
795 | /* meaningful results */ |
||
796 | |||
797 | valid->extra1 = valid->lookup_count; |
||
798 | OTV_NEST3( ContextPosFormat1, PosRuleSet, PosRule ); |
||
799 | OTV_RUN( table, valid ); |
||
800 | break; |
||
801 | |||
802 | case 2: |
||
803 | /* no need to check glyph indices/classes used as input for these */ |
||
804 | /* context rules since even invalid glyph indices/classes return */ |
||
805 | /* meaningful results */ |
||
806 | |||
807 | OTV_NEST3( ContextPosFormat2, PosClassSet, PosClassRule ); |
||
808 | OTV_RUN( table, valid ); |
||
809 | break; |
||
810 | |||
811 | case 3: |
||
812 | OTV_NEST1( ContextPosFormat3 ); |
||
813 | OTV_RUN( table, valid ); |
||
814 | break; |
||
815 | |||
816 | default: |
||
817 | FT_INVALID_FORMAT; |
||
818 | } |
||
819 | |||
820 | OTV_EXIT; |
||
821 | } |
||
822 | |||
823 | |||
824 | /*************************************************************************/ |
||
825 | /*************************************************************************/ |
||
826 | /***** *****/ |
||
827 | /***** GPOS LOOKUP TYPE 8 *****/ |
||
828 | /***** *****/ |
||
829 | /*************************************************************************/ |
||
830 | /*************************************************************************/ |
||
831 | |||
832 | /* sets valid->extra1 (lookup count) */ |
||
833 | |||
834 | static void |
||
835 | otv_ChainContextPos_validate( FT_Bytes table, |
||
836 | OTV_Validator valid ) |
||
837 | { |
||
838 | FT_Bytes p = table; |
||
839 | FT_UInt PosFormat; |
||
840 | |||
841 | |||
842 | OTV_NAME_ENTER( "ChainContextPos" ); |
||
843 | |||
844 | OTV_LIMIT_CHECK( 2 ); |
||
845 | PosFormat = FT_NEXT_USHORT( p ); |
||
846 | |||
847 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
848 | |||
849 | switch ( PosFormat ) |
||
850 | { |
||
851 | case 1: |
||
852 | /* no need to check glyph indices/classes used as input for these */ |
||
853 | /* context rules since even invalid glyph indices/classes return */ |
||
854 | /* meaningful results */ |
||
855 | |||
856 | valid->extra1 = valid->lookup_count; |
||
857 | OTV_NEST3( ChainContextPosFormat1, |
||
858 | ChainPosRuleSet, ChainPosRule ); |
||
859 | OTV_RUN( table, valid ); |
||
860 | break; |
||
861 | |||
862 | case 2: |
||
863 | /* no need to check glyph indices/classes used as input for these */ |
||
864 | /* context rules since even invalid glyph indices/classes return */ |
||
865 | /* meaningful results */ |
||
866 | |||
867 | OTV_NEST3( ChainContextPosFormat2, |
||
868 | ChainPosClassSet, ChainPosClassRule ); |
||
869 | OTV_RUN( table, valid ); |
||
870 | break; |
||
871 | |||
872 | case 3: |
||
873 | OTV_NEST1( ChainContextPosFormat3 ); |
||
874 | OTV_RUN( table, valid ); |
||
875 | break; |
||
876 | |||
877 | default: |
||
878 | FT_INVALID_FORMAT; |
||
879 | } |
||
880 | |||
881 | OTV_EXIT; |
||
882 | } |
||
883 | |||
884 | |||
885 | /*************************************************************************/ |
||
886 | /*************************************************************************/ |
||
887 | /***** *****/ |
||
888 | /***** GPOS LOOKUP TYPE 9 *****/ |
||
889 | /***** *****/ |
||
890 | /*************************************************************************/ |
||
891 | /*************************************************************************/ |
||
892 | |||
893 | /* uses valid->type_funcs */ |
||
894 | |||
895 | static void |
||
896 | otv_ExtensionPos_validate( FT_Bytes table, |
||
897 | OTV_Validator valid ) |
||
898 | { |
||
899 | FT_Bytes p = table; |
||
900 | FT_UInt PosFormat; |
||
901 | |||
902 | |||
903 | OTV_NAME_ENTER( "ExtensionPos" ); |
||
904 | |||
905 | OTV_LIMIT_CHECK( 2 ); |
||
906 | PosFormat = FT_NEXT_USHORT( p ); |
||
907 | |||
908 | OTV_TRACE(( " (format %d)\n", PosFormat )); |
||
909 | |||
910 | switch ( PosFormat ) |
||
911 | { |
||
912 | case 1: /* ExtensionPosFormat1 */ |
||
913 | { |
||
914 | FT_UInt ExtensionLookupType; |
||
915 | FT_ULong ExtensionOffset; |
||
916 | OTV_Validate_Func validate; |
||
917 | |||
918 | |||
919 | OTV_LIMIT_CHECK( 6 ); |
||
920 | ExtensionLookupType = FT_NEXT_USHORT( p ); |
||
921 | ExtensionOffset = FT_NEXT_ULONG( p ); |
||
922 | |||
923 | if ( ExtensionLookupType == 0 || ExtensionLookupType >= 9 ) |
||
924 | FT_INVALID_DATA; |
||
925 | |||
926 | validate = valid->type_funcs[ExtensionLookupType - 1]; |
||
927 | validate( table + ExtensionOffset, valid ); |
||
928 | } |
||
929 | break; |
||
930 | |||
931 | default: |
||
932 | FT_INVALID_FORMAT; |
||
933 | } |
||
934 | |||
935 | OTV_EXIT; |
||
936 | } |
||
937 | |||
938 | |||
939 | static const OTV_Validate_Func otv_gpos_validate_funcs[9] = |
||
940 | { |
||
941 | otv_SinglePos_validate, |
||
942 | otv_PairPos_validate, |
||
943 | otv_CursivePos_validate, |
||
944 | otv_MarkBasePos_validate, |
||
945 | otv_MarkLigPos_validate, |
||
946 | otv_MarkMarkPos_validate, |
||
947 | otv_ContextPos_validate, |
||
948 | otv_ChainContextPos_validate, |
||
949 | otv_ExtensionPos_validate |
||
950 | }; |
||
951 | |||
952 | |||
953 | /* sets valid->type_count */ |
||
954 | /* sets valid->type_funcs */ |
||
955 | |||
956 | FT_LOCAL_DEF( void ) |
||
957 | otv_GPOS_subtable_validate( FT_Bytes table, |
||
958 | OTV_Validator valid ) |
||
959 | { |
||
960 | valid->type_count = 9; |
||
961 | valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; |
||
962 | |||
963 | otv_Lookup_validate( table, valid ); |
||
964 | } |
||
965 | |||
966 | |||
967 | /*************************************************************************/ |
||
968 | /*************************************************************************/ |
||
969 | /***** *****/ |
||
970 | /***** GPOS TABLE *****/ |
||
971 | /***** *****/ |
||
972 | /*************************************************************************/ |
||
973 | /*************************************************************************/ |
||
974 | |||
975 | /* sets valid->glyph_count */ |
||
976 | |||
977 | FT_LOCAL_DEF( void ) |
||
978 | otv_GPOS_validate( FT_Bytes table, |
||
979 | FT_UInt glyph_count, |
||
980 | FT_Validator ftvalid ) |
||
981 | { |
||
982 | OTV_ValidatorRec validrec; |
||
983 | OTV_Validator valid = &validrec; |
||
984 | FT_Bytes p = table; |
||
985 | FT_UInt ScriptList, FeatureList, LookupList; |
||
986 | |||
987 | |||
988 | valid->root = ftvalid; |
||
989 | |||
990 | FT_TRACE3(( "validating GPOS table\n" )); |
||
991 | OTV_INIT; |
||
992 | |||
993 | OTV_LIMIT_CHECK( 10 ); |
||
994 | |||
995 | if ( FT_NEXT_ULONG( p ) != 0x10000UL ) /* Version */ |
||
996 | FT_INVALID_FORMAT; |
||
997 | |||
998 | ScriptList = FT_NEXT_USHORT( p ); |
||
999 | FeatureList = FT_NEXT_USHORT( p ); |
||
1000 | LookupList = FT_NEXT_USHORT( p ); |
||
1001 | |||
1002 | valid->type_count = 9; |
||
1003 | valid->type_funcs = (OTV_Validate_Func*)otv_gpos_validate_funcs; |
||
1004 | valid->glyph_count = glyph_count; |
||
1005 | |||
1006 | otv_LookupList_validate( table + LookupList, |
||
1007 | valid ); |
||
1008 | otv_FeatureList_validate( table + FeatureList, table + LookupList, |
||
1009 | valid ); |
||
1010 | otv_ScriptList_validate( table + ScriptList, table + FeatureList, |
||
1011 | valid ); |
||
1012 | |||
1013 | FT_TRACE4(( "\n" )); |
||
1014 | } |
||
1015 | |||
1016 | |||
1017 | /* END */=><=> |