ReactOS 0.4.16-dev-2332-g4cba65d
sfwoff.c
Go to the documentation of this file.
1/****************************************************************************
2 *
3 * sfwoff.c
4 *
5 * WOFF format management (base).
6 *
7 * Copyright (C) 1996-2020 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 "sfwoff.h"
20#include <freetype/tttags.h>
23#include <freetype/ftgzip.h>
24
25
26 /**************************************************************************
27 *
28 * The macro FT_COMPONENT is used in trace mode. It is an implicit
29 * parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log
30 * messages during execution.
31 */
32#undef FT_COMPONENT
33#define FT_COMPONENT sfwoff
34
35
36#define WRITE_USHORT( p, v ) \
37 do \
38 { \
39 *(p)++ = (FT_Byte)( (v) >> 8 ); \
40 *(p)++ = (FT_Byte)( (v) >> 0 ); \
41 \
42 } while ( 0 )
43
44#define WRITE_ULONG( p, v ) \
45 do \
46 { \
47 *(p)++ = (FT_Byte)( (v) >> 24 ); \
48 *(p)++ = (FT_Byte)( (v) >> 16 ); \
49 *(p)++ = (FT_Byte)( (v) >> 8 ); \
50 *(p)++ = (FT_Byte)( (v) >> 0 ); \
51 \
52 } while ( 0 )
53
54
55 static void
57 {
58 FT_Memory memory = stream->memory;
59
60
61 FT_FREE( stream->base );
62
63 stream->size = 0;
64 stream->base = NULL;
65 stream->close = NULL;
66 }
67
68
69 FT_CALLBACK_DEF( int )
71 const void* b )
72 {
73 WOFF_Table table1 = *(WOFF_Table*)a;
74 WOFF_Table table2 = *(WOFF_Table*)b;
75
76 FT_ULong offset1 = table1->Offset;
77 FT_ULong offset2 = table2->Offset;
78
79
80 if ( offset1 > offset2 )
81 return 1;
82 else if ( offset1 < offset2 )
83 return -1;
84 else
85 return 0;
86 }
87
88
89 /* Replace `face->root.stream' with a stream containing the extracted */
90 /* SFNT of a WOFF font. */
91
95 {
96 FT_Memory memory = stream->memory;
98
99 WOFF_HeaderRec woff;
102
103 FT_ULong woff_offset;
104
105 FT_Byte* sfnt = NULL;
106 FT_Stream sfnt_stream = NULL;
107
108 FT_Byte* sfnt_header;
109 FT_ULong sfnt_offset;
110
111 FT_Int nn;
112 FT_ULong old_tag = 0;
113
114 static const FT_Frame_Field woff_header_fields[] =
115 {
116#undef FT_STRUCTURE
117#define FT_STRUCTURE WOFF_HeaderRec
118
119 FT_FRAME_START( 44 ),
121 FT_FRAME_ULONG ( flavor ),
123 FT_FRAME_USHORT( num_tables ),
125 FT_FRAME_ULONG ( totalSfntSize ),
126 FT_FRAME_USHORT( majorVersion ),
127 FT_FRAME_USHORT( minorVersion ),
128 FT_FRAME_ULONG ( metaOffset ),
129 FT_FRAME_ULONG ( metaLength ),
130 FT_FRAME_ULONG ( metaOrigLength ),
131 FT_FRAME_ULONG ( privOffset ),
132 FT_FRAME_ULONG ( privLength ),
134 };
135
136
137 FT_ASSERT( stream == face->root.stream );
138 FT_ASSERT( FT_STREAM_POS() == 0 );
139
140 if ( FT_STREAM_READ_FIELDS( woff_header_fields, &woff ) )
141 return error;
142
143 /* Make sure we don't recurse back here or hit TTC code. */
144 if ( woff.flavor == TTAG_wOFF || woff.flavor == TTAG_ttcf )
145 return FT_THROW( Invalid_Table );
146
147 /* Miscellaneous checks. */
148 if ( woff.length != stream->size ||
149 woff.num_tables == 0 ||
150 44 + woff.num_tables * 20UL >= woff.length ||
151 12 + woff.num_tables * 16UL >= woff.totalSfntSize ||
152 ( woff.totalSfntSize & 3 ) != 0 ||
153 ( woff.metaOffset == 0 && ( woff.metaLength != 0 ||
154 woff.metaOrigLength != 0 ) ) ||
155 ( woff.metaLength != 0 && woff.metaOrigLength == 0 ) ||
156 ( woff.privOffset == 0 && woff.privLength != 0 ) )
157 {
158 FT_ERROR(( "woff_font_open: invalid WOFF header\n" ));
159 return FT_THROW( Invalid_Table );
160 }
161
162 /* Don't trust `totalSfntSize' before thorough checks. */
163 if ( FT_ALLOC( sfnt, 12 + woff.num_tables * 16UL ) ||
164 FT_NEW( sfnt_stream ) )
165 goto Exit;
166
167 sfnt_header = sfnt;
168
169 /* Write sfnt header. */
170 {
171 FT_UInt searchRange, entrySelector, rangeShift, x;
172
173
174 x = woff.num_tables;
175 entrySelector = 0;
176 while ( x )
177 {
178 x >>= 1;
179 entrySelector += 1;
180 }
181 entrySelector--;
182
183 searchRange = ( 1 << entrySelector ) * 16;
184 rangeShift = woff.num_tables * 16 - searchRange;
185
186 WRITE_ULONG ( sfnt_header, woff.flavor );
187 WRITE_USHORT( sfnt_header, woff.num_tables );
188 WRITE_USHORT( sfnt_header, searchRange );
189 WRITE_USHORT( sfnt_header, entrySelector );
190 WRITE_USHORT( sfnt_header, rangeShift );
191 }
192
193 /* While the entries in the sfnt header must be sorted by the */
194 /* tag value, the tables themselves are not. We thus have to */
195 /* sort them by offset and check that they don't overlap. */
196
197 if ( FT_NEW_ARRAY( tables, woff.num_tables ) ||
198 FT_NEW_ARRAY( indices, woff.num_tables ) )
199 goto Exit;
200
201 FT_TRACE2(( "\n"
202 " tag offset compLen origLen checksum\n"
203 " -------------------------------------------\n" ));
204
205 if ( FT_FRAME_ENTER( 20L * woff.num_tables ) )
206 goto Exit;
207
208 for ( nn = 0; nn < woff.num_tables; nn++ )
209 {
210 WOFF_Table table = tables + nn;
211
212 table->Tag = FT_GET_TAG4();
213 table->Offset = FT_GET_ULONG();
214 table->CompLength = FT_GET_ULONG();
215 table->OrigLength = FT_GET_ULONG();
216 table->CheckSum = FT_GET_ULONG();
217
218 FT_TRACE2(( " %c%c%c%c %08lx %08lx %08lx %08lx\n",
219 (FT_Char)( table->Tag >> 24 ),
220 (FT_Char)( table->Tag >> 16 ),
221 (FT_Char)( table->Tag >> 8 ),
222 (FT_Char)( table->Tag ),
223 table->Offset,
224 table->CompLength,
225 table->OrigLength,
226 table->CheckSum ));
227
228 if ( table->Tag <= old_tag )
229 {
231
232 FT_ERROR(( "woff_font_open: table tags are not sorted\n" ));
233 error = FT_THROW( Invalid_Table );
234 goto Exit;
235 }
236
237 old_tag = table->Tag;
238 indices[nn] = table;
239 }
240
242
243 /* Sort by offset. */
244
246 woff.num_tables,
247 sizeof ( WOFF_Table ),
249
250 /* Check offsets and lengths. */
251
252 woff_offset = 44 + woff.num_tables * 20L;
253 sfnt_offset = 12 + woff.num_tables * 16L;
254
255 for ( nn = 0; nn < woff.num_tables; nn++ )
256 {
258
259
260 if ( table->Offset != woff_offset ||
261 table->CompLength > woff.length ||
262 table->Offset > woff.length - table->CompLength ||
263 table->OrigLength > woff.totalSfntSize ||
264 sfnt_offset > woff.totalSfntSize - table->OrigLength ||
265 table->CompLength > table->OrigLength )
266 {
267 FT_ERROR(( "woff_font_open: invalid table offsets\n" ));
268 error = FT_THROW( Invalid_Table );
269 goto Exit;
270 }
271
272 table->OrigOffset = sfnt_offset;
273
274 /* The offsets must be multiples of 4. */
275 woff_offset += ( table->CompLength + 3 ) & ~3U;
276 sfnt_offset += ( table->OrigLength + 3 ) & ~3U;
277 }
278
279 /*
280 * Final checks!
281 *
282 * We don't decode and check the metadata block.
283 * We don't check table checksums either.
284 * But other than those, I think we implement all
285 * `MUST' checks from the spec.
286 */
287
288 if ( woff.metaOffset )
289 {
290 if ( woff.metaOffset != woff_offset ||
291 woff.metaOffset + woff.metaLength > woff.length )
292 {
293 FT_ERROR(( "woff_font_open:"
294 " invalid `metadata' offset or length\n" ));
295 error = FT_THROW( Invalid_Table );
296 goto Exit;
297 }
298
299 /* We have padding only ... */
300 woff_offset += woff.metaLength;
301 }
302
303 if ( woff.privOffset )
304 {
305 /* ... if it isn't the last block. */
306 woff_offset = ( woff_offset + 3 ) & ~3U;
307
308 if ( woff.privOffset != woff_offset ||
309 woff.privOffset + woff.privLength > woff.length )
310 {
311 FT_ERROR(( "woff_font_open: invalid `private' offset or length\n" ));
312 error = FT_THROW( Invalid_Table );
313 goto Exit;
314 }
315
316 /* No padding for the last block. */
317 woff_offset += woff.privLength;
318 }
319
320 if ( sfnt_offset != woff.totalSfntSize ||
321 woff_offset != woff.length )
322 {
323 FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" ));
324 error = FT_THROW( Invalid_Table );
325 goto Exit;
326 }
327
328 /* Now use `totalSfntSize'. */
329 if ( FT_REALLOC( sfnt,
330 12 + woff.num_tables * 16UL,
331 woff.totalSfntSize ) )
332 goto Exit;
333
334 sfnt_header = sfnt + 12;
335
336 /* Write the tables. */
337
338 for ( nn = 0; nn < woff.num_tables; nn++ )
339 {
340 WOFF_Table table = tables + nn;
341
342
343 /* Write SFNT table entry. */
344 WRITE_ULONG( sfnt_header, table->Tag );
345 WRITE_ULONG( sfnt_header, table->CheckSum );
346 WRITE_ULONG( sfnt_header, table->OrigOffset );
347 WRITE_ULONG( sfnt_header, table->OrigLength );
348
349 /* Write table data. */
350 if ( FT_STREAM_SEEK( table->Offset ) ||
351 FT_FRAME_ENTER( table->CompLength ) )
352 goto Exit;
353
354 if ( table->CompLength == table->OrigLength )
355 {
356 /* Uncompressed data; just copy. */
357 ft_memcpy( sfnt + table->OrigOffset,
358 stream->cursor,
359 table->OrigLength );
360 }
361 else
362 {
363#ifdef FT_CONFIG_OPTION_USE_ZLIB
364
365 /* Uncompress with zlib. */
366 FT_ULong output_len = table->OrigLength;
367
368
370 sfnt + table->OrigOffset, &output_len,
371 stream->cursor, table->CompLength );
372 if ( error )
373 goto Exit1;
374 if ( output_len != table->OrigLength )
375 {
376 FT_ERROR(( "woff_font_open: compressed table length mismatch\n" ));
377 error = FT_THROW( Invalid_Table );
378 goto Exit1;
379 }
380
381#else /* !FT_CONFIG_OPTION_USE_ZLIB */
382
383 error = FT_THROW( Unimplemented_Feature );
384 goto Exit1;
385
386#endif /* !FT_CONFIG_OPTION_USE_ZLIB */
387 }
388
390
391 /* We don't check whether the padding bytes in the WOFF file are */
392 /* actually '\0'. For the output, however, we do set them properly. */
393 sfnt_offset = table->OrigOffset + table->OrigLength;
394 while ( sfnt_offset & 3 )
395 {
396 sfnt[sfnt_offset] = '\0';
397 sfnt_offset++;
398 }
399 }
400
401 /* Ok! Finally ready. Swap out stream and return. */
402 FT_Stream_OpenMemory( sfnt_stream, sfnt, woff.totalSfntSize );
403 sfnt_stream->memory = stream->memory;
404 sfnt_stream->close = sfnt_stream_close;
405
407 face->root.stream,
408 ( face->root.face_flags & FT_FACE_FLAG_EXTERNAL_STREAM ) != 0 );
409
410 face->root.stream = sfnt_stream;
411
412 face->root.face_flags &= ~FT_FACE_FLAG_EXTERNAL_STREAM;
413
414 Exit:
415 FT_FREE( tables );
416 FT_FREE( indices );
417
418 if ( error )
419 {
420 FT_FREE( sfnt );
421 FT_Stream_Close( sfnt_stream );
422 FT_FREE( sfnt_stream );
423 }
424
425 return error;
426
427 Exit1:
429 goto Exit;
430 }
431
432
433#undef WRITE_USHORT
434#undef WRITE_ULONG
435
436
437/* END */
#define FT_CALLBACK_DEF(x)
#define FT_LOCAL_DEF(x)
#define NULL
Definition: types.h:112
r reserved
Definition: btrfs.c:3006
struct nls_table * tables
Definition: nls_base.c:22
#define FT_FACE_FLAG_EXTERNAL_STREAM
Definition: freetype.h:1207
return FT_Err_Ok
Definition: ftbbox.c:526
#define FT_ASSERT(condition)
Definition: ftdebug.h:241
#define FT_ERROR(varformat)
Definition: ftdebug.h:211
#define FT_THROW(e)
Definition: ftdebug.h:243
#define FT_TRACE2(varformat)
Definition: ftdebug.h:189
FT_Gzip_Uncompress(FT_Memory memory, FT_Byte *output, FT_ULong *output_len, const FT_Byte *input, FT_ULong input_len)
Definition: ftgzip.c:803
#define FT_REALLOC(ptr, cursz, newsz)
Definition: ftmemory.h:314
#define FT_NEW_ARRAY(ptr, count)
Definition: ftmemory.h:341
#define FT_NEW(ptr)
Definition: ftmemory.h:339
#define FT_ALLOC(ptr, size)
Definition: ftmemory.h:311
#define FT_FREE(ptr)
Definition: ftmemory.h:337
#define ft_memcpy
Definition: ftstdlib.h:82
#define ft_qsort
Definition: ftstdlib.h:122
#define FT_FRAME_ENTER(size)
Definition: ftstream.h:548
#define FT_FRAME_END
Definition: ftstream.h:118
#define FT_GET_ULONG()
Definition: ftstream.h:315
#define FT_STREAM_SEEK(position)
Definition: ftstream.h:525
#define FT_STREAM_POS()
Definition: ftstream.h:522
FT_Stream_Close(FT_Stream stream)
Definition: ftstream.c:48
#define FT_FRAME_ULONG(f)
Definition: ftstream.h:121
#define FT_GET_TAG4()
Definition: ftstream.h:316
#define FT_FRAME_EXIT()
Definition: ftstream.h:553
#define FT_STREAM_READ_FIELDS(fields, object)
Definition: ftstream.h:544
FT_Stream_Free(FT_Stream stream, FT_Int external)
Definition: ftobjs.c:257
#define FT_FRAME_START(size)
Definition: ftstream.h:117
FT_Stream_OpenMemory(FT_Stream stream, const FT_Byte *base, FT_ULong size)
Definition: ftstream.c:34
#define FT_FRAME_USHORT(f)
Definition: ftstream.h:123
typedefFT_BEGIN_HEADER struct FT_MemoryRec_ * FT_Memory
Definition: ftsystem.h:64
signed char FT_Char
Definition: fttypes.h:143
unsigned long FT_ULong
Definition: fttypes.h:253
unsigned char FT_Byte
Definition: fttypes.h:154
int FT_Error
Definition: fttypes.h:299
unsigned int FT_UInt
Definition: fttypes.h:231
signed int FT_Int
Definition: fttypes.h:220
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei GLenum const GLvoid * indices
Definition: gl.h:1545
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
#define error(str)
Definition: mkdosfs.c:1605
static char memory[1024 *256]
Definition: process.c:122
#define WRITE_ULONG(p, v)
Definition: sfwoff.c:44
compare_offsets(const void *a, const void *b)
Definition: sfwoff.c:70
static void sfnt_stream_close(FT_Stream stream)
Definition: sfwoff.c:56
woff_open_font(FT_Stream stream, TT_Face face)
Definition: sfwoff.c:93
#define WRITE_USHORT(p, v)
Definition: sfwoff.c:36
static void Exit(void)
Definition: sock.c:1330
FT_Memory memory
Definition: ftsystem.h:338
FT_Stream_CloseFunc close
Definition: ftsystem.h:336
FT_ULong Offset
Definition: wofftypes.h:96
Definition: parse.h:23
unsigned int size
Definition: parse.h:27
SFNT_Service sfnt
Definition: ttdriver.c:208
#define TTAG_wOFF
Definition: tttags.h:108
#define TTAG_ttcf
Definition: tttags.h:101
FT_BEGIN_HEADER struct WOFF_HeaderRec_ WOFF_HeaderRec
ActualNumberDriverObjects * sizeof(PDRIVER_OBJECT)) PDRIVER_OBJECT *DriverObjectList
#define const
Definition: zconf.h:233