Чтение «таблиц» в C ++

0

В настоящее время я смотрю на спецификацию TTF и замечаю, что он довольно много говорит о "таблицах". Я понимаю, что эти таблицы являются представлением структуры данных, однако через мой поиск в Google я не нашел объяснений относительно того, как я могу извлечь эти данные из моего файла TTF, как я могу выяснить, сколько символов занимает каждая таблица, как определить одну таблицу из другой, как я могу определить каждую часть данных в каждой таблице...

В настоящее время все, что я знаю, это то, что мне дается тип данных каждой части информации (например, здесь), которая может помочь мне определить каждую часть данных в таблице, но это возвращается к проблеме не понимания того, как определить расположение самих таблиц в файле.

Если бы кто-нибудь мог объяснить теорию о том, как это работает, или показать короткие, но хорошо прокомментированные фрагменты кода, чтобы помочь мне понять это лучше, это было бы очень признательно.

Теги:
c++11
data-structures

2 ответа

1

Первый подход заключается в тщательном изучении упомянутой документации Apple, содержащей описания структур данных. Также вы можете взглянуть на libfreetype и узнать, как эти структуры данных обрабатываются в реальном коде.

0

user3159253 совершенно правильно - сам документ, на который вы ссылаетесь, предоставляет всю необходимую вам информацию... например:

Обратите внимание, что searchRange, entrySelector и rangeShift все умножаются на 16, что представляет собой размер записи в каталоге.

Таблица 4: Смещенная подзаголовок

Type    Name    Description
uint32  scaler type     A tag to indicate the OFA scaler to be used to rasterize this font; see the note on the scaler type below for more information.
uint16  numTables   number of tables
uint16  searchRange     (maximum power of 2 <= numTables)*16
uint16  entrySelector   log2(maximum power of 2 <= numTables)
uint16  rangeShift  numTables*16-searchRange

Ваш связанный код может выглядеть примерно так:

struct Offset_Subtable;
{
    uint32 scaler_type_;
    uint16 numTables_;
    uint16 searchRange_;
    uint16 entrySelector_;
    uint16 rangeShift_;

    bool is_for_macOS() { return scaler_type_ == 0x74727565; }
    bool is_for_windoes() { return scaler_type_ == 0x00010000; }
    bool is_truetype() { return scaler_type_ == 0x74727565 ||
                         scaler_type_ == 0x00010000; }
    bool is_postscript() { return scaler_type_ == 0x74797031; }
};

Данный:

Таблица 5: Каталог таблиц

Type    Name    Description
uint32  tag     4-byte identifier
uint32  checkSum    checksum for this table
uint32  offset  offset from beginning of sfnt
uint32  length  length of this table in byte (actual length not padded length)

Вы можете сохранить кодировку:

struct Table_Directory_Entry
{
    uint32 tag_;
    uint32 checkSum_;
    uint32 offset_;
    uint32 length_;
};

const void* p_ttf = ...;
const Offset_Subtable* p_os = static_cast<const Offset_Subtable*>(p_ttf);
... use any data you're interested in...
for (int table_num = 1; table_num <= p_os->numTables_; ++table_num)
{
    const Table_Directory_Entry* p_tde =
        reinterpret_cast<const Table_Directory_Entry*>(&p_os[1]);
    ... use the table directory entry data ...
}

...и т.д....

Теперь некоторые из необработанных данных довольно запутывают ("волшебные" значения дозорного значения, целые числа, где вы предпочитаете видеть результаты как значения из enum, числа, которые необходимо умножить или разделить или смещать, чтобы получить значение, которое кто-то может интуитивно ожидать их сохранение), поэтому добавление небольших вспомогательных функций, таких как is_truetype() является хорошим началом, и вы можете пойти немного дальше, предотвратив использование необработанных полей, сделав их private при экспонировании is_truetype() и других функций public member.

Если вам нужны ваши структуры, чтобы иметь дополнительные данные, которые не являются частью содержимого TTF, тогда этот подход отбрасывания необработанных данных в вашу структуру, чтобы помочь вам разобрать/интерпретировать, ломается. Вместо этого вы можете использовать одну из этих структур с необработанными данными для удобной интерпретации необработанной памяти, поддерживая класс более высокого уровня, созданный в стеке или куче или в глобальной/статической области, который инициализирует себя указателем или ссылкой к структуре необработанных данных. Это может быть сделано в конструкторе, операторе присваивания, потоковом operator>> или любой общей функции-члена - все, что вы найдете, соответствует вашему коду. Затем вы можете вытащить и сохранить анализируемые данные в стандартных контейнерах и т.д.

  • 0
    Я должен отметить, что перевод описанных структур данных непосредственно в структуру C не совсем безопасен: вы неизбежно сталкиваетесь с проблемами выравнивания / заполнения данных и endiannes. #pragma pack и __attribute__((packed)) помогают, но не всегда. Таким образом, эти структуры должны использоваться, только если вы абсолютно уверены в архитектуре целевой платформы и других предпочтениях

Ещё вопросы

Сообщество Overcoder
Наверх
Меню