LCOV - code coverage report
Current view: directory - gfx/thebes - woff.c (source / functions) Found Hit Coverage
Test: app.info Lines: 236 0 0.0 %
Date: 2012-06-02 Functions: 8 0 0.0 %

       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 */

Generated by: LCOV version 1.7