LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/pdf - SkPDFConvertType1FontStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 119 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 5 0.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.13