1/* 2 * Copyright 2011 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkPDFConvertType1FontStream.h" 9#include "SkTemplates.h" 10 11#include <ctype.h> 12 13static bool parsePFBSection(const uint8_t** src, size_t* len, int sectionType, 14 size_t* size) { 15 // PFB sections have a two or six bytes header. 0x80 and a one byte 16 // section type followed by a four byte section length. Type one is 17 // an ASCII section (includes a length), type two is a binary section 18 // (includes a length) and type three is an EOF marker with no length. 19 const uint8_t* buf = *src; 20 if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType) { 21 return false; 22 } else if (buf[1] == 3) { 23 return true; 24 } else if (*len < 6) { 25 return false; 26 } 27 28 *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) | 29 ((size_t)buf[5] << 24); 30 size_t consumed = *size + 6; 31 if (consumed > *len) { 32 return false; 33 } 34 *src = *src + consumed; 35 *len = *len - consumed; 36 return true; 37} 38 39static bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen, 40 size_t* dataLen, size_t* trailerLen) { 41 const uint8_t* srcPtr = src; 42 size_t remaining = size; 43 44 return parsePFBSection(&srcPtr, &remaining, 1, headerLen) && 45 parsePFBSection(&srcPtr, &remaining, 2, dataLen) && 46 parsePFBSection(&srcPtr, &remaining, 1, trailerLen) && 47 parsePFBSection(&srcPtr, &remaining, 3, nullptr); 48} 49 50/* The sections of a PFA file are implicitly defined. The body starts 51 * after the line containing "eexec," and the trailer starts with 512 52 * literal 0's followed by "cleartomark" (plus arbitrary white space). 53 * 54 * This function assumes that src is NUL terminated, but the NUL 55 * termination is not included in size. 56 * 57 */ 58static bool parsePFA(const char* src, size_t size, size_t* headerLen, 59 size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) { 60 const char* end = src + size; 61 62 const char* dataPos = strstr(src, "eexec"); 63 if (!dataPos) { 64 return false; 65 } 66 dataPos += strlen("eexec"); 67 while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') && 68 dataPos < end) { 69 dataPos++; 70 } 71 *headerLen = dataPos - src; 72 73 const char* trailerPos = strstr(dataPos, "cleartomark"); 74 if (!trailerPos) { 75 return false; 76 } 77 int zeroCount = 0; 78 for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) { 79 if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') { 80 continue; 81 } else if (*trailerPos == '0') { 82 zeroCount++; 83 } else { 84 return false; 85 } 86 } 87 if (zeroCount != 512) { 88 return false; 89 } 90 91 *hexDataLen = trailerPos - src - *headerLen; 92 *trailerLen = size - *headerLen - *hexDataLen; 93 94 // Verify that the data section is hex encoded and count the bytes. 95 int nibbles = 0; 96 for (; dataPos < trailerPos; dataPos++) { 97 if (isspace(*dataPos)) { 98 continue; 99 } 100 if (!isxdigit(*dataPos)) { 101 return false; 102 } 103 nibbles++; 104 } 105 *dataLen = (nibbles + 1) / 2; 106 107 return true; 108} 109 110static int8_t hexToBin(uint8_t c) { 111 if (!isxdigit(c)) { 112 return -1; 113 } else if (c <= '9') { 114 return c - '0'; 115 } else if (c <= 'F') { 116 return c - 'A' + 10; 117 } else if (c <= 'f') { 118 return c - 'a' + 10; 119 } 120 return -1; 121} 122 123sk_sp<SkData> SkPDFConvertType1FontStream( 124 std::unique_ptr<SkStreamAsset> srcStream, size_t* headerLen, 125 size_t* dataLen, size_t* trailerLen) { 126 size_t srcLen = srcStream ? srcStream->getLength() : 0; 127 SkASSERT(srcLen); 128 if (!srcLen) { 129 return nullptr; 130 } 131 // Flatten and Nul-terminate the source stream so that we can use 132 // strstr() to search it. 133 SkAutoTMalloc<uint8_t> sourceBuffer(SkToInt(srcLen + 1)); 134 (void)srcStream->read(sourceBuffer.get(), srcLen); 135 sourceBuffer[SkToInt(srcLen)] = 0; 136 const uint8_t* src = sourceBuffer.get(); 137 138 if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) { 139 static const int kPFBSectionHeaderLength = 6; 140 const size_t length = *headerLen + *dataLen + *trailerLen; 141 SkASSERT(length > 0); 142 SkASSERT(length + (2 * kPFBSectionHeaderLength) <= srcLen); 143 144 sk_sp<SkData> data(SkData::MakeUninitialized(length)); 145 146 const uint8_t* const srcHeader = src + kPFBSectionHeaderLength; 147 // There is a six-byte section header before header and data 148 // (but not trailer) that we're not going to copy. 149 const uint8_t* const srcData = srcHeader + *headerLen + kPFBSectionHeaderLength; 150 const uint8_t* const srcTrailer = srcData + *headerLen; 151 152 uint8_t* const resultHeader = (uint8_t*)data->writable_data(); 153 uint8_t* const resultData = resultHeader + *headerLen; 154 uint8_t* const resultTrailer = resultData + *dataLen; 155 156 SkASSERT(resultTrailer + *trailerLen == resultHeader + length); 157 158 memcpy(resultHeader, srcHeader, *headerLen); 159 memcpy(resultData, srcData, *dataLen); 160 memcpy(resultTrailer, srcTrailer, *trailerLen); 161 162 return data; 163 } 164 165 // A PFA has to be converted for PDF. 166 size_t hexDataLen; 167 if (!parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen, 168 trailerLen)) { 169 return nullptr; 170 } 171 const size_t length = *headerLen + *dataLen + *trailerLen; 172 SkASSERT(length > 0); 173 auto data = SkData::MakeUninitialized(length); 174 uint8_t* buffer = (uint8_t*)data->writable_data(); 175 176 memcpy(buffer, src, *headerLen); 177 uint8_t* const resultData = &(buffer[*headerLen]); 178 179 const uint8_t* hexData = src + *headerLen; 180 const uint8_t* trailer = hexData + hexDataLen; 181 size_t outputOffset = 0; 182 uint8_t dataByte = 0; // To hush compiler. 183 bool highNibble = true; 184 for (; hexData < trailer; hexData++) { 185 int8_t curNibble = hexToBin(*hexData); 186 if (curNibble < 0) { 187 continue; 188 } 189 if (highNibble) { 190 dataByte = curNibble << 4; 191 highNibble = false; 192 } else { 193 dataByte |= curNibble; 194 highNibble = true; 195 resultData[outputOffset++] = dataByte; 196 } 197 } 198 if (!highNibble) { 199 resultData[outputOffset++] = dataByte; 200 } 201 SkASSERT(outputOffset == *dataLen); 202 203 uint8_t* const resultTrailer = &(buffer[SkToInt(*headerLen + outputOffset)]); 204 memcpy(resultTrailer, src + *headerLen + hexDataLen, *trailerLen); 205 return data; 206} 207