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#include "SharedBuffer.h" 31#include <wtf/ByteOrder.h> 32 33namespace WebCore { 34 35static bool readUInt32(SharedBuffer* buffer, size_t& offset, uint32_t& value) 36{ 37 ASSERT_ARG(offset, offset <= buffer->size()); 38 if (buffer->size() - offset < sizeof(value)) 39 return false; 40 41 value = ntohl(*reinterpret_cast_ptr<const uint32_t*>(buffer->data() + offset)); 42 offset += sizeof(value); 43 44 return true; 45} 46 47static bool readUInt16(SharedBuffer* buffer, size_t& offset, uint16_t& value) 48{ 49 ASSERT_ARG(offset, offset <= buffer->size()); 50 if (buffer->size() - offset < sizeof(value)) 51 return false; 52 53 value = ntohs(*reinterpret_cast_ptr<const uint16_t*>(buffer->data() + offset)); 54 offset += sizeof(value); 55 56 return true; 57} 58 59static bool writeUInt32(Vector<char>& vector, uint32_t value) 60{ 61 uint32_t bigEndianValue = htonl(value); 62 return vector.tryAppend(reinterpret_cast_ptr<char*>(&bigEndianValue), sizeof(bigEndianValue)); 63} 64 65static bool writeUInt16(Vector<char>& vector, uint16_t value) 66{ 67 uint16_t bigEndianValue = htons(value); 68 return vector.tryAppend(reinterpret_cast_ptr<char*>(&bigEndianValue), sizeof(bigEndianValue)); 69} 70 71static const uint32_t woffSignature = 0x774f4646; /* 'wOFF' */ 72 73bool isWOFF(SharedBuffer* buffer) 74{ 75 size_t offset = 0; 76 uint32_t signature; 77 78 return readUInt32(buffer, offset, signature) && signature == woffSignature; 79} 80 81bool convertWOFFToSfnt(SharedBuffer* woff, Vector<char>& sfnt) 82{ 83 ASSERT_ARG(sfnt, sfnt.isEmpty()); 84 85 size_t offset = 0; 86 87 // Read the WOFF header. 88 uint32_t signature; 89 if (!readUInt32(woff, offset, signature) || signature != woffSignature) { 90 ASSERT_NOT_REACHED(); 91 return false; 92 } 93 94 uint32_t flavor; 95 if (!readUInt32(woff, offset, flavor)) 96 return false; 97 98 uint32_t length; 99 if (!readUInt32(woff, offset, length) || length != woff->size()) 100 return false; 101 102 uint16_t numTables; 103 if (!readUInt16(woff, offset, numTables)) 104 return false; 105 106 if (!numTables || numTables > 0x0fff) 107 return false; 108 109 uint16_t reserved; 110 if (!readUInt16(woff, offset, reserved) || reserved) 111 return false; 112 113 uint32_t totalSfntSize; 114 if (!readUInt32(woff, offset, totalSfntSize)) 115 return false; 116 117 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)) 118 return false; 119 120 offset += sizeof(uint16_t); // majorVersion 121 offset += sizeof(uint16_t); // minorVersion 122 offset += sizeof(uint32_t); // metaOffset 123 offset += sizeof(uint32_t); // metaLength 124 offset += sizeof(uint32_t); // metaOrigLength 125 offset += sizeof(uint32_t); // privOffset 126 offset += sizeof(uint32_t); // privLength 127 128 // Check if the WOFF can supply as many tables as it claims it has. 129 if (woff->size() - offset < numTables * 5 * sizeof(uint32_t)) 130 return false; 131 132 // Write the sfnt offset subtable. 133 uint16_t entrySelector = 0; 134 uint16_t searchRange = 1; 135 while (searchRange < numTables >> 1) { 136 entrySelector++; 137 searchRange <<= 1; 138 } 139 searchRange <<= 4; 140 uint16_t rangeShift = (numTables << 4) - searchRange; 141 142 if (!writeUInt32(sfnt, flavor) 143 || !writeUInt16(sfnt, numTables) 144 || !writeUInt16(sfnt, searchRange) 145 || !writeUInt16(sfnt, entrySelector) 146 || !writeUInt16(sfnt, rangeShift)) 147 return false; 148 149 if (sfnt.size() > totalSfntSize) 150 return false; 151 152 if (totalSfntSize - sfnt.size() < numTables * 4 * sizeof(uint32_t)) 153 return false; 154 155 size_t sfntTableDirectoryCursor = sfnt.size(); 156 sfnt.grow(sfnt.size() + numTables * 4 * sizeof(uint32_t)); 157 158 // Process tables. 159 for (uint16_t i = 0; i < numTables; ++i) { 160 // Read a WOFF table directory entry. 161 uint32_t tableTag; 162 if (!readUInt32(woff, offset, tableTag)) 163 return false; 164 165 uint32_t tableOffset; 166 if (!readUInt32(woff, offset, tableOffset)) 167 return false; 168 169 uint32_t tableCompLength; 170 if (!readUInt32(woff, offset, tableCompLength)) 171 return false; 172 173 if (tableOffset > woff->size() || tableCompLength > woff->size() - tableOffset) 174 return false; 175 176 uint32_t tableOrigLength; 177 if (!readUInt32(woff, offset, tableOrigLength) || tableCompLength > tableOrigLength) 178 return false; 179 180 if (tableOrigLength > totalSfntSize || sfnt.size() > totalSfntSize - tableOrigLength) 181 return false; 182 183 uint32_t tableOrigChecksum; 184 if (!readUInt32(woff, offset, tableOrigChecksum)) 185 return false; 186 187 // Write an sfnt table directory entry. 188 uint32_t* sfntTableDirectoryPtr = reinterpret_cast_ptr<uint32_t*>(sfnt.data() + sfntTableDirectoryCursor); 189 *sfntTableDirectoryPtr++ = htonl(tableTag); 190 *sfntTableDirectoryPtr++ = htonl(tableOrigChecksum); 191 *sfntTableDirectoryPtr++ = htonl(sfnt.size()); 192 *sfntTableDirectoryPtr++ = htonl(tableOrigLength); 193 sfntTableDirectoryCursor += 4 * sizeof(uint32_t); 194 195 if (tableCompLength == tableOrigLength) { 196 // The table is not compressed. 197 if (!sfnt.tryAppend(woff->data() + tableOffset, tableCompLength)) 198 return false; 199 } else { 200 uLongf destLen = tableOrigLength; 201 if (!sfnt.tryReserveCapacity(sfnt.size() + tableOrigLength)) 202 return false; 203 Bytef* dest = reinterpret_cast<Bytef*>(sfnt.end()); 204 sfnt.grow(sfnt.size() + tableOrigLength); 205 if (uncompress(dest, &destLen, reinterpret_cast<const Bytef*>(woff->data() + tableOffset), tableCompLength) != Z_OK) 206 return false; 207 if (destLen != tableOrigLength) 208 return false; 209 } 210 211 // Pad to a multiple of 4 bytes. 212 while (sfnt.size() % 4) 213 sfnt.append(0); 214 } 215 216 return sfnt.size() == totalSfntSize; 217} 218 219} // namespace WebCore 220