Home | History | Annotate | Download | only in pdf
      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 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 
     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  */
     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 
    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 
    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