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