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