gfx/ots/src/name.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2011 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.
     5 #include "name.h"
     7 #include <algorithm>
     8 #include <cstring>
    10 #include "cff.h"
    12 // name - Naming Table
    13 // http://www.microsoft.com/typography/otspec/name.htm
    15 #define TABLE_NAME "name"
    17 namespace {
    19 bool ValidInPsName(char c) {
    20   return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c));
    21 }
    23 bool CheckPsNameAscii(const std::string& name) {
    24   for (unsigned i = 0; i < name.size(); ++i) {
    25     if (!ValidInPsName(name[i])) {
    26       return false;
    27     }
    28   }
    29   return true;
    30 }
    32 bool CheckPsNameUtf16Be(const std::string& name) {
    33   if ((name.size() & 1) != 0)
    34     return false;
    36   for (unsigned i = 0; i < name.size(); i += 2) {
    37     if (name[i] != 0) {
    38       return false;
    39     }
    40     if (!ValidInPsName(name[i+1])) {
    41       return false;
    42     }
    43   }
    44   return true;
    45 }
    47 void AssignToUtf16BeFromAscii(std::string* target,
    48                               const std::string& source) {
    49   target->resize(source.size() * 2);
    50   for (unsigned i = 0, j = 0; i < source.size(); i++) {
    51     (*target)[j++] = '\0';
    52     (*target)[j++] = source[i];
    53   }
    54 }
    56 }  // namespace
    59 namespace ots {
    61 bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
    62   Buffer table(data, length);
    64   OpenTypeNAME* name = new OpenTypeNAME;
    65   file->name = name;
    67   uint16_t format = 0;
    68   if (!table.ReadU16(&format) || format > 1) {
    69     return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
    70   }
    72   uint16_t count = 0;
    73   if (!table.ReadU16(&count)) {
    74     return OTS_FAILURE_MSG("Failed to read name count");
    75   }
    77   uint16_t string_offset = 0;
    78   if (!table.ReadU16(&string_offset) || string_offset > length) {
    79     return OTS_FAILURE_MSG("Failed to read strings offset");
    80   }
    81   const char* string_base = reinterpret_cast<const char*>(data) +
    82       string_offset;
    84   NameRecord prev_record;
    85   bool sort_required = false;
    87   // Read all the names, discarding any with invalid IDs,
    88   // and any where the offset/length would be outside the table.
    89   // A stricter alternative would be to reject the font if there
    90   // are invalid name records, but it's not clear that is necessary.
    91   for (unsigned i = 0; i < count; ++i) {
    92     NameRecord rec;
    93     uint16_t name_length, name_offset;
    94     if (!table.ReadU16(&rec.platform_id) ||
    95         !table.ReadU16(&rec.encoding_id) ||
    96         !table.ReadU16(&rec.language_id) ||
    97         !table.ReadU16(&rec.name_id) ||
    98         !table.ReadU16(&name_length) ||
    99         !table.ReadU16(&name_offset)) {
   100       return OTS_FAILURE_MSG("Failed to read name entry %d", i);
   101     }
   102     // check platform & encoding, discard names with unknown values
   103     switch (rec.platform_id) {
   104       case 0:  // Unicode
   105         if (rec.encoding_id > 6) {
   106           continue;
   107         }
   108         break;
   109       case 1:  // Macintosh
   110         if (rec.encoding_id > 32) {
   111           continue;
   112         }
   113         break;
   114       case 2:  // ISO
   115         if (rec.encoding_id > 2) {
   116           continue;
   117         }
   118         break;
   119       case 3:  // Windows: IDs 7 to 9 are "reserved"
   120         if (rec.encoding_id > 6 && rec.encoding_id != 10) {
   121           continue;
   122         }
   123         break;
   124       case 4:  // Custom (OTF Windows NT compatibility)
   125         if (rec.encoding_id > 255) {
   126           continue;
   127         }
   128         break;
   129       default:  // unknown platform
   130         continue;
   131     }
   133     const unsigned name_end = static_cast<unsigned>(string_offset) +
   134         name_offset + name_length;
   135     if (name_end > length) {
   136       continue;
   137     }
   138     rec.text.resize(name_length);
   139     rec.text.assign(string_base + name_offset, name_length);
   141     if (rec.name_id == 6) {
   142       // PostScript name: check that it is valid, if not then discard it
   143       if (rec.platform_id == 1) {
   144         if (file->cff && !file->cff->name.empty()) {
   145           rec.text = file->cff->name;
   146         } else if (!CheckPsNameAscii(rec.text)) {
   147           continue;
   148         }
   149       } else if (rec.platform_id == 0 || rec.platform_id == 3) {
   150         if (file->cff && !file->cff->name.empty()) {
   151           AssignToUtf16BeFromAscii(&rec.text, file->cff->name);
   152         } else if (!CheckPsNameUtf16Be(rec.text)) {
   153           continue;
   154         }
   155       }
   156     }
   158     if ((i > 0) && !(prev_record < rec)) {
   159       OTS_WARNING("name records are not sorted.");
   160       sort_required = true;
   161     }
   163     name->names.push_back(rec);
   164     prev_record = rec;
   165   }
   167   if (format == 1) {
   168     // extended name table format with language tags
   169     uint16_t lang_tag_count;
   170     if (!table.ReadU16(&lang_tag_count)) {
   171       return OTS_FAILURE_MSG("Failed to read language tag count");
   172     }
   173     for (unsigned i = 0; i < lang_tag_count; ++i) {
   174       uint16_t tag_length = 0;
   175       uint16_t tag_offset = 0;
   176       if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
   177         return OTS_FAILURE_MSG("Faile to read tag length or offset");
   178       }
   179       const unsigned tag_end = static_cast<unsigned>(string_offset) +
   180           tag_offset + tag_length;
   181       if (tag_end > length) {
   182         return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i);
   183       }
   184       std::string tag(string_base + tag_offset, tag_length);
   185       name->lang_tags.push_back(tag);
   186     }
   187   }
   189   if (table.offset() > string_offset) {
   190     // the string storage apparently overlapped the name/tag records;
   191     // consider this font to be badly broken
   192     return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset);
   193   }
   195   // check existence of required name strings (synthesize if necessary)
   196   //  [0 - copyright - skip]
   197   //   1 - family
   198   //   2 - subfamily
   199   //  [3 - unique ID - skip]
   200   //   4 - full name
   201   //   5 - version
   202   //   6 - postscript name
   203   static const unsigned kStdNameCount = 7;
   204   static const char* kStdNames[kStdNameCount] = {
   205     NULL,
   206     "OTS derived font",
   207     "Unspecified",
   208     NULL,
   209     "OTS derived font",
   210     "1.000",
   211     "OTS-derived-font"
   212   };
   213   // The spec says that "In CFF OpenType fonts, these two name strings, when
   214   // translated to ASCII, must also be identical to the font name as stored in
   215   // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
   216   if (file->cff && !file->cff->name.empty()) {
   217     kStdNames[6] = file->cff->name.c_str();
   218   }
   220   // scan the names to check whether the required "standard" ones are present;
   221   // if not, we'll add our fixed versions here
   222   bool mac_name[kStdNameCount] = { 0 };
   223   bool win_name[kStdNameCount] = { 0 };
   224   for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
   225        name_iter != name->names.end(); name_iter++) {
   226     const uint16_t id = name_iter->name_id;
   227     if (id >= kStdNameCount || kStdNames[id] == NULL) {
   228       continue;
   229     }
   230     if (name_iter->platform_id == 1) {
   231       mac_name[id] = true;
   232       continue;
   233     }
   234     if (name_iter->platform_id == 3) {
   235       win_name[id] = true;
   236       continue;
   237     }
   238   }
   240   for (unsigned i = 0; i < kStdNameCount; ++i) {
   241     if (kStdNames[i] == NULL) {
   242       continue;
   243     }
   244     if (!mac_name[i]) {
   245       NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
   246                      0 /* language_id */ , i /* name_id */);
   247       rec.text.assign(kStdNames[i]);
   248       name->names.push_back(rec);
   249       sort_required = true;
   250     }
   251     if (!win_name[i]) {
   252       NameRecord rec(3 /* platform_id */, 1 /* encoding_id */,
   253                      1033 /* language_id */ , i /* name_id */);
   254       AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i]));
   255       name->names.push_back(rec);
   256       sort_required = true;
   257     }
   258   }
   260   if (sort_required) {
   261     std::sort(name->names.begin(), name->names.end());
   262   }
   264   return true;
   265 }
   267 bool ots_name_should_serialise(OpenTypeFile* file) {
   268   return file->name != NULL;
   269 }
   271 bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
   272   const OpenTypeNAME* name = file->name;
   274   uint16_t name_count = name->names.size();
   275   uint16_t lang_tag_count = name->lang_tags.size();
   276   uint16_t format = 0;
   277   size_t string_offset = 6 + name_count * 12;
   279   if (name->lang_tags.size() > 0) {
   280     // lang tags require a format-1 name table
   281     format = 1;
   282     string_offset += 2 + lang_tag_count * 4;
   283   }
   284   if (string_offset > 0xffff) {
   285     return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
   286   }
   287   if (!out->WriteU16(format) ||
   288       !out->WriteU16(name_count) ||
   289       !out->WriteU16(string_offset)) {
   290     return OTS_FAILURE_MSG("Failed to write name header");
   291   }
   293   std::string string_data;
   294   for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
   295        name_iter != name->names.end(); name_iter++) {
   296     const NameRecord& rec = *name_iter;
   297     if (!out->WriteU16(rec.platform_id) ||
   298         !out->WriteU16(rec.encoding_id) ||
   299         !out->WriteU16(rec.language_id) ||
   300         !out->WriteU16(rec.name_id) ||
   301         !out->WriteU16(rec.text.size()) ||
   302         !out->WriteU16(string_data.size()) ) {
   303       return OTS_FAILURE_MSG("Faile to write name entry");
   304     }
   305     string_data.append(rec.text);
   306   }
   308   if (format == 1) {
   309     if (!out->WriteU16(lang_tag_count)) {
   310       return OTS_FAILURE_MSG("Faile to write language tag count");
   311     }
   312     for (std::vector<std::string>::const_iterator tag_iter =
   313              name->lang_tags.begin();
   314          tag_iter != name->lang_tags.end(); tag_iter++) {
   315       if (!out->WriteU16(tag_iter->size()) ||
   316           !out->WriteU16(string_data.size())) {
   317         return OTS_FAILURE_MSG("Failed to write string");
   318       }
   319       string_data.append(*tag_iter);
   320     }
   321   }
   323   if (!out->Write(string_data.data(), string_data.size())) {
   324     return OTS_FAILURE_MSG("Faile to write string data");
   325   }
   327   return true;
   328 }
   330 void ots_name_free(OpenTypeFile* file) {
   331   delete file->name;
   332 }
   334 }  // namespace

mercurial