Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2010 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
     14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
     17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
     23  * THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "WOFFFileFormat.h"
     28 #include <zlib.h>
     29 
     30 #if !ENABLE(OPENTYPE_SANITIZER)
     31 
     32 #include "SharedBuffer.h"
     33 
     34 #if OS(UNIX)
     35 #include <netinet/in.h>
     36 #endif
     37 
     38 #if PLATFORM(BREWMP)
     39 #include <AEEstd.h>
     40 #define htonl(x) std_htonl(x)
     41 #define htons(x) std_htons(x)
     42 #define ntohl(x) std_ntohl(x)
     43 #define ntohs(x) std_ntohs(x)
     44 #endif
     45 
     46 #if OS(WINDOWS)
     47 #if CPU(BIG_ENDIAN)
     48 #define ntohs(x) ((uint16_t)(x))
     49 #define htons(x) ((uint16_t)(x))
     50 #define ntohl(x) ((uint32_t)(x))
     51 #define htonl(x) ((uint32_t)(x))
     52 #elif CPU(MIDDLE_ENDIAN)
     53 #define ntohs(x) ((unit16_t)(x))
     54 #define htons(x) ((uint16_t)(x))
     55 #define ntohl(x) ((uint32_t)((((uint32_t)(x) & 0xffff0000) >> 16) | (((uint32_t)(x) & 0xffff) << 16))
     56 #define htonl(x) ntohl(x)
     57 #else
     58 #define ntohs(x) ((uint16_t)((((uint16_t)(x) & 0xff00) >> 8) | (((uint16_t)(x) & 0x00ff) << 8)))
     59 #define htons(x) ntohs(x)
     60 #define ntohl(x) ((uint32_t)((((uint32_t)(x) & 0xff000000) >> 24) | (((uint32_t)(x) & 0x00ff0000) >>  8) | \
     61                  (((uint32_t)(x) & 0x0000ff00) <<  8) | (((uint32_t)(x) & 0x000000ff) << 24)))
     62 #define htonl(x) ntohl(x)
     63 #endif
     64 #endif // OS(WINDOWS)
     65 
     66 namespace WebCore {
     67 
     68 static bool readUInt32(SharedBuffer* buffer, size_t& offset, uint32_t& value)
     69 {
     70     ASSERT_ARG(offset, offset <= buffer->size());
     71     if (buffer->size() - offset < sizeof(value))
     72         return false;
     73 
     74     value = ntohl(*reinterpret_cast<const uint32_t*>(buffer->data() + offset));
     75     offset += sizeof(value);
     76 
     77     return true;
     78 }
     79 
     80 static bool readUInt16(SharedBuffer* buffer, size_t& offset, uint16_t& value)
     81 {
     82     ASSERT_ARG(offset, offset <= buffer->size());
     83     if (buffer->size() - offset < sizeof(value))
     84         return false;
     85 
     86     value = ntohs(*reinterpret_cast<const uint16_t*>(buffer->data() + offset));
     87     offset += sizeof(value);
     88 
     89     return true;
     90 }
     91 
     92 static bool writeUInt32(Vector<char>& vector, uint32_t value)
     93 {
     94     uint32_t bigEndianValue = htonl(value);
     95     return vector.tryAppend(reinterpret_cast<char*>(&bigEndianValue), sizeof(bigEndianValue));
     96 }
     97 
     98 static bool writeUInt16(Vector<char>& vector, uint16_t value)
     99 {
    100     uint16_t bigEndianValue = htons(value);
    101     return vector.tryAppend(reinterpret_cast<char*>(&bigEndianValue), sizeof(bigEndianValue));
    102 }
    103 
    104 static const uint32_t woffSignature = 0x774f4646; /* 'wOFF' */
    105 
    106 bool isWOFF(SharedBuffer* buffer)
    107 {
    108     size_t offset = 0;
    109     uint32_t signature;
    110 
    111     return readUInt32(buffer, offset, signature) && signature == woffSignature;
    112 }
    113 
    114 bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt)
    115 {
    116     ASSERT_ARG(sfnt, sfnt.isEmpty());
    117 
    118     size_t offset = 0;
    119 
    120     // Read the WOFF header.
    121     uint32_t signature;
    122     if (!readUInt32(woff, offset, signature) || signature != woffSignature) {
    123         ASSERT_NOT_REACHED();
    124         return false;
    125     }
    126 
    127     uint32_t flavor;
    128     if (!readUInt32(woff, offset, flavor))
    129         return false;
    130 
    131     uint32_t length;
    132     if (!readUInt32(woff, offset, length) || length != woff->size())
    133         return false;
    134 
    135     uint16_t numTables;
    136     if (!readUInt16(woff, offset, numTables))
    137         return false;
    138 
    139     if (!numTables || numTables > 0x0fff)
    140         return false;
    141 
    142     uint16_t reserved;
    143     if (!readUInt16(woff, offset, reserved) || reserved)
    144         return false;
    145 
    146     uint32_t totalSfntSize;
    147     if (!readUInt32(woff, offset, totalSfntSize))
    148         return false;
    149 
    150     if (woff->size() - offset < sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t))
    151         return false;
    152 
    153     offset += sizeof(uint16_t); // majorVersion
    154     offset += sizeof(uint16_t); // minorVersion
    155     offset += sizeof(uint32_t); // metaOffset
    156     offset += sizeof(uint32_t); // metaLength
    157     offset += sizeof(uint32_t); // metaOrigLength
    158     offset += sizeof(uint32_t); // privOffset
    159     offset += sizeof(uint32_t); // privLength
    160 
    161     // Check if the WOFF can supply as many tables as it claims it has.
    162     if (woff->size() - offset < numTables * 5 * sizeof(uint32_t))
    163         return false;
    164 
    165     // Write the sfnt offset subtable.
    166     uint16_t entrySelector = 0;
    167     uint16_t searchRange = 1;
    168     while (searchRange < numTables >> 1) {
    169         entrySelector++;
    170         searchRange <<= 1;
    171     }
    172     searchRange <<= 4;
    173     uint16_t rangeShift = (numTables << 4) - searchRange;
    174 
    175     if (!writeUInt32(sfnt, flavor)
    176         || !writeUInt16(sfnt, numTables)
    177         || !writeUInt16(sfnt, searchRange)
    178         || !writeUInt16(sfnt, entrySelector)
    179         || !writeUInt16(sfnt, rangeShift))
    180         return false;
    181 
    182     if (sfnt.size() > totalSfntSize)
    183         return false;
    184 
    185     if (totalSfntSize - sfnt.size() < numTables * 4 * sizeof(uint32_t))
    186         return false;
    187 
    188     size_t sfntTableDirectoryCursor = sfnt.size();
    189     sfnt.grow(sfnt.size() + numTables * 4 * sizeof(uint32_t));
    190 
    191     // Process tables.
    192     for (uint16_t i = 0; i < numTables; ++i) {
    193         // Read a WOFF table directory entry.
    194         uint32_t tableTag;
    195         if (!readUInt32(woff, offset, tableTag))
    196             return false;
    197 
    198         uint32_t tableOffset;
    199         if (!readUInt32(woff, offset, tableOffset))
    200             return false;
    201 
    202         uint32_t tableCompLength;
    203         if (!readUInt32(woff, offset, tableCompLength))
    204             return false;
    205 
    206         if (tableOffset > woff->size() || tableCompLength > woff->size() - tableOffset)
    207             return false;
    208 
    209         uint32_t tableOrigLength;
    210         if (!readUInt32(woff, offset, tableOrigLength) || tableCompLength > tableOrigLength)
    211             return false;
    212 
    213         if (tableOrigLength > totalSfntSize || sfnt.size() > totalSfntSize - tableOrigLength)
    214             return false;
    215 
    216         uint32_t tableOrigChecksum;
    217         if (!readUInt32(woff, offset, tableOrigChecksum))
    218             return false;
    219 
    220         // Write an sfnt table directory entry.
    221         uint32_t* sfntTableDirectoryPtr = reinterpret_cast<uint32_t*>(sfnt.data() + sfntTableDirectoryCursor);
    222         *sfntTableDirectoryPtr++ = htonl(tableTag);
    223         *sfntTableDirectoryPtr++ = htonl(tableOrigChecksum);
    224         *sfntTableDirectoryPtr++ = htonl(sfnt.size());
    225         *sfntTableDirectoryPtr++ = htonl(tableOrigLength);
    226         sfntTableDirectoryCursor += 4 * sizeof(uint32_t);
    227 
    228         if (tableCompLength == tableOrigLength) {
    229             // The table is not compressed.
    230             if (!sfnt.tryAppend(woff->data() + tableOffset, tableCompLength))
    231                 return false;
    232         } else {
    233             uLongf destLen = tableOrigLength;
    234             if (!sfnt.tryReserveCapacity(sfnt.size() + tableOrigLength))
    235                 return false;
    236             Bytef* dest = reinterpret_cast<Bytef*>(sfnt.end());
    237             sfnt.grow(sfnt.size() + tableOrigLength);
    238             if (uncompress(dest, &destLen, reinterpret_cast<const Bytef*>(woff->data() + tableOffset), tableCompLength) != Z_OK)
    239                 return false;
    240             if (destLen != tableOrigLength)
    241                 return false;
    242         }
    243 
    244         // Pad to a multiple of 4 bytes.
    245         while (sfnt.size() % 4)
    246             sfnt.append(0);
    247     }
    248 
    249     return sfnt.size() == totalSfntSize;
    250 }
    251 
    252 } // namespace WebCore
    253 
    254 #endif // !ENABLE(OPENTYPE_SANITIZER)
    255