woff-tools-2009.10.04/0000775000000000000000000000000012145203653012707 5ustar rootrootwoff-tools-2009.10.04/woff2sfnt.c0000666000000000000000000001346611251762220015002 0ustar rootroot/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is WOFF font packaging code. * * The Initial Developer of the Original Code is Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jonathan Kew * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #ifdef WIN32 #include #endif #include "woff.h" static void die(const char * msg) { fprintf(stderr, "# fatal error: %s\n", msg); exit(2); } static void reportErr(uint32_t status) { woffPrintStatus(stderr, status, "### "); exit(status & 0xff); } static void usage(const char * progName) { fprintf(stderr, "Usage:\n" " %s [-v | -m | -p] \n" " decode WOFF file , writing OpenType data to stdout\n" "Options (instead of decoding to OpenType format)\n" " -v write font version to stdout\n" " -m write WOFF metadata block to stdout\n" " -p write private data block to stdout\n" "Note: only one of -v, -m, -p may be used at a time.\n" , progName); } const uint8_t * readFile(const char * name, uint32_t * len) { FILE * inFile = fopen(name, "rb"); if (!inFile) { char buf[200]; sprintf(buf, "unable to open file %s", name); die(buf); } if (fseek(inFile, 0, SEEK_END) != 0) die("seek failure"); *len = ftell(inFile); if (fseek(inFile, 0, SEEK_SET) != 0) die("seek failure"); uint8_t * data = (uint8_t *) malloc(*len); if (!data) die("malloc failure"); if (fread(data, 1, *len, inFile) != *len) die("file read failure"); fclose(inFile); return data; } int main(int argc, char *argv[]) { const char * progName = argv[0]; uint32_t status = eWOFF_ok; int opt; int option = 0; while ((opt = getopt(argc, argv, "vmph")) != -1) { switch (opt) { case 'v': if (option) fprintf(stderr, "# ignoring option '%c', already got '%c'\n", opt, option); else option = 'v'; break; case 'm': if (option) fprintf(stderr, "# ignoring option '%c', already got '%c'\n", opt, option); else option = 'm'; break; case 'p': if (option) fprintf(stderr, "# ignoring option '%c', already got '%c'\n", opt, option); else option = 'p'; break; case 'h': case '?': usage(progName); exit(0); default: fprintf(stderr, "# unknown option '%c'\n", opt); break; } } argc -= optind; argv += optind; if (argc != 1) { usage(progName); exit(1); } uint32_t woffLen; const uint8_t * woffData = readFile(argv[0], &woffLen); uint32_t len; const uint8_t * data; switch (option) { case 'v': { uint16_t maj, min; woffGetFontVersion(woffData, woffLen, &maj, &min, &status); if (WOFF_FAILURE(status)) { reportErr(status); } printf("%u.%u\n", maj, min); } break; case 'm': { data = woffGetMetadata(woffData, woffLen, &len, &status); if (WOFF_FAILURE(status)) { reportErr(status); } if (data) { if (fwrite(data, 1, len, stdout) != len) die("error writing metadata to output"); free((void *) data); } else { printf("\n"); } } break; case 'p': { data = woffGetPrivateData(woffData, woffLen, &len, &status); if (WOFF_FAILURE(status)) { reportErr(status); } if (data) { #ifdef WIN32 setmode(fileno(stdout), O_BINARY); #endif if (fwrite(data, 1, len, stdout) != len) die("error writing private data to output"); free((void *) data); } } break; default: { data = woffDecode(woffData, woffLen, &len, &status); if (WOFF_FAILURE(status)) { reportErr(status); } if (data) { #ifdef WIN32 setmode(fileno(stdout), O_BINARY); #endif if (fwrite(data, 1, len, stdout) != len) die("error writing sfnt data to output"); free((void *) data); } else { die("unable to decode WOFF data"); } } break; } if (WOFF_WARNING(status)) { woffPrintStatus(stderr, status, "### "); } free((void *) woffData); return 0; } woff-tools-2009.10.04/woff.c0000666000000000000000000010260511257145605014027 0ustar rootroot/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is WOFF font packaging code. * * The Initial Developer of the Original Code is Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jonathan Kew * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "woff-private.h" #include #include #include #include #ifdef WOFF_MOZILLA_CLIENT /* define this when building as part of Gecko */ # include "prmem.h" # define malloc PR_Malloc # define realloc PR_Realloc # define free PR_Free #endif /* * Just simple whole-file encoding and decoding functions; a more extensive * WOFF library could provide support for accessing individual tables from a * compressed font, alternative options for memory allocation/ownership and * error handling, etc. */ /* on errors, each function sets a status variable and jumps to failure: */ #undef FAIL #define FAIL(err) do { status |= err; goto failure; } while (0) /* adjust an offset for longword alignment */ #define LONGALIGN(x) (((x) + 3) & ~3) static int compareOffsets(const void * lhs, const void * rhs) { const tableOrderRec * a = (const tableOrderRec *) lhs; const tableOrderRec * b = (const tableOrderRec *) rhs; /* don't simply return a->offset - b->offset because these are unsigned offset values; could convert to int, but possible integer overflow */ return a->offset > b->offset ? 1 : a->offset < b->offset ? -1 : 0; } #ifndef WOFF_MOZILLA_CLIENT /******************************************************************/ /* * * * * * * * * * * * * * ENCODING * * * * * * * * * * * * * * */ /******************************************************************/ static uint32_t calcChecksum(const sfntDirEntry * dirEntry, const uint8_t * sfntData, uint32_t sfntLen) { /* just returns zero on errors, they will be detected again elsewhere */ const uint32_t * csumPtr; const uint32_t * csumEnd; uint32_t csum = 0; uint32_t length = LONGALIGN(READ32BE(dirEntry->length)); uint32_t offset = READ32BE(dirEntry->offset); uint32_t tag; if ((offset & 3) != 0) { return csum; } if (length > sfntLen || offset > sfntLen - length) { return csum; } csumPtr = (const uint32_t *) (sfntData + offset); csumEnd = csumPtr + length / 4; while (csumPtr < csumEnd) { csum += READ32BE(*csumPtr); csumPtr++; } tag = READ32BE(dirEntry->tag); if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) { const sfntHeadTable * head; if (length < HEAD_TABLE_SIZE) { return 0; } head = (const sfntHeadTable *)(sfntData + offset); csum -= READ32BE(head->checkSumAdjustment); } return csum; } const uint8_t * woffEncode(const uint8_t * sfntData, uint32_t sfntLen, uint16_t majorVersion, uint16_t minorVersion, uint32_t * woffLen, uint32_t * pStatus) { uint8_t * woffData = NULL; tableOrderRec * tableOrder = NULL; uint32_t tableOffset; uint32_t totalSfntSize; uint16_t numOrigTables; uint16_t numTables; uint16_t tableIndex; uint16_t order; const sfntDirEntry * sfntDir; uint32_t tableBase; uint32_t checkSumAdjustment = 0; woffHeader * newHeader; uint32_t tag = 0; uint32_t removedDsigSize = 0; uint32_t status = eWOFF_ok; const sfntHeader * header = (const sfntHeader *) (sfntData); const sfntHeadTable * head = NULL; if (pStatus && WOFF_FAILURE(*pStatus)) { return NULL; } if (READ32BE(header->version) != SFNT_VERSION_TT && READ32BE(header->version) != SFNT_VERSION_CFF && READ32BE(header->version) != SFNT_VERSION_true) { status |= eWOFF_warn_unknown_version; } numOrigTables = READ16BE(header->numTables); sfntDir = (const sfntDirEntry *) (sfntData + sizeof(sfntHeader)); for (tableIndex = 0; tableIndex < numOrigTables; ++tableIndex) { /* validate table checksums, to figure out if we need to drop DSIG; also check that table directory is correctly sorted */ uint32_t prevTag = tag; uint32_t csum = calcChecksum(&sfntDir[tableIndex], sfntData, sfntLen); if (csum != READ32BE(sfntDir[tableIndex].checksum)) { status |= eWOFF_warn_checksum_mismatch; } checkSumAdjustment += csum; tag = READ32BE(sfntDir[tableIndex].tag); if (tag <= prevTag) { FAIL(eWOFF_invalid); } if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) { if (READ32BE(sfntDir[tableIndex].length) < HEAD_TABLE_SIZE) { FAIL(eWOFF_invalid); } head = (const sfntHeadTable *)(sfntData + READ32BE(sfntDir[tableIndex].offset)); } } if (!head) { FAIL(eWOFF_invalid); } if ((status & eWOFF_warn_checksum_mismatch) == 0) { /* no point even checking if we already have an error, as fixing that will change the overall checksum too */ const uint32_t * csumPtr = (const uint32_t *) sfntData; const uint32_t * csumEnd = csumPtr + 3 + 4 * numOrigTables; while (csumPtr < csumEnd) { checkSumAdjustment += READ32BE(*csumPtr); ++csumPtr; } checkSumAdjustment = 0xB1B0AFBA - checkSumAdjustment; if (checkSumAdjustment != READ32BE(head->checkSumAdjustment)) { status |= eWOFF_warn_checksum_mismatch; } } /* Fixing checkSumAdjustment is tricky, because if there's a DSIG table, we're going to have to remove that, which in turn means that table offsets in the directory will all change. And recalculating checkSumAdjustment requires taking account of any individual table checksum corrections, but they have not actually been applied to the sfnt data at this point. And finally, we'd need to get the corrected checkSumAdjustment into the encoded head table (but we can't modify the original sfnt data). An easier way out seems to be to go ahead and encode the font, knowing that checkSumAdjustment will be wrong; then (if the status flag eWOFF_warn_checksum_mismatch is set) we'll decode the font back to sfnt format. This will fix up the checkSumAdjustment (and return a warning status). We'll ignore that warning, and then re-encode the new, cleaned-up sfnt to get the final WOFF data. Perhaps not the most efficient approach, but it seems simpler than trying to predict the correct final checkSumAdjustment and incorporate it into the head table on the fly. */ tableOrder = (tableOrderRec *) malloc(numOrigTables * sizeof(tableOrderRec)); if (!tableOrder) { FAIL(eWOFF_out_of_memory); } for (tableIndex = 0, numTables = 0; tableIndex < numOrigTables; ++tableIndex) { if ((status & eWOFF_warn_checksum_mismatch) != 0) { /* check for DSIG table that we must drop if we're fixing checksums */ tag = READ32BE(sfntDir[tableIndex].tag); if (tag == TABLE_TAG_DSIG) { status |= eWOFF_warn_removed_DSIG; removedDsigSize = READ32BE(sfntDir[tableIndex].length); continue; } } tableOrder[numTables].offset = READ32BE(sfntDir[tableIndex].offset); tableOrder[numTables].oldIndex = tableIndex; tableOrder[numTables].newIndex = numTables; ++numTables; } qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets); /* initially, allocate space for header and directory */ tableOffset = sizeof(woffHeader) + numTables * sizeof(woffDirEntry); woffData = (uint8_t *) malloc(tableOffset); if (!woffData) { FAIL(eWOFF_out_of_memory); } /* accumulator for total expected size of decoded font */ totalSfntSize = sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry); /* * We use a macro for this rather than creating a variable because woffData * will get reallocated during encoding. The macro avoids the risk of using a * stale pointer, and the compiler should optimize multiple successive uses. */ #define WOFFDIR ((woffDirEntry *) (woffData + sizeof(woffHeader))) for (order = 0; order < numTables; ++order) { uLong sourceLen, destLen; uint32_t sourceOffset; uint16_t oldIndex = tableOrder[order].oldIndex; uint16_t newIndex = tableOrder[order].newIndex; WOFFDIR[newIndex].tag = sfntDir[oldIndex].tag; if ((status & eWOFF_warn_checksum_mismatch) != 0) { uint32_t csum = calcChecksum(&sfntDir[oldIndex], sfntData, sfntLen); WOFFDIR[newIndex].checksum = READ32BE(csum); } else { WOFFDIR[newIndex].checksum = sfntDir[oldIndex].checksum; } WOFFDIR[newIndex].origLen = sfntDir[oldIndex].length; WOFFDIR[newIndex].offset = READ32BE(tableOffset); /* allocate enough space for upper bound of compressed size */ sourceOffset = READ32BE(sfntDir[oldIndex].offset); if ((sourceOffset & 3) != 0) { status |= eWOFF_warn_misaligned_table; } sourceLen = READ32BE(sfntDir[oldIndex].length); if (sourceLen > sfntLen || sourceOffset > sfntLen - sourceLen) { FAIL(eWOFF_invalid); } destLen = LONGALIGN(compressBound(sourceLen)); woffData = (uint8_t *) realloc(woffData, tableOffset + destLen); if (!woffData) { FAIL(eWOFF_out_of_memory); } /* do the compression directly into the WOFF data block */ if (compress2((Bytef *) (woffData + tableOffset), &destLen, (const Bytef *) (sfntData + sourceOffset), sourceLen, 9) != Z_OK) { FAIL(eWOFF_compression_failure); } if (destLen < sourceLen) { /* compressed table was smaller */ tableOffset += destLen; WOFFDIR[newIndex].compLen = READ32BE(destLen); } else { /* compression didn't make it smaller, so store original data instead */ destLen = sourceLen; /* reallocate to ensure enough space for the table, plus potential padding after it */ woffData = (uint8_t *) realloc(woffData, tableOffset + LONGALIGN(sourceLen)); if (!woffData) { FAIL(eWOFF_out_of_memory); } /* copy the original data into place */ memcpy(woffData + tableOffset, sfntData + READ32BE(sfntDir[oldIndex].offset), sourceLen); tableOffset += sourceLen; WOFFDIR[newIndex].compLen = WOFFDIR[newIndex].origLen; } /* we always realloc woffData to a long-aligned size, so this is safe */ while ((tableOffset & 3) != 0) { woffData[tableOffset++] = 0; } /* update total size of uncompressed OpenType with table size */ totalSfntSize += sourceLen; totalSfntSize = LONGALIGN(totalSfntSize); } if (totalSfntSize > sfntLen) { if (totalSfntSize > LONGALIGN(sfntLen)) { FAIL(eWOFF_invalid); } else { status |= eWOFF_warn_unpadded_table; } } else if (totalSfntSize < sfntLen) { /* check if the remaining data is a DSIG we're removing; if so, we're already warning about that */ if ((status & eWOFF_warn_removed_DSIG) != 0 || sfntLen - totalSfntSize > LONGALIGN(removedDsigSize) + sizeof(sfntDirEntry)) { status |= eWOFF_warn_trailing_data; } } /* write the header */ newHeader = (woffHeader *) (woffData); newHeader->signature = WOFF_SIGNATURE; newHeader->signature = READ32BE(newHeader->signature); newHeader->flavor = header->version; newHeader->length = READ32BE(tableOffset); newHeader->numTables = READ16BE(numTables); newHeader->reserved = 0; newHeader->totalSfntSize = READ32BE(totalSfntSize); newHeader->majorVersion = READ16BE(majorVersion); newHeader->minorVersion = READ16BE(minorVersion); newHeader->metaOffset = 0; newHeader->metaCompLen = 0; newHeader->metaOrigLen = 0; newHeader->privOffset = 0; newHeader->privLen = 0; free(tableOrder); if ((status & eWOFF_warn_checksum_mismatch) != 0) { /* The original font had checksum errors, so we now decode our WOFF data back to sfnt format (which fixes checkSumAdjustment), then re-encode to get a clean copy. */ const uint8_t * cleanSfnt = woffDecode(woffData, tableOffset, &sfntLen, &status); if (WOFF_FAILURE(status)) { FAIL(status); } free(woffData); woffData = (uint8_t *) woffEncode(cleanSfnt, sfntLen, majorVersion, minorVersion, &tableOffset, &status); free((void *) cleanSfnt); if (WOFF_FAILURE(status)) { FAIL(status); } } if (woffLen) { *woffLen = tableOffset; } if (pStatus) { *pStatus |= status; } return woffData; failure: if (tableOrder) { free(tableOrder); } if (woffData) { free(woffData); } if (pStatus) { *pStatus = status; } return NULL; } static const uint8_t * rebuildWoff(const uint8_t * woffData, uint32_t * woffLen, const uint8_t * metaData, uint32_t metaCompLen, uint32_t metaOrigLen, const uint8_t * privData, uint32_t privLen, uint32_t * pStatus) { const woffHeader * origHeader; const woffDirEntry * woffDir; uint8_t * newData = NULL; uint8_t * tableData = NULL; woffHeader * newHeader; uint16_t numTables; uint32_t tableLimit, totalSize, offset; uint16_t i; uint32_t status = eWOFF_ok; if (*woffLen < sizeof(woffHeader)) { FAIL(eWOFF_invalid); } origHeader = (const woffHeader *) (woffData); if (READ32BE(origHeader->signature) != WOFF_SIGNATURE) { FAIL(eWOFF_bad_signature); } numTables = READ16BE(origHeader->numTables); woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader)); tableLimit = 0; for (i = 0; i < numTables; ++i) { uint32_t end = READ32BE(woffDir[i].offset) + READ32BE(woffDir[i].compLen); if (end > tableLimit) { tableLimit = end; } } tableLimit = LONGALIGN(tableLimit); /* check for broken input (meta/priv data before sfnt tables) */ offset = READ32BE(origHeader->metaOffset); if (offset != 0 && offset < tableLimit) { FAIL(eWOFF_illegal_order); } offset = READ32BE(origHeader->privOffset); if (offset != 0 && offset < tableLimit) { FAIL(eWOFF_illegal_order); } totalSize = tableLimit; /* already long-aligned */ if (metaCompLen) { totalSize += metaCompLen; } if (privLen) { totalSize = LONGALIGN(totalSize) + privLen; } newData = malloc(totalSize); if (!newData) { FAIL(eWOFF_out_of_memory); } /* copy the header, directory, and sfnt tables */ memcpy(newData, woffData, tableLimit); /* then overwrite the header fields that should be changed */ newHeader = (woffHeader *) newData; newHeader->length = READ32BE(totalSize); newHeader->metaOffset = 0; newHeader->metaCompLen = 0; newHeader->metaOrigLen = 0; newHeader->privOffset = 0; newHeader->privLen = 0; offset = tableLimit; if (metaData && metaCompLen > 0 && metaOrigLen > 0) { newHeader->metaOffset = READ32BE(offset); newHeader->metaCompLen = READ32BE(metaCompLen); newHeader->metaOrigLen = READ32BE(metaOrigLen); memcpy(newData + offset, metaData, metaCompLen); offset += metaCompLen; } if (privData && privLen > 0) { while ((offset & 3) != 0) { newData[offset++] = 0; } newHeader->privOffset = READ32BE(offset); newHeader->privLen = READ32BE(privLen); memcpy(newData + offset, privData, privLen); offset += privLen; } *woffLen = offset; free((void *) woffData); if (pStatus) { *pStatus |= status; } return newData; failure: if (newData) { free(newData); } if (pStatus) { *pStatus = status; } return NULL; } const uint8_t * woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen, const uint8_t * metaData, uint32_t metaLen, uint32_t * pStatus) { const woffHeader * header; uLong compLen = 0; uint8_t * compData = NULL; const uint8_t * privData = NULL; uint32_t privLen = 0; uint32_t status = eWOFF_ok; if (pStatus && WOFF_FAILURE(*pStatus)) { return NULL; } if (!woffData || !woffLen) { FAIL(eWOFF_bad_parameter); } if (*woffLen < sizeof(woffHeader)) { FAIL(eWOFF_invalid); } header = (const woffHeader *) (woffData); if (READ32BE(header->signature) != WOFF_SIGNATURE) { FAIL(eWOFF_bad_signature); } if (header->privOffset != 0 && header->privLen != 0) { privData = woffData + READ32BE(header->privOffset); privLen = READ32BE(header->privLen); if (privData + privLen > woffData + *woffLen) { FAIL(eWOFF_invalid); } } if (metaData && metaLen > 0) { compLen = compressBound(metaLen); compData = malloc(compLen); if (!compData) { FAIL(eWOFF_out_of_memory); } if (compress2((Bytef *) compData, &compLen, (const Bytef *) metaData, metaLen, 9) != Z_OK) { FAIL(eWOFF_compression_failure); } } woffData = rebuildWoff(woffData, woffLen, compData, compLen, metaLen, privData, privLen, pStatus); free(compData); return woffData; failure: if (compData) { free(compData); } if (pStatus) { *pStatus = status; } return NULL; } const uint8_t * woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen, const uint8_t * privData, uint32_t privLen, uint32_t * pStatus) { const woffHeader * header; const uint8_t * metaData = NULL; uint32_t metaLen = 0; uint32_t status = eWOFF_ok; if (pStatus && WOFF_FAILURE(*pStatus)) { return NULL; } if (!woffData || !woffLen) { FAIL(eWOFF_bad_parameter); } if (*woffLen < sizeof(woffHeader)) { FAIL(eWOFF_invalid); } header = (const woffHeader *) (woffData); if (READ32BE(header->signature) != WOFF_SIGNATURE) { FAIL(eWOFF_bad_signature); } if (header->metaOffset != 0 && header->metaCompLen != 0) { metaData = woffData + READ32BE(header->metaOffset); metaLen = READ32BE(header->metaCompLen); if (metaData + metaLen > woffData + *woffLen) { FAIL(eWOFF_invalid); } } woffData = rebuildWoff(woffData, woffLen, metaData, metaLen, READ32BE(header->metaOrigLen), privData, privLen, pStatus); return woffData; failure: if (pStatus) { *pStatus = status; } return NULL; } #endif /* WOFF_MOZILLA_CLIENT */ /******************************************************************/ /* * * * * * * * * * * * * * DECODING * * * * * * * * * * * * * * */ /******************************************************************/ static uint32_t sanityCheck(const uint8_t * woffData, uint32_t woffLen) { const woffHeader * header; uint16_t numTables, i; const woffDirEntry * dirEntry; uint32_t tableTotal = 0; if (!woffData || !woffLen) { return eWOFF_bad_parameter; } if (woffLen < sizeof(woffHeader)) { return eWOFF_invalid; } header = (const woffHeader *) (woffData); if (READ32BE(header->signature) != WOFF_SIGNATURE) { return eWOFF_bad_signature; } if (READ32BE(header->length) != woffLen || header->reserved != 0) { return eWOFF_invalid; } numTables = READ16BE(header->numTables); if (woffLen < sizeof(woffHeader) + numTables * sizeof(woffDirEntry)) { return eWOFF_invalid; } dirEntry = (const woffDirEntry *) (woffData + sizeof(woffHeader)); for (i = 0; i < numTables; ++i) { uint32_t offs = READ32BE(dirEntry->offset); uint32_t orig = READ32BE(dirEntry->origLen); uint32_t comp = READ32BE(dirEntry->compLen); if (comp > orig || comp > woffLen || offs > woffLen - comp) { return eWOFF_invalid; } orig = (orig + 3) & ~3; if (tableTotal > 0xffffffffU - orig) { return eWOFF_invalid; } tableTotal += orig; ++dirEntry; } if (tableTotal > 0xffffffffU - sizeof(sfntHeader) - numTables * sizeof(sfntDirEntry) || READ32BE(header->totalSfntSize) != tableTotal + sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry)) { return eWOFF_invalid; } return eWOFF_ok; } uint32_t woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen, uint32_t * pStatus) { uint32_t status = eWOFF_ok; uint32_t totalLen = 0; if (pStatus && WOFF_FAILURE(*pStatus)) { return 0; } status = sanityCheck(woffData, woffLen); if (WOFF_FAILURE(status)) { FAIL(status); } totalLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize); /* totalLen must be correctly rounded up to 4-byte alignment, otherwise sanityCheck would have failed */ failure: if (pStatus) { *pStatus = status; } return totalLen; } static void woffDecodeToBufferInternal(const uint8_t * woffData, uint32_t woffLen, uint8_t * sfntData, uint32_t bufferLen, uint32_t * pActualSfntLen, uint32_t * pStatus) { /* this is only called after sanityCheck has verified that (a) basic header fields are ok (b) all the WOFF table offset/length pairs are valid (within the data) (c) the sum of original sizes + header/directory matches totalSfntSize so we don't have to re-check those overflow conditions here */ tableOrderRec * tableOrder = NULL; const woffHeader * header; uint16_t numTables; uint16_t tableIndex; uint16_t order; const woffDirEntry * woffDir; uint32_t totalLen; sfntHeader * newHeader; uint16_t searchRange, rangeShift, entrySelector; uint32_t offset; sfntDirEntry * sfntDir; uint32_t headOffset = 0, headLength = 0; sfntHeadTable * head; uint32_t csum = 0; const uint32_t * csumPtr; uint32_t oldCheckSumAdjustment; uint32_t status = eWOFF_ok; if (pStatus && WOFF_FAILURE(*pStatus)) { return; } /* check basic header fields */ header = (const woffHeader *) (woffData); if (READ32BE(header->flavor) != SFNT_VERSION_TT && READ32BE(header->flavor) != SFNT_VERSION_CFF && READ32BE(header->flavor) != SFNT_VERSION_true) { status |= eWOFF_warn_unknown_version; } numTables = READ16BE(header->numTables); woffDir = (const woffDirEntry *) (woffData + sizeof(woffHeader)); totalLen = READ32BE(header->totalSfntSize); /* construct the sfnt header */ newHeader = (sfntHeader *) (sfntData); newHeader->version = header->flavor; newHeader->numTables = READ16BE(numTables); /* calculate header fields for binary search */ searchRange = numTables; searchRange |= (searchRange >> 1); searchRange |= (searchRange >> 2); searchRange |= (searchRange >> 4); searchRange |= (searchRange >> 8); searchRange &= ~(searchRange >> 1); searchRange *= 16; newHeader->searchRange = READ16BE(searchRange); rangeShift = numTables * 16 - searchRange; newHeader->rangeShift = READ16BE(rangeShift); entrySelector = 0; while (searchRange > 16) { ++entrySelector; searchRange >>= 1; } newHeader->entrySelector = READ16BE(entrySelector); tableOrder = (tableOrderRec *) malloc(numTables * sizeof(tableOrderRec)); if (!tableOrder) { FAIL(eWOFF_out_of_memory); } for (tableIndex = 0; tableIndex < numTables; ++tableIndex) { tableOrder[tableIndex].offset = READ32BE(woffDir[tableIndex].offset); tableOrder[tableIndex].oldIndex = tableIndex; } qsort(tableOrder, numTables, sizeof(tableOrderRec), compareOffsets); /* process each table, filling in the sfnt directory */ offset = sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry); sfntDir = (sfntDirEntry *) (sfntData + sizeof(sfntHeader)); for (order = 0; order < numTables; ++order) { uint32_t origLen, compLen, tag, sourceOffset; tableIndex = tableOrder[order].oldIndex; /* validity of these was confirmed by sanityCheck */ origLen = READ32BE(woffDir[tableIndex].origLen); compLen = READ32BE(woffDir[tableIndex].compLen); sourceOffset = READ32BE(woffDir[tableIndex].offset); sfntDir[tableIndex].tag = woffDir[tableIndex].tag; sfntDir[tableIndex].offset = READ32BE(offset); sfntDir[tableIndex].length = woffDir[tableIndex].origLen; sfntDir[tableIndex].checksum = woffDir[tableIndex].checksum; csum += READ32BE(sfntDir[tableIndex].checksum); if (compLen < origLen) { uLongf destLen = origLen; if (uncompress((Bytef *)(sfntData + offset), &destLen, (const Bytef *)(woffData + sourceOffset), compLen) != Z_OK || destLen != origLen) { FAIL(eWOFF_compression_failure); } } else { memcpy(sfntData + offset, woffData + sourceOffset, origLen); } /* note that old Mac bitmap-only fonts have no 'head' table (eg NISC18030.ttf) but a 'bhed' table instead */ tag = READ32BE(sfntDir[tableIndex].tag); if (tag == TABLE_TAG_head || tag == TABLE_TAG_bhed) { headOffset = offset; headLength = origLen; } offset += origLen; while (offset < totalLen && (offset & 3) != 0) { sfntData[offset++] = 0; } } if (headOffset > 0) { /* the font checksum in the 'head' table depends on all the individual table checksums (collected above), plus the header and directory which are added in here */ if (headLength < HEAD_TABLE_SIZE) { FAIL(eWOFF_invalid); } head = (sfntHeadTable *)(sfntData + headOffset); oldCheckSumAdjustment = READ32BE(head->checkSumAdjustment); head->checkSumAdjustment = 0; csumPtr = (const uint32_t *)sfntData; while (csumPtr < (const uint32_t *)(sfntData + sizeof(sfntHeader) + numTables * sizeof(sfntDirEntry))) { csum += READ32BE(*csumPtr); csumPtr++; } csum = SFNT_CHECKSUM_CALC_CONST - csum; if (oldCheckSumAdjustment != csum) { /* if the checksum doesn't match, we fix it; but this will invalidate any DSIG that may be present */ status |= eWOFF_warn_checksum_mismatch; } head->checkSumAdjustment = READ32BE(csum); } if (pActualSfntLen) { *pActualSfntLen = totalLen; } if (pStatus) { *pStatus |= status; } free(tableOrder); return; failure: if (tableOrder) { free(tableOrder); } if (pActualSfntLen) { *pActualSfntLen = 0; } if (pStatus) { *pStatus = status; } } void woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen, uint8_t * sfntData, uint32_t bufferLen, uint32_t * pActualSfntLen, uint32_t * pStatus) { uint32_t status = eWOFF_ok; uint32_t totalLen; if (pStatus && WOFF_FAILURE(*pStatus)) { return; } status = sanityCheck(woffData, woffLen); if (WOFF_FAILURE(status)) { FAIL(status); } if (!sfntData) { FAIL(eWOFF_bad_parameter); } totalLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize); if (bufferLen < totalLen) { FAIL(eWOFF_buffer_too_small); } woffDecodeToBufferInternal(woffData, woffLen, sfntData, bufferLen, pActualSfntLen, pStatus); return; failure: if (pActualSfntLen) { *pActualSfntLen = 0; } if (pStatus) { *pStatus = status; } } const uint8_t * woffDecode(const uint8_t * woffData, uint32_t woffLen, uint32_t * sfntLen, uint32_t * pStatus) { uint32_t status = eWOFF_ok; uint8_t * sfntData = NULL; uint32_t bufLen; if (pStatus && WOFF_FAILURE(*pStatus)) { return NULL; } status = sanityCheck(woffData, woffLen); if (WOFF_FAILURE(status)) { FAIL(status); } bufLen = READ32BE(((const woffHeader *) (woffData))->totalSfntSize); sfntData = (uint8_t *) malloc(bufLen); if (!sfntData) { FAIL(eWOFF_out_of_memory); } woffDecodeToBufferInternal(woffData, woffLen, sfntData, bufLen, sfntLen, &status); if (WOFF_FAILURE(status)) { FAIL(status); } if (pStatus) { *pStatus |= status; } return sfntData; failure: if (sfntData) { free(sfntData); } if (pStatus) { *pStatus = status; } return NULL; } #ifndef WOFF_MOZILLA_CLIENT const uint8_t * woffGetMetadata(const uint8_t * woffData, uint32_t woffLen, uint32_t * metaLen, uint32_t * pStatus) { const woffHeader * header; uint32_t offset, compLen; uLong origLen; uint8_t * data = NULL; uint32_t status = eWOFF_ok; if (pStatus && WOFF_FAILURE(*pStatus)) { return NULL; } status = sanityCheck(woffData, woffLen); if (WOFF_FAILURE(status)) { FAIL(status); } header = (const woffHeader *) (woffData); offset = READ32BE(header->metaOffset); compLen = READ32BE(header->metaCompLen); origLen = READ32BE(header->metaOrigLen); if (offset == 0 || compLen == 0 || origLen == 0) { return NULL; } if (compLen > woffLen || offset > woffLen - compLen) { FAIL(eWOFF_invalid); } data = malloc(origLen); if (!data) { FAIL(eWOFF_out_of_memory); } if (uncompress((Bytef *)data, &origLen, (const Bytef *)woffData + offset, compLen) != Z_OK || origLen != READ32BE(header->metaOrigLen)) { FAIL(eWOFF_compression_failure); } if (metaLen) { *metaLen = origLen; } if (pStatus) { *pStatus |= status; } return data; failure: if (data) { free(data); } if (pStatus) { *pStatus = status; } return NULL; } const uint8_t * woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen, uint32_t * privLen, uint32_t * pStatus) { const woffHeader * header; uint32_t offset, length; uint8_t * data = NULL; uint32_t status = eWOFF_ok; if (pStatus && WOFF_FAILURE(*pStatus)) { return NULL; } status = sanityCheck(woffData, woffLen); if (WOFF_FAILURE(status)) { FAIL(status); } header = (const woffHeader *) (woffData); offset = READ32BE(header->privOffset); length = READ32BE(header->privLen); if (offset == 0 || length == 0) { return NULL; } if (length > woffLen || offset > woffLen - length) { FAIL(eWOFF_invalid); } data = malloc(length); if (!data) { FAIL(eWOFF_out_of_memory); } memcpy(data, woffData + offset, length); if (privLen) { *privLen = length; } if (pStatus) { *pStatus |= status; } return data; failure: if (data) { free(data); } if (pStatus) { *pStatus = status; } return NULL; } void woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen, uint16_t * major, uint16_t * minor, uint32_t * pStatus) { const woffHeader * header; uint32_t status = eWOFF_ok; if (pStatus && WOFF_FAILURE(*pStatus)) { return; } status = sanityCheck(woffData, woffLen); if (WOFF_FAILURE(status)) { FAIL(status); } if (!major || !minor) { FAIL(eWOFF_bad_parameter); } *major = *minor = 0; header = (const woffHeader *) (woffData); *major = READ16BE(header->majorVersion); *minor = READ16BE(header->minorVersion); failure: if (pStatus) { *pStatus = status; } } /* utility to print messages corresponding to WOFF encoder/decoder errors */ void woffPrintStatus(FILE * f, uint32_t status, const char * prefix) { if (!prefix) { prefix = ""; } if (WOFF_WARNING(status)) { const char * template = "%sWOFF warning: %s\n"; if (status & eWOFF_warn_unknown_version) { fprintf(f, template, prefix, "unrecognized sfnt version"); } if (status & eWOFF_warn_checksum_mismatch) { fprintf(f, template, prefix, "checksum mismatch (corrected)"); } if (status & eWOFF_warn_misaligned_table) { fprintf(f, template, prefix, "misaligned font table"); } if (status & eWOFF_warn_trailing_data) { fprintf(f, template, prefix, "extraneous input data discarded"); } if (status & eWOFF_warn_unpadded_table) { fprintf(f, template, prefix, "final table not correctly padded"); } if (status & eWOFF_warn_removed_DSIG) { fprintf(f, template, prefix, "digital signature (DSIG) table removed"); } } if (WOFF_FAILURE(status)) { const char * template = "%sWOFF error: %s\n"; const char * msg; switch (status & 0xff) { case eWOFF_out_of_memory: msg = "memory allocation failure"; break; case eWOFF_invalid: msg = "invalid input font"; break; case eWOFF_compression_failure: msg = "zlib compression/decompression failure"; break; case eWOFF_bad_signature: msg = "incorrect WOFF file signature"; break; case eWOFF_buffer_too_small: msg = "buffer too small"; break; case eWOFF_bad_parameter: msg = "bad parameter to WOFF function"; break; case eWOFF_illegal_order: msg = "incorrect table directory order"; break; default: msg = "unknown internal error"; break; } fprintf(f, template, prefix, msg); } } #endif /* not WOFF_MOZILLA_CLIENT */ woff-tools-2009.10.04/Makefile0000666000000000000000000000054311245544632014360 0ustar rootrootall: sfnt2woff woff2sfnt sfnt2woff: sfnt2woff.o woff.o woff.h Makefile $(CC) $(LDFLAGS) -o $@ $< woff.o -lz woff2sfnt: woff2sfnt.o woff.o woff.h Makefile $(CC) $(LDFLAGS) -o $@ $< woff.o -lz sfnt2woff.o: sfnt2woff.c woff.h Makefile woff2sfnt.o: woff2sfnt.c woff.h Makefile woff.o: woff.c woff.h woff-private.h Makefile clean: $(RM) -r *.o *.dSYM woff-tools-2009.10.04/sfnt2woff.c0000666000000000000000000001273711251762216015007 0ustar rootroot/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is WOFF font packaging code. * * The Initial Developer of the Original Code is Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jonathan Kew * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include #include #include #include #include "woff.h" static void die(const char * msg) { fprintf(stderr, "# fatal error: %s\n", msg); exit(2); } static void reportErr(uint32_t status) { woffPrintStatus(stderr, status, "### "); exit(2); } static void usage(const char * progName) { fprintf(stderr, "Usage:\n" " %s [-v .] [-m ] [-p ] \n" " package OpenType as WOFF, creating .woff\n" "Options:\n" " -v . set font version number (major and minor, both integers)\n" " -m include metadata from (not validated)\n" " -p include private data block\n" , progName); } const uint8_t * readFile(const char * name, uint32_t * len) { FILE * inFile = fopen(name, "rb"); if (!inFile) { char buf[200]; sprintf(buf, "unable to open file %s", name); die(buf); } if (fseek(inFile, 0, SEEK_END) != 0) die("seek failure"); *len = ftell(inFile); if (fseek(inFile, 0, SEEK_SET) != 0) die("seek failure"); uint8_t * data = (uint8_t *) malloc(*len); if (!data) die("malloc failure"); if (fread(data, 1, *len, inFile) != *len) die("file read failure"); fclose(inFile); return data; } int main(int argc, char * argv[]) { const char * progName = argv[0]; const char * metadataFile = NULL; const char * privateFile = NULL; unsigned int maj = 0, min = 0; uint32_t status = eWOFF_ok; int opt; while ((opt = getopt(argc, argv, "v:m:p:h")) != -1) { switch (opt) { case 'v': if (sscanf(optarg, "%u.%u", &maj, &min) < 2 || maj > 0xffff || min > 0xffff) { fprintf(stderr, "# bad version number, setting to 0.0\n"); maj = min = 0; } break; case 'm': metadataFile = optarg; break; case 'p': privateFile = optarg; break; case 'h': case '?': usage(progName); exit(0); default: fprintf(stderr, "# unknown option \"%c\"\n", opt); break; } } argc -= optind; argv += optind; if (argc != 1) { usage(progName); exit(1); } uint32_t sfntLen; const uint8_t * sfntData = readFile(argv[0], &sfntLen); uint32_t woffLen; const uint8_t * woffData = woffEncode(sfntData, sfntLen, maj, min, &woffLen, &status); free((void *)sfntData); if (WOFF_FAILURE(status)) { reportErr(status); } if (metadataFile) { uint32_t len; const uint8_t * data = readFile(metadataFile, &len); woffData = woffSetMetadata(woffData, &woffLen, data, len, &status); free((void *)data); if (WOFF_FAILURE(status)) { reportErr(status); } } if (privateFile) { uint32_t len; const uint8_t * data = readFile(privateFile, &len); woffData = woffSetPrivateData(woffData, &woffLen, data, len, &status); free((void *)data); if (WOFF_FAILURE(status)) { reportErr(status); } } if (WOFF_WARNING(status)) { woffPrintStatus(stderr, status, "### "); } char * outName = (char *) malloc(strlen(argv[0]) + 8); if (!outName) die("malloc failure"); strcpy(outName, argv[0]); char * ext = strrchr(outName, '.'); if (ext && (!strcmp(ext, ".ttf") || !strcmp(ext, ".otf"))) *ext = 0; strcat(outName, ".woff"); if (woffData) { FILE * outFile = fopen(outName, "wb"); free(outName); if (!outFile) die("unable to open output file"); if (fwrite(woffData, 1, woffLen, outFile) != woffLen) die("file write failure"); fclose(outFile); free((void *) woffData); } else { die("unable to create WOFF data"); } return 0; } woff-tools-2009.10.04/woff.h0000666000000000000000000002251311254152526014030 0ustar rootroot/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is WOFF font packaging code. * * The Initial Developer of the Original Code is Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jonathan Kew * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef WOFF_H_ #define WOFF_H_ /* API for the WOFF encoder and decoder */ #ifdef _MSC_VER /* MS VC lacks inttypes.h but we can make do with a few definitons here */ typedef char int8_t; typedef short int16_t; typedef int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else #include #endif #include /* only for FILE, needed for woffPrintStatus */ /* error codes returned in the status parameter of WOFF functions */ enum { /* Success */ eWOFF_ok = 0, /* Errors: no valid result returned */ eWOFF_out_of_memory = 1, /* malloc or realloc failed */ eWOFF_invalid = 2, /* invalid input file (e.g., bad offset) */ eWOFF_compression_failure = 3, /* error in zlib call */ eWOFF_bad_signature = 4, /* unrecognized file signature */ eWOFF_buffer_too_small = 5, /* the provided buffer is too small */ eWOFF_bad_parameter = 6, /* bad parameter (e.g., null source ptr) */ eWOFF_illegal_order = 7, /* improperly ordered chunks in WOFF font */ /* Warnings: call succeeded but something odd was noticed. Multiple warnings may be OR'd together. */ eWOFF_warn_unknown_version = 0x0100, /* unrecognized version of sfnt, not standard TrueType or CFF */ eWOFF_warn_checksum_mismatch = 0x0200, /* bad checksum, use with caution; any DSIG will be invalid */ eWOFF_warn_misaligned_table = 0x0400, /* table not long-aligned; fixing, but DSIG will be invalid */ eWOFF_warn_trailing_data = 0x0800, /* trailing junk discarded, any DSIG may be invalid */ eWOFF_warn_unpadded_table = 0x1000, /* sfnt not correctly padded, any DSIG may be invalid */ eWOFF_warn_removed_DSIG = 0x2000 /* removed digital signature while fixing checksum errors */ }; /* Note: status parameters must be initialized to eWOFF_ok before calling WOFF functions. If the status parameter contains an error code, functions will return immediately. */ #define WOFF_SUCCESS(status) (((uint32_t)(status) & 0xff) == eWOFF_ok) #define WOFF_FAILURE(status) (!WOFF_SUCCESS(status)) #define WOFF_WARNING(status) ((uint32_t)(status) & ~0xff) #ifdef __cplusplus extern "C" { #endif #ifndef WOFF_DISABLE_ENCODING /***************************************************************************** * Returns a new malloc() block containing the encoded data, or NULL on error; * caller should free() this when finished with it. * Returns length of the encoded data in woffLen. * The new WOFF has no metadata or private block; * see the following functions to update these elements. */ const uint8_t * woffEncode(const uint8_t * sfntData, uint32_t sfntLen, uint16_t majorVersion, uint16_t minorVersion, uint32_t * woffLen, uint32_t * status); /***************************************************************************** * Add the given metadata block to the WOFF font, replacing any existing * metadata block. The block will be zlib-compressed. * Metadata is required to be valid XML (use of UTF-8 is recommended), * though this function does not currently check this. * The woffData pointer must be a malloc() block (typically from woffEncode); * it will be freed by this function and a new malloc() block will be returned. * Returns NULL if an error occurs, in which case the original WOFF is NOT freed. */ const uint8_t * woffSetMetadata(const uint8_t * woffData, uint32_t * woffLen, const uint8_t * metaData, uint32_t metaLen, uint32_t * status); /***************************************************************************** * Add the given private data block to the WOFF font, replacing any existing * private block. The block will NOT be zlib-compressed. * Private data may be any arbitrary block of bytes; it may be externally * compressed by the client if desired. * The woffData pointer must be a malloc() block (typically from woffEncode); * it will be freed by this function and a new malloc() block will be returned. * Returns NULL if an error occurs, in which case the original WOFF is NOT freed. */ const uint8_t * woffSetPrivateData(const uint8_t * woffData, uint32_t * woffLen, const uint8_t * privData, uint32_t privLen, uint32_t * status); #endif /* WOFF_DISABLE_ENCODING */ /***************************************************************************** * Returns the size of buffer needed to decode the font (or zero on error). */ uint32_t woffGetDecodedSize(const uint8_t * woffData, uint32_t woffLen, uint32_t * pStatus); /***************************************************************************** * Decodes WOFF font to a caller-supplied buffer of size bufferLen. * Returns the actual size of the decoded sfnt data in pActualSfntLen * (must be <= bufferLen, otherwise an error will be returned). */ void woffDecodeToBuffer(const uint8_t * woffData, uint32_t woffLen, uint8_t * sfntData, uint32_t bufferLen, uint32_t * pActualSfntLen, uint32_t * pStatus); /***************************************************************************** * Returns a new malloc() block containing the decoded data, or NULL on error; * caller should free() this when finished with it. * Returns length of the decoded data in sfntLen. */ const uint8_t * woffDecode(const uint8_t * woffData, uint32_t woffLen, uint32_t * sfntLen, uint32_t * status); /***************************************************************************** * Returns a new malloc() block containing the metadata from the WOFF font, * or NULL if an error occurs or no metadata is present. * Length of the metadata is returned in metaLen. * The metadata is decompressed before returning. */ const uint8_t * woffGetMetadata(const uint8_t * woffData, uint32_t woffLen, uint32_t * metaLen, uint32_t * status); /***************************************************************************** * Returns a new malloc() block containing the private data from the WOFF font, * or NULL if an error occurs or no private data is present. * Length of the private data is returned in privLen. */ const uint8_t * woffGetPrivateData(const uint8_t * woffData, uint32_t woffLen, uint32_t * privLen, uint32_t * status); /***************************************************************************** * Returns the font version numbers from the WOFF font in the major and minor * parameters. * Check the status result to know if the function succeeded. */ void woffGetFontVersion(const uint8_t * woffData, uint32_t woffLen, uint16_t * major, uint16_t * minor, uint32_t * status); /***************************************************************************** * Utility to print warning and/or error status to the specified FILE*. * The prefix string will be prepended to each line (ok to pass NULL if no * prefix is wanted). * (Provides terse English messages only, not intended for end-user display; * user-friendly tools should map the status codes to their own messages.) */ void woffPrintStatus(FILE * f, uint32_t status, const char * prefix); #ifdef __cplusplus } #endif #endif woff-tools-2009.10.04/woff-private.h0000666000000000000000000001117111254152526015476 0ustar rootroot/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is WOFF font packaging code. * * The Initial Developer of the Original Code is Mozilla Corporation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Jonathan Kew * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #ifndef WOFF_PRIVATE_H_ #define WOFF_PRIVATE_H_ #include "woff.h" /* private definitions used in the WOFF encoder/decoder functions */ /* create an OT tag from 4 characters */ #define TAG(a,b,c,d) ((a)<<24 | (b)<<16 | (c)<<8 | (d)) #define WOFF_SIGNATURE TAG('w','O','F','F') #define SFNT_VERSION_CFF TAG('O','T','T','O') #define SFNT_VERSION_TT 0x00010000 #define SFNT_VERSION_true TAG('t','r','u','e') #define TABLE_TAG_DSIG TAG('D','S','I','G') #define TABLE_TAG_head TAG('h','e','a','d') #define TABLE_TAG_bhed TAG('b','h','e','d') #define SFNT_CHECKSUM_CALC_CONST 0xB1B0AFBAU /* from the TT/OT spec */ #ifdef WOFF_MOZILLA_CLIENT # include # define READ32BE(x) PR_ntohl(x) # define READ16BE(x) PR_ntohs(x) #else /* These macros to read values as big-endian only work on "real" variables, not general expressions, because of the use of &(x), but they are designed to work on both BE and LE machines without the need for a configure check. For production code, we might want to replace this with something more efficient. */ /* read a 32-bit BigEndian value */ # define READ32BE(x) ( ( (uint32_t) ((uint8_t*)&(x))[0] << 24 ) + \ ( (uint32_t) ((uint8_t*)&(x))[1] << 16 ) + \ ( (uint32_t) ((uint8_t*)&(x))[2] << 8 ) + \ (uint32_t) ((uint8_t*)&(x))[3] ) /* read a 16-bit BigEndian value */ # define READ16BE(x) ( ( (uint16_t) ((uint8_t*)&(x))[0] << 8 ) + \ (uint16_t) ((uint8_t*)&(x))[1] ) #endif #pragma pack(push,1) typedef struct { uint32_t version; uint16_t numTables; uint16_t searchRange; uint16_t entrySelector; uint16_t rangeShift; } sfntHeader; typedef struct { uint32_t tag; uint32_t checksum; uint32_t offset; uint32_t length; } sfntDirEntry; typedef struct { uint32_t signature; uint32_t flavor; uint32_t length; uint16_t numTables; uint16_t reserved; uint32_t totalSfntSize; uint16_t majorVersion; uint16_t minorVersion; uint32_t metaOffset; uint32_t metaCompLen; uint32_t metaOrigLen; uint32_t privOffset; uint32_t privLen; } woffHeader; typedef struct { uint32_t tag; uint32_t offset; uint32_t compLen; uint32_t origLen; uint32_t checksum; } woffDirEntry; typedef struct { uint32_t version; uint32_t fontRevision; uint32_t checkSumAdjustment; uint32_t magicNumber; uint16_t flags; uint16_t unitsPerEm; uint32_t created[2]; uint32_t modified[2]; int16_t xMin; int16_t yMin; int16_t xMax; int16_t yMax; uint16_t macStyle; uint16_t lowestRecPpem; int16_t fontDirectionHint; int16_t indexToLocFormat; int16_t glyphDataFormat; } sfntHeadTable; #define HEAD_TABLE_SIZE 54 /* sizeof(sfntHeadTable) may report 56 because of alignment */ typedef struct { uint32_t offset; uint16_t oldIndex; uint16_t newIndex; } tableOrderRec; #pragma pack(pop) #endif