1 : /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is WOFF font packaging code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2009
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Jonathan Kew <jfkthame@gmail.com>
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either the GNU General Public License Version 2 or later (the "GPL"), or
26 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "woff-private.h"
39 :
40 : #include <stdio.h>
41 : #include <stdlib.h>
42 : #include <string.h>
43 : #include "zlib.h"
44 :
45 : #ifdef WOFF_MOZILLA_CLIENT /* define this when building as part of Gecko */
46 : # include "prmem.h"
47 : # define malloc PR_Malloc
48 : # define realloc PR_Realloc
49 : # define free PR_Free
50 : #endif
51 :
52 : /*
53 : * Just simple whole-file encoding and decoding functions; a more extensive
54 : * WOFF library could provide support for accessing individual tables from a
55 : * compressed font, alternative options for memory allocation/ownership and
56 : * error handling, etc.
57 : */
58 :
59 : /* on errors, each function sets a status variable and jumps to failure: */
60 : #undef FAIL
61 : #define FAIL(err) do { status |= err; goto failure; } while (0)
62 :
63 : /* adjust an offset for longword alignment */
64 : #define LONGALIGN(x) (((x) + 3) & ~3)
65 :
66 : static int
67 0 : compareOffsets(const void * lhs, const void * rhs)
68 : {
69 0 : const tableOrderRec * a = (const tableOrderRec *) lhs;
70 0 : const tableOrderRec * b = (const tableOrderRec *) rhs;
71 : /* don't simply return a->offset - b->offset because these are unsigned
72 : offset values; could convert to int, but possible integer overflow */
73 0 : return a->offset > b->offset ? 1 :
74 0 : a->offset < b->offset ? -1 :
75 : 0;
76 : }
77 :
78 : #ifndef WOFF_MOZILLA_CLIENT
79 :
80 : /******************************************************************/
81 : /* * * * * * * * * * * * * * ENCODING * * * * * * * * * * * * * * */
82 : /******************************************************************/
83 :
84 : static uint32_t
85 : calcChecksum(const sfntDirEntry * dirEntry,
86 : const uint8_t * sfntData, uint32_t sfntLen)
87 : {
88 : /* just returns zero on errors, they will be detected again elsewhere */
89 : const uint32_t * csumPtr;
90 : const uint32_t * csumEnd;
91 : uint32_t csum = 0;
92 : uint32_t length = READ32BE(dirEntry->length);
93 : uint32_t offset = READ32BE(dirEntry->offset);
94 : uint32_t tag;
95 : if (LONGALIGN(length) < length) { /* overflow */
96 : return csum;
97 : } else {
98 : length = LONGALIGN(length);
99 : }
100 : if ((offset & 3) != 0) { /* invalid - not properly aligned */
101 : return csum;
102 : }
103 : if (length > sfntLen || offset > sfntLen - length) {
104 : return csum;
105 : }
106 : csumPtr = (const uint32_t *) (sfntData + offset);
107 : csumEnd = csumPtr + length / 4;
108 : while (csumPtr < csumEnd) {
109 : csum += READ32BE(*csumPtr);
110 : csumPtr++;
111 : }
112 : tag = READ32BE(dirEntry->tag);
113 : if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) {
114 : const sfntHeadTable * head;
115 : if (length < HEAD_TABLE_SIZE) {
116 : return 0;
117 : }
118 : head = (const sfntHeadTable *)(sfntData + offset);
119 : csum -= READ32BE(head->checkSumAdjustment);
120 : }
121 : return csum;
122 : }
123 :
124 : const uint8_t *
125 : woffEncode(const uint8_t * sfntData, uint32_t sfntLen,
126 : uint16_t majorVersion, uint16_t minorVersion,
127 : uint32_t * woffLen, uint32_t * pStatus)
128 : {
129 : uint8_t * woffData = NULL;
130 : tableOrderRec * tableOrder = NULL;
131 :
132 : uint32_t tableOffset;
133 : uint32_t totalSfntSize;
134 :
135 : uint16_t numOrigTables;
136 : uint16_t numTables;
137 : uint16_t tableIndex;
138 : uint16_t order;
139 : const sfntDirEntry * sfntDir;
140 : uint32_t tableBase;
141 : uint32_t checkSumAdjustment = 0;
142 : woffHeader * newHeader;
143 : uint32_t tag = 0;
144 : uint32_t removedDsigSize = 0;
145 : uint32_t status = eWOFF_ok;
146 :
147 : const sfntHeader * header = (const sfntHeader *) (sfntData);
148 : const sfntHeadTable * head = NULL;
149 :
150 : if (pStatus && WOFF_FAILURE(*pStatus)) {
151 : return NULL;
152 : }
153 :
154 : if (READ32BE(header->version) != SFNT_VERSION_TT &&
155 : READ32BE(header->version) != SFNT_VERSION_CFF &&
156 : READ32BE(header->version) != SFNT_VERSION_true) {
157 : status |= eWOFF_warn_unknown_version;
158 : }
159 :
160 : numOrigTables = READ16BE(header->numTables);
161 : sfntDir = (const sfntDirEntry *) (sfntData + sizeof(sfntHeader));
162 :
163 : for (tableIndex = 0; tableIndex < numOrigTables; ++tableIndex) {
164 : /* validate table checksums, to figure out if we need to drop DSIG;
165 : also check that table directory is correctly sorted */
166 : uint32_t prevTag = tag;
167 : uint32_t csum = calcChecksum(&sfntDir[tableIndex], sfntData, sfntLen);
168 : if (csum != READ32BE(sfntDir[tableIndex].checksum)) {
169 : status |= eWOFF_warn_checksum_mismatch;
170 : }
171 : checkSumAdjustment += csum;
172 : tag = READ32BE(sfntDir[tableIndex].tag);
173 : if (tag <= prevTag) {
174 : FAIL(eWOFF_invalid);
175 : }
176 : if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) {
177 : if (READ32BE(sfntDir[tableIndex].length) < HEAD_TABLE_SIZE) {
178 : FAIL(eWOFF_invalid);
179 : }
180 : head = (const sfntHeadTable *)(sfntData +
181 : READ32BE(sfntDir[tableIndex].offset));
182 : }
183 : }
184 : if (!head) {
185 : FAIL(eWOFF_invalid);
186 : }
187 : if ((status & eWOFF_warn_checksum_mismatch) == 0) {
188 : /* no point even checking if we already have an error,
189 : as fixing that will change the overall checksum too */
190 : const uint32_t * csumPtr = (const uint32_t *) sfntData;
191 : const uint32_t * csumEnd = csumPtr + 3 + 4 * numOrigTables;
192 : while (csumPtr < csumEnd) {
193 : checkSumAdjustment += READ32BE(*csumPtr);
194 : ++csumPtr;
195 : }
196 : checkSumAdjustment = 0xB1B0AFBA - checkSumAdjustment;
197 : if (checkSumAdjustment != READ32BE(head->checkSumAdjustment)) {
198 : status |= eWOFF_warn_checksum_mismatch;
199 : }
200 : }
201 :
202 : /* Fixing checkSumAdjustment is tricky, because if there's a DSIG table,
203 : we're going to have to remove that, which in turn means that table
204 : offsets in the directory will all change.
205 : And recalculating checkSumAdjustment requires taking account of any
206 : individual table checksum corrections, but they have not actually been
207 : applied to the sfnt data at this point.
208 : And finally, we'd need to get the corrected checkSumAdjustment into the
209 : encoded head table (but we can't modify the original sfnt data).
210 : An easier way out seems to be to go ahead and encode the font, knowing
211 : that checkSumAdjustment will be wrong; then (if the status flag
212 : eWOFF_warn_checksum_mismatch is set) we'll decode the font back to
213 : sfnt format. This will fix up the checkSumAdjustment (and return a
214 : warning status). We'll ignore that warning, and then re-encode the
215 : new, cleaned-up sfnt to get the final WOFF data. Perhaps not the most
216 : efficient approach, but it seems simpler than trying to predict the
217 : correct final checkSumAdjustment and incorporate it into the head
218 : table on the fly. */
219 :
220 : tableOrder = (tableOrderRec *) malloc(numOrigTables * sizeof(tableOrderRec));
221 : if (!tableOrder) {
222 : FAIL(eWOFF_out_of_memory);
223 : }
224 : for (tableIndex = 0, numTables = 0;
225 : tableIndex < numOrigTables; ++tableIndex) {
226 : if ((status & eWOFF_warn_checksum_mismatch) != 0) {
227 : /* check for DSIG table that we must drop if we're fixing checksums */
228 : tag = READ32BE(sfntDir[tableIndex].tag);
229 : if (tag == TABLE_TAG_DSIG) {
230 : status |= eWOFF_warn_removed_DSIG;
231 : removedDsigSize = READ32BE(sfntDir[tableIndex].length);
232 : if (LONGALIGN(removedDsigSize) < removedDsigSize) {
233 : FAIL(eWOFF_invalid);
234 : }
235 : continue;
236 : }
237 : }
238 : tableOrder[numTables].offset = READ32BE(sfntDir[tableIndex].offset);
239 : tableOrder[numTables].oldIndex = tableIndex;
240 : tableOrder[numTables].newIndex = numTables;
241 : ++numTables;
242 : }
243 : qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets);
244 :
245 : /* initially, allocate space for header and directory */
246 : /* cannot be too big because numTables is 16-bit */
247 : tableOffset = sizeof(woffHeader) + numTables * sizeof(woffDirEntry);
248 : woffData = (uint8_t *) malloc(tableOffset);
249 : if (!woffData) {
250 : FAIL(eWOFF_out_of_memory);
251 : }
252 :
253 : /* accumulator for total expected size of decoded font */
254 : totalSfntSize = sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry);
255 :
256 : /*
257 : * We use a macro for this rather than creating a variable because woffData
258 : * will get reallocated during encoding. The macro avoids the risk of using a
259 : * stale pointer, and the compiler should optimize multiple successive uses.
260 : */
261 : #define WOFFDIR ((woffDirEntry *) (woffData + sizeof(woffHeader)))
262 :
263 : for (order = 0; order < numTables; ++order) {
264 : uLong sourceLen, destLen;
265 : uint32_t sourceOffset;
266 :
267 : uint16_t oldIndex = tableOrder[order].oldIndex;
268 : uint16_t newIndex = tableOrder[order].newIndex;
269 :
270 : WOFFDIR[newIndex].tag = sfntDir[oldIndex].tag;
271 : if ((status & eWOFF_warn_checksum_mismatch) != 0) {
272 : uint32_t csum = calcChecksum(&sfntDir[oldIndex], sfntData, sfntLen);
273 : WOFFDIR[newIndex].checksum = READ32BE(csum);
274 : } else {
275 : WOFFDIR[newIndex].checksum = sfntDir[oldIndex].checksum;
276 : }
277 : WOFFDIR[newIndex].origLen = sfntDir[oldIndex].length;
278 :
279 : /* we always realloc woffData to a long-aligned size, so this is safe */
280 : while ((tableOffset & 3) != 0) {
281 : woffData[tableOffset++] = 0;
282 : }
283 : WOFFDIR[newIndex].offset = READ32BE(tableOffset);
284 :
285 : /* allocate enough space for upper bound of compressed size */
286 : sourceOffset = READ32BE(sfntDir[oldIndex].offset);
287 : if ((sourceOffset & 3) != 0) {
288 : status |= eWOFF_warn_misaligned_table;
289 : }
290 : sourceLen = READ32BE(sfntDir[oldIndex].length);
291 : if (sourceLen > sfntLen || sourceOffset > sfntLen - sourceLen) {
292 : FAIL(eWOFF_invalid);
293 : }
294 : destLen = compressBound(sourceLen);
295 : if (LONGALIGN(destLen) < destLen) {
296 : /* something weird is going on if this overflows! */
297 : FAIL(eWOFF_invalid);
298 : }
299 : destLen = LONGALIGN(destLen);
300 : if (tableOffset + destLen < tableOffset) {
301 : FAIL(eWOFF_invalid);
302 : }
303 : woffData = (uint8_t *) realloc(woffData, tableOffset + destLen);
304 : if (!woffData) {
305 : FAIL(eWOFF_out_of_memory);
306 : }
307 :
308 : /* do the compression directly into the WOFF data block */
309 : if (compress2((Bytef *) (woffData + tableOffset), &destLen,
310 : (const Bytef *) (sfntData + sourceOffset),
311 : sourceLen, 9) != Z_OK) {
312 : FAIL(eWOFF_compression_failure);
313 : }
314 : if (destLen < sourceLen) {
315 : /* compressed table was smaller */
316 : tableOffset += destLen; /* checked for potential overflow above */
317 : WOFFDIR[newIndex].compLen = READ32BE(destLen);
318 : } else {
319 : /* compression didn't make it smaller, so store original data instead */
320 : if (LONGALIGN(sourceLen) < sourceLen) {
321 : FAIL(eWOFF_invalid); /* overflow, bail out */
322 : }
323 : destLen = sourceLen;
324 : /* reallocate to ensure enough space for the table,
325 : plus potential padding after it */
326 : if (tableOffset + LONGALIGN(sourceLen) < tableOffset) {
327 : FAIL(eWOFF_invalid); /* overflow, bail out */
328 : }
329 : woffData = (uint8_t *) realloc(woffData,
330 : tableOffset + LONGALIGN(sourceLen));
331 : if (!woffData) {
332 : FAIL(eWOFF_out_of_memory);
333 : }
334 : /* copy the original data into place */
335 : memcpy(woffData + tableOffset,
336 : sfntData + READ32BE(sfntDir[oldIndex].offset), sourceLen);
337 : if (tableOffset + sourceLen < tableOffset) {
338 : FAIL(eWOFF_invalid); /* overflow, bail out */
339 : }
340 : tableOffset += sourceLen;
341 : WOFFDIR[newIndex].compLen = WOFFDIR[newIndex].origLen;
342 : }
343 :
344 : /* update total size of uncompressed OpenType with table size */
345 : if (totalSfntSize + sourceLen < totalSfntSize) {
346 : FAIL(eWOFF_invalid); /* overflow, bail out */
347 : }
348 : totalSfntSize += sourceLen;
349 : if (LONGALIGN(totalSfntSize) < totalSfntSize) {
350 : FAIL(eWOFF_invalid);
351 : }
352 : totalSfntSize = LONGALIGN(totalSfntSize);
353 : }
354 :
355 : if (totalSfntSize > sfntLen) {
356 : if (totalSfntSize > LONGALIGN(sfntLen)) {
357 : FAIL(eWOFF_invalid);
358 : } else {
359 : status |= eWOFF_warn_unpadded_table;
360 : }
361 : } else if (totalSfntSize < sfntLen) {
362 : /* check if the remaining data is a DSIG we're removing;
363 : if so, we're already warning about that */
364 : if ((status & eWOFF_warn_removed_DSIG) != 0 ||
365 : sfntLen - totalSfntSize >
366 : LONGALIGN(removedDsigSize) + sizeof(sfntDirEntry)) {
367 : status |= eWOFF_warn_trailing_data;
368 : }
369 : }
370 :
371 : /* write the header */
372 : newHeader = (woffHeader *) (woffData);
373 : newHeader->signature = WOFF_SIGNATURE;
374 : newHeader->signature = READ32BE(newHeader->signature);
375 : newHeader->flavor = header->version;
376 : newHeader->length = READ32BE(tableOffset);
377 : newHeader->numTables = READ16BE(numTables);
378 : newHeader->reserved = 0;
379 : newHeader->totalSfntSize = READ32BE(totalSfntSize);
380 : newHeader->majorVersion = READ16BE(majorVersion);
381 : newHeader->minorVersion = READ16BE(minorVersion);
382 : newHeader->metaOffset = 0;
383 : newHeader->metaCompLen = 0;
384 : newHeader->metaOrigLen = 0;
385 : newHeader->privOffset = 0;
386 : newHeader->privLen = 0;
387 :
388 : free(tableOrder);
389 :
390 : if ((status & eWOFF_warn_checksum_mismatch) != 0) {
391 : /* The original font had checksum errors, so we now decode our WOFF data
392 : back to sfnt format (which fixes checkSumAdjustment), then re-encode
393 : to get a clean copy. */
394 : const uint8_t * cleanSfnt = woffDecode(woffData, tableOffset,
395 : &sfntLen, &status);
396 : if (WOFF_FAILURE(status)) {
397 : FAIL(status);
398 : }
399 : free(woffData);
400 : woffData = (uint8_t *) woffEncode(cleanSfnt, sfntLen,
401 : majorVersion, minorVersion,
402 : &tableOffset, &status);
403 : free((void *) cleanSfnt);
404 : if (WOFF_FAILURE(status)) {
405 : FAIL(status);
406 : }
407 : }
408 :
409 : if (woffLen) {
410 : *woffLen = tableOffset;
411 : }
412 : if (pStatus) {
413 : *pStatus |= status;
414 : }
415 : return woffData;
416 :
417 : failure:
418 : if (tableOrder) {
419 : free(tableOrder);
420 : }
421 : if (woffData) {
422 : free(woffData);
423 : }
424 : if (pStatus) {
425 : *pStatus = status;
426 : }
427 : return NULL;
428 : }
429 :
430 : static const uint8_t *
431 : rebuildWoff(const uint8_t * woffData, uint32_t * woffLen,
432 : const uint8_t * metaData, uint32_t metaCompLen, uint32_t metaOrigLen,
433 : const uint8_t * privData, uint32_t privLen, uint32_t * pStatus)
434 : {
435 : const woffHeader * origHeader;
436 : const woffDirEntry * woffDir;
437 : uint8_t * newData = NULL;
438 : uint8_t * tableData = NULL;
439 : woffHeader * newHeader;
440 : uint16_t numTables;
441 : uint32_t tableLimit, totalSize, offset;
442 : uint16_t i;
443 : uint32_t status = eWOFF_ok;
444 :
445 : if (*woffLen < sizeof(woffHeader)) {
446 : FAIL(eWOFF_invalid);
447 : }
448 : origHeader = (const woffHeader *) (woffData);
449 :
450 : if (READ32BE(origHeader->signature) != WOFF_SIGNATURE) {
451 : FAIL(eWOFF_bad_signature);
452 : }
453 :
454 : numTables = READ16BE(origHeader->numTables);
455 : woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader));
456 : tableLimit = 0;
457 : for (i = 0; i < numTables; ++i) {
458 : uint32_t end = READ32BE(woffDir[i].offset) + READ32BE(woffDir[i].compLen);
459 : if (end > tableLimit) {
460 : tableLimit = end;
461 : }
462 : }
463 : tableLimit = LONGALIGN(tableLimit);
464 :
465 : /* check for broken input (meta/priv data before sfnt tables) */
466 : offset = READ32BE(origHeader->metaOffset);
467 : if (offset != 0 && offset < tableLimit) {
468 : FAIL(eWOFF_illegal_order);
469 : }
470 : offset = READ32BE(origHeader->privOffset);
471 : if (offset != 0 && offset < tableLimit) {
472 : FAIL(eWOFF_illegal_order);
473 : }
474 :
475 : totalSize = tableLimit; /* already long-aligned */
476 : if (metaCompLen) {
477 : if (totalSize + metaCompLen < totalSize) {
478 : FAIL(eWOFF_invalid);
479 : }
480 : totalSize += metaCompLen;
481 : }
482 : if (privLen) {
483 : if (LONGALIGN(totalSize) < totalSize) {
484 : FAIL(eWOFF_invalid);
485 : }
486 : totalSize = LONGALIGN(totalSize);
487 : if (totalSize + privLen < totalSize) {
488 : FAIL(eWOFF_invalid);
489 : }
490 : totalSize += privLen;
491 : }
492 : newData = malloc(totalSize);
493 : if (!newData) {
494 : FAIL(eWOFF_out_of_memory);
495 : }
496 :
497 : /* copy the header, directory, and sfnt tables */
498 : memcpy(newData, woffData, tableLimit);
499 :
500 : /* then overwrite the header fields that should be changed */
501 : newHeader = (woffHeader *) newData;
502 : newHeader->length = READ32BE(totalSize);
503 : newHeader->metaOffset = 0;
504 : newHeader->metaCompLen = 0;
505 : newHeader->metaOrigLen = 0;
506 : newHeader->privOffset = 0;
507 : newHeader->privLen = 0;
508 :
509 : offset = tableLimit;
510 : if (metaData && metaCompLen > 0 && metaOrigLen > 0) {
511 : newHeader->metaOffset = READ32BE(offset);
512 : newHeader->metaCompLen = READ32BE(metaCompLen);
513 : newHeader->metaOrigLen = READ32BE(metaOrigLen);
514 : memcpy(newData + offset, metaData, metaCompLen);
515 : offset += metaCompLen;
516 : }
517 :
518 : if (privData && privLen > 0) {
519 : while ((offset & 3) != 0) {
520 : newData[offset++] = 0;
521 : }
522 : newHeader->privOffset = READ32BE(offset);
523 : newHeader->privLen = READ32BE(privLen);
524 : memcpy(newData + offset, privData, privLen);
525 : offset += privLen;
526 : }
527 :
528 : *woffLen = offset;
529 : free((void *) woffData);
530 :
531 : if (pStatus) {
532 : *pStatus |= status;
533 : }
534 : return newData;
535 :
536 : failure:
537 : if (newData) {
538 : free(newData);
539 : }
540 : if (pStatus) {
541 : *pStatus = status;
542 : }
543 : return NULL;
544 : }
545 :
546 : const uint8_t *
547 : woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen,
548 : const uint8_t * metaData, uint32_t metaLen,
549 : uint32_t * pStatus)
550 : {
551 : const woffHeader * header;
552 : uLong compLen = 0;
553 : uint8_t * compData = NULL;
554 : const uint8_t * privData = NULL;
555 : uint32_t privLen = 0;
556 : uint32_t status = eWOFF_ok;
557 :
558 : if (pStatus && WOFF_FAILURE(*pStatus)) {
559 : return NULL;
560 : }
561 :
562 : if (!woffData || !woffLen) {
563 : FAIL(eWOFF_bad_parameter);
564 : }
565 :
566 : if (*woffLen < sizeof(woffHeader)) {
567 : FAIL(eWOFF_invalid);
568 : }
569 : header = (const woffHeader *) (woffData);
570 :
571 : if (READ32BE(header->signature) != WOFF_SIGNATURE) {
572 : FAIL(eWOFF_bad_signature);
573 : }
574 :
575 : if (header->privOffset != 0 && header->privLen != 0) {
576 : privData = woffData + READ32BE(header->privOffset);
577 : privLen = READ32BE(header->privLen);
578 : if (privData + privLen > woffData + *woffLen) {
579 : FAIL(eWOFF_invalid);
580 : }
581 : }
582 :
583 : if (metaData && metaLen > 0) {
584 : compLen = compressBound(metaLen);
585 : compData = malloc(compLen);
586 : if (!compData) {
587 : FAIL(eWOFF_out_of_memory);
588 : }
589 :
590 : if (compress2((Bytef *) compData, &compLen,
591 : (const Bytef *) metaData, metaLen, 9) != Z_OK) {
592 : FAIL(eWOFF_compression_failure);
593 : }
594 : }
595 :
596 : woffData = rebuildWoff(woffData, woffLen,
597 : compData, compLen, metaLen,
598 : privData, privLen, pStatus);
599 : free(compData);
600 : return woffData;
601 :
602 : failure:
603 : if (compData) {
604 : free(compData);
605 : }
606 : if (pStatus) {
607 : *pStatus = status;
608 : }
609 : return NULL;
610 : }
611 :
612 : const uint8_t *
613 : woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen,
614 : const uint8_t * privData, uint32_t privLen,
615 : uint32_t * pStatus)
616 : {
617 : const woffHeader * header;
618 : const uint8_t * metaData = NULL;
619 : uint32_t metaLen = 0;
620 : uint32_t status = eWOFF_ok;
621 :
622 : if (pStatus && WOFF_FAILURE(*pStatus)) {
623 : return NULL;
624 : }
625 :
626 : if (!woffData || !woffLen) {
627 : FAIL(eWOFF_bad_parameter);
628 : }
629 :
630 : if (*woffLen < sizeof(woffHeader)) {
631 : FAIL(eWOFF_invalid);
632 : }
633 : header = (const woffHeader *) (woffData);
634 :
635 : if (READ32BE(header->signature) != WOFF_SIGNATURE) {
636 : FAIL(eWOFF_bad_signature);
637 : }
638 :
639 : if (header->metaOffset != 0 && header->metaCompLen != 0) {
640 : metaData = woffData + READ32BE(header->metaOffset);
641 : metaLen = READ32BE(header->metaCompLen);
642 : if (metaData + metaLen > woffData + *woffLen) {
643 : FAIL(eWOFF_invalid);
644 : }
645 : }
646 :
647 : woffData = rebuildWoff(woffData, woffLen,
648 : metaData, metaLen, READ32BE(header->metaOrigLen),
649 : privData, privLen, pStatus);
650 : return woffData;
651 :
652 : failure:
653 : if (pStatus) {
654 : *pStatus = status;
655 : }
656 : return NULL;
657 : }
658 :
659 : #endif /* WOFF_MOZILLA_CLIENT */
660 :
661 : /******************************************************************/
662 : /* * * * * * * * * * * * * * DECODING * * * * * * * * * * * * * * */
663 : /******************************************************************/
664 :
665 : static uint32_t
666 0 : sanityCheck(const uint8_t * woffData, uint32_t woffLen)
667 : {
668 : const woffHeader * header;
669 : uint16_t numTables, i;
670 : const woffDirEntry * dirEntry;
671 0 : uint64_t tableTotal = 0;
672 :
673 0 : if (!woffData || !woffLen) {
674 0 : return eWOFF_bad_parameter;
675 : }
676 :
677 0 : if (woffLen < sizeof(woffHeader)) {
678 0 : return eWOFF_invalid;
679 : }
680 :
681 0 : header = (const woffHeader *) (woffData);
682 0 : if (READ32BE(header->signature) != WOFF_SIGNATURE) {
683 0 : return eWOFF_bad_signature;
684 : }
685 :
686 0 : if (READ32BE(header->length) != woffLen || header->reserved != 0) {
687 0 : return eWOFF_invalid;
688 : }
689 :
690 0 : numTables = READ16BE(header->numTables);
691 0 : if (woffLen < sizeof(woffHeader) + numTables * sizeof(woffDirEntry)) {
692 0 : return eWOFF_invalid;
693 : }
694 :
695 0 : dirEntry = (const woffDirEntry *) (woffData + sizeof(woffHeader));
696 0 : for (i = 0; i < numTables; ++i) {
697 0 : uint64_t offs = READ32BE(dirEntry->offset);
698 0 : uint64_t orig = READ32BE(dirEntry->origLen);
699 0 : uint64_t comp = READ32BE(dirEntry->compLen);
700 0 : if (comp > orig || comp > woffLen || offs > woffLen - comp) {
701 0 : return eWOFF_invalid;
702 : }
703 0 : orig = (orig + 3) & ~3;
704 0 : tableTotal += orig;
705 0 : if (tableTotal > 0xffffffffU) {
706 0 : return eWOFF_invalid;
707 : }
708 0 : ++dirEntry;
709 : }
710 :
711 0 : if (tableTotal > 0xffffffffU - sizeof(sfntHeader) -
712 0 : numTables * sizeof(sfntDirEntry) ||
713 0 : READ32BE(header->totalSfntSize) !=
714 0 : tableTotal + sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry)) {
715 0 : return eWOFF_invalid;
716 : }
717 :
718 0 : return eWOFF_ok;
719 : }
720 :
721 : uint32_t
722 0 : woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen,
723 : uint32_t * pStatus)
724 : {
725 0 : uint32_t status = eWOFF_ok;
726 0 : uint32_t totalLen = 0;
727 :
728 0 : if (pStatus && WOFF_FAILURE(*pStatus)) {
729 0 : return 0;
730 : }
731 :
732 0 : status = sanityCheck(woffData, woffLen);
733 0 : if (WOFF_FAILURE(status)) {
734 0 : FAIL(status);
735 : }
736 :
737 0 : totalLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize);
738 : /* totalLen must be correctly rounded up to 4-byte alignment, otherwise
739 : sanityCheck would have failed */
740 :
741 : failure:
742 0 : if (pStatus) {
743 0 : *pStatus = status;
744 : }
745 0 : return totalLen;
746 : }
747 :
748 : static void
749 0 : woffDecodeToBufferInternal(const uint8_t * woffData, uint32_t woffLen,
750 : uint8_t * sfntData, uint32_t bufferLen,
751 : uint32_t * pActualSfntLen, uint32_t * pStatus)
752 : {
753 : /* this is only called after sanityCheck has verified that
754 : (a) basic header fields are ok
755 : (b) all the WOFF table offset/length pairs are valid (within the data)
756 : (c) the sum of original sizes + header/directory matches totalSfntSize
757 : so we don't have to re-check those overflow conditions here */
758 0 : tableOrderRec * tableOrder = NULL;
759 : const woffHeader * header;
760 : uint16_t numTables;
761 : uint16_t tableIndex;
762 : uint16_t order;
763 : const woffDirEntry * woffDir;
764 : uint32_t totalLen;
765 : sfntHeader * newHeader;
766 : uint16_t searchRange, rangeShift, entrySelector;
767 : uint32_t offset;
768 : sfntDirEntry * sfntDir;
769 0 : uint32_t headOffset = 0, headLength = 0;
770 : sfntHeadTable * head;
771 0 : uint32_t csum = 0;
772 : const uint32_t * csumPtr;
773 : uint32_t oldCheckSumAdjustment;
774 0 : uint32_t status = eWOFF_ok;
775 :
776 0 : if (pStatus && WOFF_FAILURE(*pStatus)) {
777 0 : return;
778 : }
779 :
780 : /* check basic header fields */
781 0 : header = (const woffHeader *) (woffData);
782 0 : if (READ32BE(header->flavor) != SFNT_VERSION_TT &&
783 0 : READ32BE(header->flavor) != SFNT_VERSION_CFF &&
784 0 : READ32BE(header->flavor) != SFNT_VERSION_true) {
785 0 : status |= eWOFF_warn_unknown_version;
786 : }
787 :
788 0 : numTables = READ16BE(header->numTables);
789 0 : woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader));
790 :
791 0 : totalLen = READ32BE(header->totalSfntSize);
792 :
793 : /* construct the sfnt header */
794 0 : newHeader = (sfntHeader *) (sfntData);
795 0 : newHeader->version = header->flavor;
796 0 : newHeader->numTables = READ16BE(numTables);
797 :
798 : /* calculate header fields for binary search */
799 0 : searchRange = numTables;
800 0 : searchRange |= (searchRange >> 1);
801 0 : searchRange |= (searchRange >> 2);
802 0 : searchRange |= (searchRange >> 4);
803 0 : searchRange |= (searchRange >> 8);
804 0 : searchRange &= ~(searchRange >> 1);
805 0 : searchRange *= 16;
806 0 : newHeader->searchRange = READ16BE(searchRange);
807 0 : rangeShift = numTables * 16 - searchRange;
808 0 : newHeader->rangeShift = READ16BE(rangeShift);
809 0 : entrySelector = 0;
810 0 : while (searchRange > 16) {
811 0 : ++entrySelector;
812 0 : searchRange >>= 1;
813 : }
814 0 : newHeader->entrySelector = READ16BE(entrySelector);
815 :
816 : /* cannot be too big because numTables is 16-bit */
817 0 : tableOrder = (tableOrderRec *) malloc(numTables * sizeof(tableOrderRec));
818 0 : if (!tableOrder) {
819 0 : FAIL(eWOFF_out_of_memory);
820 : }
821 0 : for (tableIndex = 0; tableIndex < numTables; ++tableIndex) {
822 0 : tableOrder[tableIndex].offset = READ32BE(woffDir[tableIndex].offset);
823 0 : tableOrder[tableIndex].oldIndex = tableIndex;
824 : }
825 0 : qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets);
826 :
827 : /* process each table, filling in the sfnt directory */
828 0 : offset = sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry);
829 0 : sfntDir = (sfntDirEntry *) (sfntData + sizeof(sfntHeader));
830 0 : for (order = 0; order < numTables; ++order) {
831 : uint32_t origLen, compLen, tag, sourceOffset;
832 0 : tableIndex = tableOrder[order].oldIndex;
833 :
834 : /* validity of these was confirmed by sanityCheck */
835 0 : origLen = READ32BE(woffDir[tableIndex].origLen);
836 0 : compLen = READ32BE(woffDir[tableIndex].compLen);
837 0 : sourceOffset = READ32BE(woffDir[tableIndex].offset);
838 :
839 0 : sfntDir[tableIndex].tag = woffDir[tableIndex].tag;
840 0 : sfntDir[tableIndex].offset = READ32BE(offset);
841 0 : sfntDir[tableIndex].length = woffDir[tableIndex].origLen;
842 0 : sfntDir[tableIndex].checksum = woffDir[tableIndex].checksum;
843 0 : csum += READ32BE(sfntDir[tableIndex].checksum);
844 :
845 0 : if (compLen < origLen) {
846 0 : uLongf destLen = origLen;
847 0 : if (uncompress((Bytef *)(sfntData + offset), &destLen,
848 : (const Bytef *)(woffData + sourceOffset),
849 0 : compLen) != Z_OK || destLen != origLen) {
850 0 : FAIL(eWOFF_compression_failure);
851 : }
852 : } else {
853 0 : memcpy(sfntData + offset, woffData + sourceOffset, origLen);
854 : }
855 :
856 : /* note that old Mac bitmap-only fonts have no 'head' table
857 : (eg NISC18030.ttf) but a 'bhed' table instead */
858 0 : tag = READ32BE(sfntDir[tableIndex].tag);
859 0 : if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) {
860 0 : headOffset = offset;
861 0 : headLength = origLen;
862 : }
863 :
864 0 : offset += origLen;
865 :
866 0 : while (offset < totalLen && (offset & 3) != 0) {
867 0 : sfntData[offset++] = 0;
868 : }
869 : }
870 :
871 0 : if (headOffset > 0) {
872 : /* the font checksum in the 'head' table depends on all the individual
873 : table checksums (collected above), plus the header and directory
874 : which are added in here */
875 0 : if (headLength < HEAD_TABLE_SIZE) {
876 0 : FAIL(eWOFF_invalid);
877 : }
878 0 : head = (sfntHeadTable *)(sfntData + headOffset);
879 0 : oldCheckSumAdjustment = READ32BE(head->checkSumAdjustment);
880 0 : head->checkSumAdjustment = 0;
881 0 : csumPtr = (const uint32_t *)sfntData;
882 0 : while (csumPtr < (const uint32_t *)(sfntData + sizeof(sfntHeader) +
883 0 : numTables * sizeof(sfntDirEntry))) {
884 0 : csum += READ32BE(*csumPtr);
885 0 : csumPtr++;
886 : }
887 0 : csum = SFNT_CHECKSUM_CALC_CONST - csum;
888 :
889 0 : if (oldCheckSumAdjustment != csum) {
890 : /* if the checksum doesn't match, we fix it; but this will invalidate
891 : any DSIG that may be present */
892 0 : status |= eWOFF_warn_checksum_mismatch;
893 : }
894 0 : head->checkSumAdjustment = READ32BE(csum);
895 : }
896 :
897 0 : if (pActualSfntLen) {
898 0 : *pActualSfntLen = totalLen;
899 : }
900 0 : if (pStatus) {
901 0 : *pStatus |= status;
902 : }
903 0 : free(tableOrder);
904 0 : return;
905 :
906 : failure:
907 0 : if (tableOrder) {
908 0 : free(tableOrder);
909 : }
910 0 : if (pActualSfntLen) {
911 0 : *pActualSfntLen = 0;
912 : }
913 0 : if (pStatus) {
914 0 : *pStatus = status;
915 : }
916 : }
917 :
918 : void
919 0 : woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen,
920 : uint8_t * sfntData, uint32_t bufferLen,
921 : uint32_t * pActualSfntLen, uint32_t * pStatus)
922 : {
923 0 : uint32_t status = eWOFF_ok;
924 : uint32_t totalLen;
925 :
926 0 : if (pStatus && WOFF_FAILURE(*pStatus)) {
927 0 : return;
928 : }
929 :
930 0 : status = sanityCheck(woffData, woffLen);
931 0 : if (WOFF_FAILURE(status)) {
932 0 : FAIL(status);
933 : }
934 :
935 0 : if (!sfntData) {
936 0 : FAIL(eWOFF_bad_parameter);
937 : }
938 :
939 0 : totalLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize);
940 0 : if (bufferLen < totalLen) {
941 0 : FAIL(eWOFF_buffer_too_small);
942 : }
943 :
944 0 : woffDecodeToBufferInternal(woffData, woffLen, sfntData, bufferLen,
945 : pActualSfntLen, pStatus);
946 0 : return;
947 :
948 : failure:
949 0 : if (pActualSfntLen) {
950 0 : *pActualSfntLen = 0;
951 : }
952 0 : if (pStatus) {
953 0 : *pStatus = status;
954 : }
955 : }
956 :
957 : const uint8_t *
958 0 : woffDecode(const uint8_t * woffData, uint32_t woffLen,
959 : uint32_t * sfntLen, uint32_t * pStatus)
960 : {
961 0 : uint32_t status = eWOFF_ok;
962 0 : uint8_t * sfntData = NULL;
963 : uint32_t bufLen;
964 :
965 0 : if (pStatus && WOFF_FAILURE(*pStatus)) {
966 0 : return NULL;
967 : }
968 :
969 0 : status = sanityCheck(woffData, woffLen);
970 0 : if (WOFF_FAILURE(status)) {
971 0 : FAIL(status);
972 : }
973 :
974 0 : bufLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize);
975 0 : sfntData = (uint8_t *) malloc(bufLen);
976 0 : if (!sfntData) {
977 0 : FAIL(eWOFF_out_of_memory);
978 : }
979 :
980 0 : woffDecodeToBufferInternal(woffData, woffLen, sfntData, bufLen,
981 : sfntLen, &status);
982 0 : if (WOFF_FAILURE(status)) {
983 0 : FAIL(status);
984 : }
985 :
986 0 : if (pStatus) {
987 0 : *pStatus |= status;
988 : }
989 0 : return sfntData;
990 :
991 : failure:
992 0 : if (sfntData) {
993 0 : free(sfntData);
994 : }
995 0 : if (pStatus) {
996 0 : *pStatus = status;
997 : }
998 0 : return NULL;
999 : }
1000 :
1001 : /* functions to get size and data of a single table */
1002 :
1003 0 : uint32_t woffGetTableSize(const uint8_t * woffData, uint32_t woffLen,
1004 : uint32_t tag, uint32_t * pStatus)
1005 : {
1006 0 : uint32_t status = eWOFF_ok;
1007 : const woffHeader * header;
1008 : uint16_t numTables;
1009 : uint16_t tableIndex;
1010 : const woffDirEntry * woffDir;
1011 :
1012 0 : if (pStatus && WOFF_FAILURE(*pStatus)) {
1013 0 : return 0;
1014 : }
1015 :
1016 0 : status = sanityCheck(woffData, woffLen);
1017 0 : if (WOFF_FAILURE(status)) {
1018 0 : FAIL(status);
1019 : }
1020 :
1021 0 : header = (const woffHeader *) (woffData);
1022 :
1023 0 : numTables = READ16BE(header->numTables);
1024 0 : woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader));
1025 :
1026 0 : for (tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1027 : uint32_t thisTag;
1028 0 : thisTag = READ32BE(woffDir[tableIndex].tag);
1029 0 : if (thisTag < tag) {
1030 0 : continue;
1031 : }
1032 0 : if (thisTag > tag) {
1033 0 : break;
1034 : }
1035 0 : return READ32BE(woffDir[tableIndex].origLen);
1036 : }
1037 :
1038 0 : status = eWOFF_warn_no_such_table;
1039 :
1040 : failure:
1041 0 : if (pStatus) {
1042 0 : *pStatus = status;
1043 : }
1044 0 : return 0;
1045 : }
1046 :
1047 0 : void woffGetTableToBuffer(const uint8_t * woffData, uint32_t woffLen,
1048 : uint32_t tag, uint8_t * buffer, uint32_t bufferLen,
1049 : uint32_t * pTableLen, uint32_t * pStatus)
1050 : {
1051 0 : uint32_t status = eWOFF_ok;
1052 : const woffHeader * header;
1053 : uint16_t numTables;
1054 : uint16_t tableIndex;
1055 : const woffDirEntry * woffDir;
1056 :
1057 0 : if (pStatus && WOFF_FAILURE(*pStatus)) {
1058 0 : return;
1059 : }
1060 :
1061 0 : status = sanityCheck(woffData, woffLen);
1062 0 : if (WOFF_FAILURE(status)) {
1063 0 : FAIL(status);
1064 : }
1065 :
1066 0 : header = (const woffHeader *) (woffData);
1067 :
1068 0 : numTables = READ16BE(header->numTables);
1069 0 : woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader));
1070 :
1071 0 : for (tableIndex = 0; tableIndex < numTables; ++tableIndex) {
1072 : uint32_t thisTag, origLen, compLen, sourceOffset;
1073 0 : thisTag = READ32BE(woffDir[tableIndex].tag);
1074 0 : if (thisTag < tag) {
1075 0 : continue;
1076 : }
1077 0 : if (thisTag > tag) {
1078 0 : break;
1079 : }
1080 :
1081 : /* found the required table: decompress it (checking for overflow) */
1082 0 : origLen = READ32BE(woffDir[tableIndex].origLen);
1083 0 : if (origLen > bufferLen) {
1084 0 : FAIL(eWOFF_buffer_too_small);
1085 : }
1086 :
1087 0 : compLen = READ32BE(woffDir[tableIndex].compLen);
1088 0 : sourceOffset = READ32BE(woffDir[tableIndex].offset);
1089 :
1090 0 : if (compLen < origLen) {
1091 0 : uLongf destLen = origLen;
1092 0 : if (uncompress((Bytef *)(buffer), &destLen,
1093 : (const Bytef *)(woffData + sourceOffset),
1094 0 : compLen) != Z_OK || destLen != origLen) {
1095 0 : FAIL(eWOFF_compression_failure);
1096 : }
1097 : } else {
1098 0 : memcpy(buffer, woffData + sourceOffset, origLen);
1099 : }
1100 :
1101 0 : if (pTableLen) {
1102 0 : *pTableLen = origLen;
1103 : }
1104 :
1105 0 : return;
1106 : }
1107 :
1108 0 : status = eWOFF_warn_no_such_table;
1109 :
1110 : failure:
1111 0 : if (pStatus) {
1112 0 : *pStatus = status;
1113 : }
1114 : }
1115 :
1116 :
1117 : #ifndef WOFF_MOZILLA_CLIENT
1118 :
1119 : const uint8_t *
1120 : woffGetMetadata(const uint8_t * woffData, uint32_t woffLen,
1121 : uint32_t * metaLen, uint32_t * pStatus)
1122 : {
1123 : const woffHeader * header;
1124 : uint32_t offset, compLen;
1125 : uLong origLen;
1126 : uint8_t * data = NULL;
1127 : uint32_t status = eWOFF_ok;
1128 :
1129 : if (pStatus && WOFF_FAILURE(*pStatus)) {
1130 : return NULL;
1131 : }
1132 :
1133 : status = sanityCheck(woffData, woffLen);
1134 : if (WOFF_FAILURE(status)) {
1135 : FAIL(status);
1136 : }
1137 :
1138 : header = (const woffHeader *) (woffData);
1139 :
1140 : offset = READ32BE(header->metaOffset);
1141 : compLen = READ32BE(header->metaCompLen);
1142 : origLen = READ32BE(header->metaOrigLen);
1143 : if (offset == 0 || compLen == 0 || origLen == 0) {
1144 : return NULL;
1145 : }
1146 :
1147 : if (compLen > woffLen || offset > woffLen - compLen) {
1148 : FAIL(eWOFF_invalid);
1149 : }
1150 :
1151 : data = malloc(origLen);
1152 : if (!data) {
1153 : FAIL(eWOFF_out_of_memory);
1154 : }
1155 :
1156 : if (uncompress((Bytef *)data, &origLen,
1157 : (const Bytef *)woffData + offset, compLen) != Z_OK ||
1158 : origLen != READ32BE(header->metaOrigLen)) {
1159 : FAIL(eWOFF_compression_failure);
1160 : }
1161 :
1162 : if (metaLen) {
1163 : *metaLen = origLen;
1164 : }
1165 : if (pStatus) {
1166 : *pStatus |= status;
1167 : }
1168 : return data;
1169 :
1170 : failure:
1171 : if (data) {
1172 : free(data);
1173 : }
1174 : if (pStatus) {
1175 : *pStatus = status;
1176 : }
1177 : return NULL;
1178 : }
1179 :
1180 : const uint8_t *
1181 : woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen,
1182 : uint32_t * privLen, uint32_t * pStatus)
1183 : {
1184 : const woffHeader * header;
1185 : uint32_t offset, length;
1186 : uint8_t * data = NULL;
1187 : uint32_t status = eWOFF_ok;
1188 :
1189 : if (pStatus && WOFF_FAILURE(*pStatus)) {
1190 : return NULL;
1191 : }
1192 :
1193 : status = sanityCheck(woffData, woffLen);
1194 : if (WOFF_FAILURE(status)) {
1195 : FAIL(status);
1196 : }
1197 :
1198 : header = (const woffHeader *) (woffData);
1199 :
1200 : offset = READ32BE(header->privOffset);
1201 : length = READ32BE(header->privLen);
1202 : if (offset == 0 || length == 0) {
1203 : return NULL;
1204 : }
1205 :
1206 : if (length > woffLen || offset > woffLen - length) {
1207 : FAIL(eWOFF_invalid);
1208 : }
1209 :
1210 : data = malloc(length);
1211 : if (!data) {
1212 : FAIL(eWOFF_out_of_memory);
1213 : }
1214 :
1215 : memcpy(data, woffData + offset, length);
1216 :
1217 : if (privLen) {
1218 : *privLen = length;
1219 : }
1220 : if (pStatus) {
1221 : *pStatus |= status;
1222 : }
1223 : return data;
1224 :
1225 : failure:
1226 : if (data) {
1227 : free(data);
1228 : }
1229 : if (pStatus) {
1230 : *pStatus = status;
1231 : }
1232 : return NULL;
1233 : }
1234 :
1235 : void
1236 : woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen,
1237 : uint16_t * major, uint16_t * minor, uint32_t * pStatus)
1238 : {
1239 : const woffHeader * header;
1240 : uint32_t status = eWOFF_ok;
1241 :
1242 : if (pStatus && WOFF_FAILURE(*pStatus)) {
1243 : return;
1244 : }
1245 :
1246 : status = sanityCheck(woffData, woffLen);
1247 : if (WOFF_FAILURE(status)) {
1248 : FAIL(status);
1249 : }
1250 :
1251 : if (!major || !minor) {
1252 : FAIL(eWOFF_bad_parameter);
1253 : }
1254 :
1255 : *major = *minor = 0;
1256 :
1257 : header = (const woffHeader *) (woffData);
1258 :
1259 : *major = READ16BE(header->majorVersion);
1260 : *minor = READ16BE(header->minorVersion);
1261 :
1262 : failure:
1263 : if (pStatus) {
1264 : *pStatus = status;
1265 : }
1266 : }
1267 :
1268 : /* utility to print messages corresponding to WOFF encoder/decoder errors */
1269 : void
1270 : woffPrintStatus(FILE * f, uint32_t status, const char * prefix)
1271 : {
1272 : if (!prefix) {
1273 : prefix = "";
1274 : }
1275 : if (WOFF_WARNING(status)) {
1276 : const char * template = "%sWOFF warning: %s\n";
1277 : if (status & eWOFF_warn_unknown_version) {
1278 : fprintf(f, template, prefix, "unrecognized sfnt version");
1279 : }
1280 : if (status & eWOFF_warn_checksum_mismatch) {
1281 : fprintf(f, template, prefix, "checksum mismatch (corrected)");
1282 : }
1283 : if (status & eWOFF_warn_misaligned_table) {
1284 : fprintf(f, template, prefix, "misaligned font table");
1285 : }
1286 : if (status & eWOFF_warn_trailing_data) {
1287 : fprintf(f, template, prefix, "extraneous input data discarded");
1288 : }
1289 : if (status & eWOFF_warn_unpadded_table) {
1290 : fprintf(f, template, prefix, "final table not correctly padded");
1291 : }
1292 : if (status & eWOFF_warn_removed_DSIG) {
1293 : fprintf(f, template, prefix, "digital signature (DSIG) table removed");
1294 : }
1295 : }
1296 : if (WOFF_FAILURE(status)) {
1297 : const char * template = "%sWOFF error: %s\n";
1298 : const char * msg;
1299 : switch (status & 0xff) {
1300 : case eWOFF_out_of_memory:
1301 : msg = "memory allocation failure";
1302 : break;
1303 : case eWOFF_invalid:
1304 : msg = "invalid input font";
1305 : break;
1306 : case eWOFF_compression_failure:
1307 : msg = "zlib compression/decompression failure";
1308 : break;
1309 : case eWOFF_bad_signature:
1310 : msg = "incorrect WOFF file signature";
1311 : break;
1312 : case eWOFF_buffer_too_small:
1313 : msg = "buffer too small";
1314 : break;
1315 : case eWOFF_bad_parameter:
1316 : msg = "bad parameter to WOFF function";
1317 : break;
1318 : case eWOFF_illegal_order:
1319 : msg = "incorrect table directory order";
1320 : break;
1321 : default:
1322 : msg = "unknown internal error";
1323 : break;
1324 : }
1325 : fprintf(f, template, prefix, msg);
1326 : }
1327 : }
1328 :
1329 : #endif /* not WOFF_MOZILLA_CLIENT */
|