Home | History | Annotate | Download | only in src
      1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "post.h"
      6 
      7 #include "maxp.h"
      8 
      9 // post - PostScript
     10 // http://www.microsoft.com/opentype/otspec/post.htm
     11 
     12 namespace ots {
     13 
     14 bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
     15   Buffer table(data, length);
     16 
     17   OpenTypePOST *post = new OpenTypePOST;
     18   file->post = post;
     19 
     20   if (!table.ReadU32(&post->version) ||
     21       !table.ReadU32(&post->italic_angle) ||
     22       !table.ReadS16(&post->underline) ||
     23       !table.ReadS16(&post->underline_thickness) ||
     24       !table.ReadU32(&post->is_fixed_pitch)) {
     25     return OTS_FAILURE();
     26   }
     27 
     28   if (post->underline_thickness < 0) {
     29     post->underline_thickness = 1;
     30   }
     31 
     32   if (post->version == 0x00010000) {
     33     return true;
     34   } else if (post->version == 0x00030000) {
     35     return true;
     36   } else if (post->version != 0x00020000) {
     37     // 0x00025000 is deprecated. We don't accept it.
     38     return OTS_FAILURE();
     39   }
     40 
     41   // We have a version 2 table with a list of Pascal strings at the end
     42 
     43   // We don't care about the memory usage fields. We'll set all these to zero
     44   // when serialising
     45   if (!table.Skip(16)) {
     46     return OTS_FAILURE();
     47   }
     48 
     49   uint16_t num_glyphs = 0;
     50   if (!table.ReadU16(&num_glyphs)) {
     51     return OTS_FAILURE();
     52   }
     53 
     54   if (!file->maxp) {
     55     return OTS_FAILURE();
     56   }
     57 
     58   if (num_glyphs == 0) {
     59     if (file->maxp->num_glyphs > 258) {
     60       return OTS_FAILURE();
     61     }
     62     OTS_WARNING("table version is 1, but no glyf names are found");
     63     // workaround for fonts in http://www.fontsquirrel.com/fontface
     64     // (e.g., yataghan.ttf).
     65     post->version = 0x00010000;
     66     return true;
     67   }
     68 
     69   if (num_glyphs != file->maxp->num_glyphs) {
     70     // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
     71     return OTS_FAILURE();
     72   }
     73 
     74   post->glyph_name_index.resize(num_glyphs);
     75   for (unsigned i = 0; i < num_glyphs; ++i) {
     76     if (!table.ReadU16(&post->glyph_name_index[i])) {
     77       return OTS_FAILURE();
     78     }
     79     if (post->glyph_name_index[i] >= 32768) {
     80       // Note: droid_arialuni.ttf fails this test.
     81       return OTS_FAILURE();  // reserved area.
     82     }
     83   }
     84 
     85   // Now we have an array of Pascal strings. We have to check that they are all
     86   // valid and read them in.
     87   const size_t strings_offset = table.offset();
     88   const uint8_t *strings = data + strings_offset;
     89   const uint8_t *strings_end = data + length;
     90 
     91   for (;;) {
     92     if (strings == strings_end) break;
     93     const unsigned string_length = *strings;
     94     if (strings + 1 + string_length > strings_end) {
     95       return OTS_FAILURE();
     96     }
     97     if (std::memchr(strings + 1, '\0', string_length)) {
     98       return OTS_FAILURE();
     99     }
    100     post->names.push_back(
    101         std::string(reinterpret_cast<const char*>(strings + 1), string_length));
    102     strings += 1 + string_length;
    103   }
    104   const unsigned num_strings = post->names.size();
    105 
    106   // check that all the references are within bounds
    107   for (unsigned i = 0; i < num_glyphs; ++i) {
    108     unsigned offset = post->glyph_name_index[i];
    109     if (offset < 258) {
    110       continue;
    111     }
    112 
    113     offset -= 258;
    114     if (offset >= num_strings) {
    115       return OTS_FAILURE();
    116     }
    117   }
    118 
    119   return true;
    120 }
    121 
    122 bool ots_post_should_serialise(OpenTypeFile *file) {
    123   return file->post != NULL;
    124 }
    125 
    126 bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
    127   const OpenTypePOST *post = file->post;
    128 
    129   // OpenType with CFF glyphs must have v3 post table.
    130   if (file->post && file->cff && file->post->version != 0x00030000) {
    131     return OTS_FAILURE();
    132   }
    133 
    134   if (!out->WriteU32(post->version) ||
    135       !out->WriteU32(post->italic_angle) ||
    136       !out->WriteS16(post->underline) ||
    137       !out->WriteS16(post->underline_thickness) ||
    138       !out->WriteU32(post->is_fixed_pitch) ||
    139       !out->WriteU32(0) ||
    140       !out->WriteU32(0) ||
    141       !out->WriteU32(0) ||
    142       !out->WriteU32(0)) {
    143     return OTS_FAILURE();
    144   }
    145 
    146   if (post->version != 0x00020000) {
    147     return true;  // v1.0 and v3.0 does not have glyph names.
    148   }
    149 
    150   if (!out->WriteU16(post->glyph_name_index.size())) {
    151     return OTS_FAILURE();
    152   }
    153 
    154   for (unsigned i = 0; i < post->glyph_name_index.size(); ++i) {
    155     if (!out->WriteU16(post->glyph_name_index[i])) {
    156       return OTS_FAILURE();
    157     }
    158   }
    159 
    160   // Now we just have to write out the strings in the correct order
    161   for (unsigned i = 0; i < post->names.size(); ++i) {
    162     const std::string& s = post->names[i];
    163     const uint8_t string_length = s.size();
    164     if (!out->Write(&string_length, 1)) {
    165       return OTS_FAILURE();
    166     }
    167     // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
    168     // We allow them.
    169     if (string_length > 0 && !out->Write(s.data(), string_length)) {
    170       return OTS_FAILURE();
    171     }
    172   }
    173 
    174   return true;
    175 }
    176 
    177 void ots_post_free(OpenTypeFile *file) {
    178   delete file->post;
    179 }
    180 
    181 }  // namespace ots
    182