Advertisement
Guest User

basic TTF structs/parser

a guest
Nov 29th, 2014
226
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.53 KB | None | 0 0
  1. // copyright 2014 "aciddose"
  2. // made available under "DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE Version 2, December 2004"
  3. // see: http://www.wtfpl.net/about/
  4.  
  5. //        DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  6. //                    Version 2, December 2004
  7. //
  8. // Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
  9. //
  10. // Everyone is permitted to copy and distribute verbatim or modified
  11. // copies of this license document, and changing it is allowed as long
  12. // as the name is changed.
  13. //
  14. //            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
  15. //   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  16. //
  17. //  0. You just DO WHAT THE FUCK YOU WANT TO.
  18.  
  19. // I modified the license text by inserting it in a comment. Arch-Rebel.
  20.  
  21. #include <stdio.h>
  22. #include <stdint.h>
  23.  
  24. #include <vector>
  25. #include <fstream>
  26.  
  27. #include <assert.h>
  28.  
  29. // yes, this code is "terrific".
  30. // no, not the modern slang. the literal definition of "terrific".
  31. // "terrific": 2. archaic: causing terror.
  32. // fix it if you don't like it, smart guy.
  33.  
  34. struct file : public std::vector<char>
  35. {
  36.     file(const char *filename)
  37.     {
  38.         std::ifstream f(filename, std::ifstream::binary);
  39.         if (f.is_open()) {
  40.             f.seekg(0, std::ios::end);
  41.             resize(size_t(f.tellg()));
  42.             f.seekg(0, std::ios::beg);
  43.             f.read(data(), size());
  44.             name = filename;
  45.         } else {
  46.             printf("failure loading file: %s\n", filename);
  47.             assert(false);
  48.         }
  49.     }
  50.  
  51.     void write(const char *filename)
  52.     {
  53.         std::ofstream f(filename, std::ofstream::binary);
  54.         if (f.is_open()) {
  55.             f.write(data(), size());
  56.         } else {
  57.             printf("failure writing file: %s\n", filename);
  58.             assert(false);
  59.         }
  60.     }
  61.  
  62.     const char *get_name() const
  63.     {
  64.         return name.c_str();
  65.     }
  66.  
  67. private:
  68.  
  69.     std::string name;
  70. };
  71.  
  72. namespace ttf
  73. {
  74.     typedef uint32_t u32;
  75.     typedef uint16_t u16;
  76.     typedef uint8_t  u08;
  77.  
  78.     u32 swap(const u32 x)
  79.     {
  80.         return ((x >> 24) | ((x & 0x00FF0000) >> 8) | ((x & 0x0000FF00) << 8) | (x << 24));
  81.     }
  82.  
  83.     u16 swap(const u16 x)
  84.     {
  85.         return ((x >> 8) | (x << 8));
  86.     }
  87.  
  88.     struct header_t
  89.     {
  90.         void print(const char *indent) const;
  91.  
  92.         u32 version;
  93.         u16 tables;
  94.         u16 search;
  95.         u16 select;
  96.         u16 shift;
  97.     };
  98.  
  99.     struct index_t
  100.     {
  101.         u08 id[4];
  102.         u32 checksum;
  103.         u32 offset;
  104.         u32 length;
  105.     };
  106.  
  107.     typedef std::vector<index_t *> directory_index;
  108.  
  109.     struct gasp_t
  110.     {
  111.         static void print(const char *indent, const char *p, int offset, int length)
  112.         {
  113.             const gasp_t *t = (gasp_t *)(p + offset);
  114.             t->print(indent);
  115.         }
  116.  
  117.         struct range_t
  118.         {
  119.             const char *get_behavior_string() const
  120.             {
  121.                 static const char *str[] =
  122.                 {
  123.                     "none", "grid fit", "smoothing", "grid fit + smoothing",
  124.                     "symmetric grid fit", 0, 0, 0,
  125.                     "symmetric smoothing", 0, 0, 0,
  126.                     "symmetric grid fit + smoothing", 0, 0, 0,
  127.                 };
  128.  
  129.                 const int i = swap(behavior);
  130.  
  131.                 return (i >= 0 && i < 16 ? str[i] : "out of range behavior flag");
  132.             }
  133.  
  134.             u16 max_ppem;
  135.             u16 behavior;
  136.         };
  137.  
  138.         const range_t &get_range(int i) const
  139.         {
  140.             assert(i >= 0);
  141.             assert(i < swap(ranges));
  142.             range_t *range = (range_t *)(this + 1);
  143.             return range[i];
  144.         }
  145.  
  146.         void print(const char *indent) const;
  147.  
  148.         u16 version;
  149.         u16 ranges;
  150.     };
  151.  
  152.     struct table_dat_t
  153.     {
  154.         typedef void(*print_table_func)(const char *indent, const char *p, int offset, int length);
  155.         table_dat_t(const char *_id, const char *_desc, print_table_func _ptfunc = 0) :
  156.             id(_id),
  157.             description(_desc),
  158.             print_table(_ptfunc)
  159.         {
  160.         }
  161.  
  162.         const char *id;
  163.         const char *description;
  164.         print_table_func print_table;
  165.     };
  166.  
  167.     // do these strings cause any issue with copyright?
  168.     // if so i suppose we can change these to various flavors
  169.     // of cheese. although as descriptions of fact, i suspect not.
  170.     table_dat_t tables[] =
  171.     {
  172.         // "required tables"
  173.         table_dat_t("cmap", "character to glyph mapping"),
  174.         table_dat_t("glyf", "glyph data"),
  175.         table_dat_t("head", "font header"),
  176.         table_dat_t("hhea", "horizontal header"),
  177.         table_dat_t("hmtx", "horizontal metrics"),
  178.         table_dat_t("loca", "index to location"),
  179.         table_dat_t("maxp", "maximum profile"),
  180.         table_dat_t("name", "naming"),
  181.         table_dat_t("post", "postscript information"),
  182.         table_dat_t("OS/2", "os/2 & windows specific metrics"),
  183.  
  184.         // "optional tables"
  185.         table_dat_t("cvt ", "control values"),
  186.         table_dat_t("EBDT", "bitmap data"),
  187.         table_dat_t("EBLC", "bitmap location"),
  188.         table_dat_t("EBSC", "bitmap scaling"),
  189.         table_dat_t("fpgm", "font program"),
  190.         table_dat_t("gasp", "grid-fitting and scan conversion procedure", &gasp_t::print),
  191.         table_dat_t("hdmx", "horizontal device metrics"),
  192.         table_dat_t("kern", "kerning"),
  193.         table_dat_t("LTSH", "linear thresholds"),
  194.         table_dat_t("prep", "CVT program"),
  195.         table_dat_t("PCLT", "PCL5"),
  196.         table_dat_t("VDMX", "vertical device metrics"),
  197.         table_dat_t("vhea", "vertical metrics header"),
  198.         table_dat_t("vmtx", "vertical metrics"),
  199.         table_dat_t(0, 0),
  200.     };
  201.  
  202.     table_dat_t *find_table_dat(std::string id)
  203.     {
  204.         for (int i = 0; tables[i].id; i++) {
  205.             if (id.compare(tables[i].id) == 0) {
  206.                 return &tables[i];
  207.             }
  208.         }
  209.  
  210.         return 0;
  211.     }
  212.  
  213. #if 1
  214.     // this is hopefully a proper replacement
  215.     // which operates entirely within length
  216.     u32 checksum(const char *p, int length)
  217.     {
  218.         const u08 *table = (u08 *)p;
  219.         u32 sum = 0;
  220.         u32 data = 0;
  221.         int i = 0;
  222.         for (; i < length; i++) {
  223.             data = (data << 8) | table[i];
  224.             if ((i & 3) == 3) {
  225.                 sum += data;
  226.                 data = 0;
  227.             }
  228.         }
  229.  
  230.         // zero pad the remaining bytes
  231.         //ad::u32 good_data = swap(*(ad::u32 *)&table[i&~3]);
  232.         sum += data << (8 * (4 - (length & 3)));
  233.  
  234.         return sum;
  235.     }
  236. #else
  237.     // this method is "dumb" in that it may access data outside the specified 'length'.
  238.     // to work at all, relies upon chunks being aligned and padded to dwords.
  239.     u32 checksum(const char *p, int length)
  240.     {
  241.         const u32 *table = (u32 *)p;
  242.         const u32 *end = table + ((length + 3) & ~3) / sizeof(u32);
  243.         u32 sum = 0;
  244.         while (table < end) {
  245.             sum += swap(*table++);
  246.         }
  247.         return sum;
  248.     }
  249. #endif
  250. };
  251.  
  252. void ttf::header_t::print(const char *indent) const
  253. {
  254.     printf("%sversion %i.%i\n", indent, version>>8, version&0xFF);
  255.     printf("%stables %i\n",     indent, swap(tables));
  256.     printf("%ssearch %i\n",     indent, swap(search));
  257.     printf("%sselect %i\n",     indent, swap(select));
  258.     printf("%sshift %i\n",      indent, swap(shift));
  259. }
  260.  
  261. void ttf::gasp_t::print(const char *indent) const
  262. {
  263.     printf("%sversion %i\n", indent, swap(version));
  264.     printf("%sranges %i\n", indent, swap(ranges));
  265.  
  266.     const int _ranges = swap(ranges);
  267.     for (int i = 0; i < _ranges; i++) {
  268.         const gasp_t::range_t &range = get_range(i);
  269.  
  270.         // force to anti-aliasing
  271.         //range.behavior = 3;
  272.         const int max_ppem = swap(range.max_ppem);
  273.  
  274.         printf("%s\t%i: %-5i %s\n", indent, i + 1, max_ppem, range.get_behavior_string());
  275.     }
  276. }
  277.  
  278. void print_directory(ttf::directory_index &directory, const char *data_start)
  279. {
  280.     for (unsigned int i = 0; i < directory.size(); i++) {
  281.         ttf::index_t *dir = directory[i];
  282.  
  283.         char *id = (char *)&dir->id;
  284.         char id_string[8];
  285.         for (int j = 0; j < 4; j++) {
  286.             id_string[j] = id[j];
  287.         }
  288.         id_string[4] = 0;
  289.  
  290.         const int offset = ttf::swap(dir->offset);
  291.         const int length = ttf::swap(dir->length);
  292.  
  293.         printf("\t%-2i '%s' %-8i %-8i", i + 1, id_string, offset, length);
  294.  
  295.         ttf::table_dat_t *table_dat = ttf::find_table_dat(id_string);
  296.         if (table_dat) {
  297.             printf(" %s", table_dat->description);
  298.         }
  299.  
  300.         printf("\n");
  301.  
  302.         ttf::u32 checksum = ttf::swap(dir->checksum);
  303.         ttf::u32 calculated_checksum = ttf::checksum(data_start + offset, length);
  304.         if (checksum != calculated_checksum) {
  305.             printf("\tBAD CHECKSUM\n\n");
  306.             dir->checksum = ttf::swap(calculated_checksum);
  307.         }
  308.     }
  309. }
  310.  
  311. void print_table(const char *id, ttf::directory_index &directory, const char *data_start)
  312. {
  313.     ttf::index_t *dir = 0;
  314.  
  315.     for (unsigned int i = 0; i < directory.size(); i++) {
  316.         if (!memcmp(&directory[i]->id, id, 4)) {
  317.             dir = directory[i];
  318.             break;
  319.         }
  320.     }
  321.  
  322.     if (dir) {
  323.         printf("'%s' table:\n", id);
  324.         ttf::table_dat_t *table_dat = ttf::find_table_dat(id);
  325.         if (table_dat && table_dat->print_table) {
  326.             table_dat->print_table("\t", data_start, ttf::swap(dir->offset), ttf::swap(dir->length));
  327.         } else {
  328.             printf("\tno function specified to print this table type\n");
  329.         }
  330.     } else {
  331.         printf("couldn't locate '%s' table in directory\n", id);
  332.     }
  333. }
  334.  
  335. void read_ttf(const char *ttf_filename)
  336. {
  337.     using namespace ttf;
  338.  
  339.     file ttf(ttf_filename);
  340.  
  341.     printf("%s (%i bytes)\n\n", ttf.get_name(), ttf.size());
  342.  
  343.     if (ttf.size()) {
  344.         char *data = ttf.data();
  345.         ttf::header_t *head = (header_t *)data;
  346.  
  347.         const int version = swap(head->version);
  348.         const int tables = swap(head->tables);
  349.  
  350.         printf("header:\n");
  351.         head->print("\t");
  352.         printf("\n");
  353.  
  354.         // populate table directory
  355.         ttf::index_t *pdir = (index_t *)(head + 1);
  356.         ttf::directory_index directory(tables);
  357.         for (int i = 0; i < tables; i++) {
  358.             directory[i] = &pdir[i];
  359.         }
  360.  
  361.         printf("directory:\n");
  362.         print_directory(directory, data);
  363.         printf("\n");
  364.  
  365.         print_table("gasp", directory, data);
  366.         printf("\n");
  367.  
  368.         print_table("name", directory, data);
  369.         printf("\n");
  370.  
  371. #if write_to_modified
  372.         char filename[1024];
  373.         strcpy(filename, ttf.get_name());
  374.         char *path = strrchr(filename, '/');
  375.         path = path ? path+1 : filename;
  376.         const char *file = strrchr(ttf.get_name(), '/');
  377.         file = file ? file+1 : ttf.get_name();
  378.         if (path && file) {
  379.             strcpy(path, "modified");
  380.             //_mkdir(filename);
  381.             strcat(path, "/");
  382.             strcat(path, file);
  383.             ttf.write(filename);
  384.         }
  385. #endif
  386.     }
  387.  
  388.     printf("\n");
  389. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement