Line data Source code
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 :
13 0 : 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 0 : const uint8_t* buf = *src;
20 0 : if (*len < 2 || buf[0] != 0x80 || buf[1] != sectionType) {
21 0 : return false;
22 0 : } else if (buf[1] == 3) {
23 0 : return true;
24 0 : } else if (*len < 6) {
25 0 : return false;
26 : }
27 :
28 0 : *size = (size_t)buf[2] | ((size_t)buf[3] << 8) | ((size_t)buf[4] << 16) |
29 0 : ((size_t)buf[5] << 24);
30 0 : size_t consumed = *size + 6;
31 0 : if (consumed > *len) {
32 0 : return false;
33 : }
34 0 : *src = *src + consumed;
35 0 : *len = *len - consumed;
36 0 : return true;
37 : }
38 :
39 0 : static bool parsePFB(const uint8_t* src, size_t size, size_t* headerLen,
40 : size_t* dataLen, size_t* trailerLen) {
41 0 : const uint8_t* srcPtr = src;
42 0 : size_t remaining = size;
43 :
44 0 : return parsePFBSection(&srcPtr, &remaining, 1, headerLen) &&
45 0 : parsePFBSection(&srcPtr, &remaining, 2, dataLen) &&
46 0 : parsePFBSection(&srcPtr, &remaining, 1, trailerLen) &&
47 0 : 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 : */
58 0 : static bool parsePFA(const char* src, size_t size, size_t* headerLen,
59 : size_t* hexDataLen, size_t* dataLen, size_t* trailerLen) {
60 0 : const char* end = src + size;
61 :
62 0 : const char* dataPos = strstr(src, "eexec");
63 0 : if (!dataPos) {
64 0 : return false;
65 : }
66 0 : dataPos += strlen("eexec");
67 0 : while ((*dataPos == '\n' || *dataPos == '\r' || *dataPos == ' ') &&
68 : dataPos < end) {
69 0 : dataPos++;
70 : }
71 0 : *headerLen = dataPos - src;
72 :
73 0 : const char* trailerPos = strstr(dataPos, "cleartomark");
74 0 : if (!trailerPos) {
75 0 : return false;
76 : }
77 0 : int zeroCount = 0;
78 0 : for (trailerPos--; trailerPos > dataPos && zeroCount < 512; trailerPos--) {
79 0 : if (*trailerPos == '\n' || *trailerPos == '\r' || *trailerPos == ' ') {
80 0 : continue;
81 0 : } else if (*trailerPos == '0') {
82 0 : zeroCount++;
83 : } else {
84 0 : return false;
85 : }
86 : }
87 0 : if (zeroCount != 512) {
88 0 : return false;
89 : }
90 :
91 0 : *hexDataLen = trailerPos - src - *headerLen;
92 0 : *trailerLen = size - *headerLen - *hexDataLen;
93 :
94 : // Verify that the data section is hex encoded and count the bytes.
95 0 : int nibbles = 0;
96 0 : for (; dataPos < trailerPos; dataPos++) {
97 0 : if (isspace(*dataPos)) {
98 0 : continue;
99 : }
100 0 : if (!isxdigit(*dataPos)) {
101 0 : return false;
102 : }
103 0 : nibbles++;
104 : }
105 0 : *dataLen = (nibbles + 1) / 2;
106 :
107 0 : return true;
108 : }
109 :
110 0 : static int8_t hexToBin(uint8_t c) {
111 0 : if (!isxdigit(c)) {
112 0 : return -1;
113 0 : } else if (c <= '9') {
114 0 : return c - '0';
115 0 : } else if (c <= 'F') {
116 0 : return c - 'A' + 10;
117 0 : } else if (c <= 'f') {
118 0 : return c - 'a' + 10;
119 : }
120 0 : return -1;
121 : }
122 :
123 0 : sk_sp<SkData> SkPDFConvertType1FontStream(
124 : std::unique_ptr<SkStreamAsset> srcStream, size_t* headerLen,
125 : size_t* dataLen, size_t* trailerLen) {
126 0 : size_t srcLen = srcStream ? srcStream->getLength() : 0;
127 0 : SkASSERT(srcLen);
128 0 : if (!srcLen) {
129 0 : return nullptr;
130 : }
131 : // Flatten and Nul-terminate the source stream so that we can use
132 : // strstr() to search it.
133 0 : SkAutoTMalloc<uint8_t> sourceBuffer(SkToInt(srcLen + 1));
134 0 : (void)srcStream->read(sourceBuffer.get(), srcLen);
135 0 : sourceBuffer[SkToInt(srcLen)] = 0;
136 0 : const uint8_t* src = sourceBuffer.get();
137 :
138 0 : if (parsePFB(src, srcLen, headerLen, dataLen, trailerLen)) {
139 : static const int kPFBSectionHeaderLength = 6;
140 0 : const size_t length = *headerLen + *dataLen + *trailerLen;
141 0 : SkASSERT(length > 0);
142 0 : SkASSERT(length + (2 * kPFBSectionHeaderLength) <= srcLen);
143 :
144 0 : sk_sp<SkData> data(SkData::MakeUninitialized(length));
145 :
146 0 : 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 0 : const uint8_t* const srcData = srcHeader + *headerLen + kPFBSectionHeaderLength;
150 0 : const uint8_t* const srcTrailer = srcData + *headerLen;
151 :
152 0 : uint8_t* const resultHeader = (uint8_t*)data->writable_data();
153 0 : uint8_t* const resultData = resultHeader + *headerLen;
154 0 : uint8_t* const resultTrailer = resultData + *dataLen;
155 :
156 0 : SkASSERT(resultTrailer + *trailerLen == resultHeader + length);
157 :
158 0 : memcpy(resultHeader, srcHeader, *headerLen);
159 0 : memcpy(resultData, srcData, *dataLen);
160 0 : memcpy(resultTrailer, srcTrailer, *trailerLen);
161 :
162 0 : return data;
163 : }
164 :
165 : // A PFA has to be converted for PDF.
166 : size_t hexDataLen;
167 0 : if (!parsePFA((const char*)src, srcLen, headerLen, &hexDataLen, dataLen,
168 : trailerLen)) {
169 0 : return nullptr;
170 : }
171 0 : const size_t length = *headerLen + *dataLen + *trailerLen;
172 0 : SkASSERT(length > 0);
173 0 : auto data = SkData::MakeUninitialized(length);
174 0 : uint8_t* buffer = (uint8_t*)data->writable_data();
175 :
176 0 : memcpy(buffer, src, *headerLen);
177 0 : uint8_t* const resultData = &(buffer[*headerLen]);
178 :
179 0 : const uint8_t* hexData = src + *headerLen;
180 0 : const uint8_t* trailer = hexData + hexDataLen;
181 0 : size_t outputOffset = 0;
182 0 : uint8_t dataByte = 0; // To hush compiler.
183 0 : bool highNibble = true;
184 0 : for (; hexData < trailer; hexData++) {
185 0 : int8_t curNibble = hexToBin(*hexData);
186 0 : if (curNibble < 0) {
187 0 : continue;
188 : }
189 0 : if (highNibble) {
190 0 : dataByte = curNibble << 4;
191 0 : highNibble = false;
192 : } else {
193 0 : dataByte |= curNibble;
194 0 : highNibble = true;
195 0 : resultData[outputOffset++] = dataByte;
196 : }
197 : }
198 0 : if (!highNibble) {
199 0 : resultData[outputOffset++] = dataByte;
200 : }
201 0 : SkASSERT(outputOffset == *dataLen);
202 :
203 0 : uint8_t* const resultTrailer = &(buffer[SkToInt(*headerLen + outputOffset)]);
204 0 : memcpy(resultTrailer, src + *headerLen + hexDataLen, *trailerLen);
205 0 : return data;
206 : }
|