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
parsePFBSection(const uint8_t ** src,size_t * len,int sectionType,size_t * size)13 static 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
parsePFB(const uint8_t * src,size_t size,size_t * headerLen,size_t * dataLen,size_t * trailerLen)39 static 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 */
parsePFA(const char * src,size_t size,size_t * headerLen,size_t * hexDataLen,size_t * dataLen,size_t * trailerLen)58 static 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
hexToBin(uint8_t c)110 static 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
SkPDFConvertType1FontStream(std::unique_ptr<SkStreamAsset> srcStream,size_t * headerLen,size_t * dataLen,size_t * trailerLen)123 sk_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