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