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