LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkFontStream.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 83 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 9 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 "SkAutoMalloc.h"
       9             : #include "SkEndian.h"
      10             : #include "SkFontStream.h"
      11             : #include "SkStream.h"
      12             : 
      13             : struct SkSFNTHeader {
      14             :     uint32_t    fVersion;
      15             :     uint16_t    fNumTables;
      16             :     uint16_t    fSearchRange;
      17             :     uint16_t    fEntrySelector;
      18             :     uint16_t    fRangeShift;
      19             : };
      20             : 
      21             : struct SkTTCFHeader {
      22             :     uint32_t    fTag;
      23             :     uint32_t    fVersion;
      24             :     uint32_t    fNumOffsets;
      25             :     uint32_t    fOffset0;   // the first of N (fNumOffsets)
      26             : };
      27             : 
      28             : union SkSharedTTHeader {
      29             :     SkSFNTHeader    fSingle;
      30             :     SkTTCFHeader    fCollection;
      31             : };
      32             : 
      33             : struct SkSFNTDirEntry {
      34             :     uint32_t    fTag;
      35             :     uint32_t    fChecksum;
      36             :     uint32_t    fOffset;
      37             :     uint32_t    fLength;
      38             : };
      39             : 
      40           0 : static bool read(SkStream* stream, void* buffer, size_t amount) {
      41           0 :     return stream->read(buffer, amount) == amount;
      42             : }
      43             : 
      44           0 : static bool skip(SkStream* stream, size_t amount) {
      45           0 :     return stream->skip(amount) == amount;
      46             : }
      47             : 
      48             : /** Return the number of tables, or if this is a TTC (collection), return the
      49             :     number of tables in the first element of the collection. In either case,
      50             :     if offsetToDir is not-null, set it to the offset to the beginning of the
      51             :     table headers (SkSFNTDirEntry), relative to the start of the stream.
      52             : 
      53             :     On an error, return 0 for number of tables, and ignore offsetToDir
      54             :  */
      55           0 : static int count_tables(SkStream* stream, int ttcIndex, size_t* offsetToDir) {
      56           0 :     SkASSERT(ttcIndex >= 0);
      57             : 
      58           0 :     SkAutoSMalloc<1024> storage(sizeof(SkSharedTTHeader));
      59           0 :     SkSharedTTHeader* header = (SkSharedTTHeader*)storage.get();
      60             : 
      61           0 :     if (!read(stream, header, sizeof(SkSharedTTHeader))) {
      62           0 :         return 0;
      63             :     }
      64             : 
      65             :     // by default, SkSFNTHeader is at the start of the stream
      66           0 :     size_t offset = 0;
      67             : 
      68             :     // if we're really a collection, the first 4-bytes will be 'ttcf'
      69           0 :     uint32_t tag = SkEndian_SwapBE32(header->fCollection.fTag);
      70           0 :     if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) {
      71           0 :         unsigned count = SkEndian_SwapBE32(header->fCollection.fNumOffsets);
      72           0 :         if ((unsigned)ttcIndex >= count) {
      73           0 :             return 0;
      74             :         }
      75             : 
      76           0 :         if (ttcIndex > 0) { // need to read more of the shared header
      77           0 :             stream->rewind();
      78           0 :             size_t amount = sizeof(SkSharedTTHeader) + ttcIndex * sizeof(uint32_t);
      79           0 :             header = (SkSharedTTHeader*)storage.reset(amount);
      80           0 :             if (!read(stream, header, amount)) {
      81           0 :                 return 0;
      82             :             }
      83             :         }
      84             :         // this is the offset to the local SkSFNTHeader
      85           0 :         offset = SkEndian_SwapBE32((&header->fCollection.fOffset0)[ttcIndex]);
      86           0 :         stream->rewind();
      87           0 :         if (!skip(stream, offset)) {
      88           0 :             return 0;
      89             :         }
      90           0 :         if (!read(stream, header, sizeof(SkSFNTHeader))) {
      91           0 :             return 0;
      92             :         }
      93             :     }
      94             : 
      95           0 :     if (offsetToDir) {
      96             :         // add the size of the header, so we will point to the DirEntries
      97           0 :         *offsetToDir = offset + sizeof(SkSFNTHeader);
      98             :     }
      99           0 :     return SkEndian_SwapBE16(header->fSingle.fNumTables);
     100             : }
     101             : 
     102             : ///////////////////////////////////////////////////////////////////////////////
     103             : 
     104             : struct SfntHeader {
     105           0 :     SfntHeader() : fCount(0), fDir(nullptr) {}
     106           0 :     ~SfntHeader() { sk_free(fDir); }
     107             : 
     108             :     /** If it returns true, then fCount and fDir are properly initialized.
     109             :         Note: fDir will point to the raw array of SkSFNTDirEntry values,
     110             :         meaning they will still be in the file's native endianness (BE).
     111             : 
     112             :         fDir will be automatically freed when this object is destroyed
     113             :      */
     114           0 :     bool init(SkStream* stream, int ttcIndex) {
     115           0 :         stream->rewind();
     116             : 
     117             :         size_t offsetToDir;
     118           0 :         fCount = count_tables(stream, ttcIndex, &offsetToDir);
     119           0 :         if (0 == fCount) {
     120           0 :             return false;
     121             :         }
     122             : 
     123           0 :         stream->rewind();
     124           0 :         if (!skip(stream, offsetToDir)) {
     125           0 :             return false;
     126             :         }
     127             : 
     128           0 :         size_t size = fCount * sizeof(SkSFNTDirEntry);
     129           0 :         fDir = reinterpret_cast<SkSFNTDirEntry*>(sk_malloc_throw(size));
     130           0 :         return read(stream, fDir, size);
     131             :     }
     132             : 
     133             :     int             fCount;
     134             :     SkSFNTDirEntry* fDir;
     135             : };
     136             : 
     137             : ///////////////////////////////////////////////////////////////////////////////
     138             : 
     139           0 : int SkFontStream::CountTTCEntries(SkStream* stream) {
     140           0 :     stream->rewind();
     141             : 
     142             :     SkSharedTTHeader shared;
     143           0 :     if (!read(stream, &shared, sizeof(shared))) {
     144           0 :         return 0;
     145             :     }
     146             : 
     147             :     // if we're really a collection, the first 4-bytes will be 'ttcf'
     148           0 :     uint32_t tag = SkEndian_SwapBE32(shared.fCollection.fTag);
     149           0 :     if (SkSetFourByteTag('t', 't', 'c', 'f') == tag) {
     150           0 :         return SkEndian_SwapBE32(shared.fCollection.fNumOffsets);
     151             :     } else {
     152           0 :         return 1;   // normal 'sfnt' has 1 dir entry
     153             :     }
     154             : }
     155             : 
     156           0 : int SkFontStream::GetTableTags(SkStream* stream, int ttcIndex,
     157             :                                SkFontTableTag tags[]) {
     158           0 :     SfntHeader  header;
     159           0 :     if (!header.init(stream, ttcIndex)) {
     160           0 :         return 0;
     161             :     }
     162             : 
     163           0 :     if (tags) {
     164           0 :         for (int i = 0; i < header.fCount; i++) {
     165           0 :             tags[i] = SkEndian_SwapBE32(header.fDir[i].fTag);
     166             :         }
     167             :     }
     168           0 :     return header.fCount;
     169             : }
     170             : 
     171           0 : size_t SkFontStream::GetTableData(SkStream* stream, int ttcIndex,
     172             :                                   SkFontTableTag tag,
     173             :                                   size_t offset, size_t length, void* data) {
     174           0 :     SfntHeader  header;
     175           0 :     if (!header.init(stream, ttcIndex)) {
     176           0 :         return 0;
     177             :     }
     178             : 
     179           0 :     for (int i = 0; i < header.fCount; i++) {
     180           0 :         if (SkEndian_SwapBE32(header.fDir[i].fTag) == tag) {
     181           0 :             size_t realOffset = SkEndian_SwapBE32(header.fDir[i].fOffset);
     182           0 :             size_t realLength = SkEndian_SwapBE32(header.fDir[i].fLength);
     183             :             // now sanity check the caller's offset/length
     184           0 :             if (offset >= realLength) {
     185           0 :                 return 0;
     186             :             }
     187             :             // if the caller is trusting the length from the file, then a
     188             :             // hostile file might choose a value which would overflow offset +
     189             :             // length.
     190           0 :             if (offset + length < offset) {
     191           0 :                 return 0;
     192             :             }
     193           0 :             if (length > realLength - offset) {
     194           0 :                 length = realLength - offset;
     195             :             }
     196           0 :             if (data) {
     197             :                 // skip the stream to the part of the table we want to copy from
     198           0 :                 stream->rewind();
     199           0 :                 size_t bytesToSkip = realOffset + offset;
     200           0 :                 if (!skip(stream, bytesToSkip)) {
     201           0 :                     return 0;
     202             :                 }
     203           0 :                 if (!read(stream, data, length)) {
     204           0 :                     return 0;
     205             :                 }
     206             :             }
     207           0 :             return length;
     208             :         }
     209             :     }
     210           0 :     return 0;
     211             : }

Generated by: LCOV version 1.13