qmk_firmware

QMK firmware for my keyboards (Corne, Sweep Ferris) and trackball (Ploopy Adept)
Log | Files | Refs | Submodules | LICENSE

qff.c (5106B)


      1 // Copyright 2021 Nick Brassel (@tzarc)
      2 // SPDX-License-Identifier: GPL-2.0-or-later
      3 
      4 // Quantum Font File "QFF" File Format.
      5 // See https://docs.qmk.fm/#/quantum_painter_qff for more information.
      6 
      7 #include "qff.h"
      8 #include "qp_draw.h"
      9 
     10 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
     11 // QFF API
     12 
     13 bool qff_read_font_descriptor(qp_stream_t *stream, uint8_t *line_height, bool *has_ascii_table, uint16_t *num_unicode_glyphs, uint8_t *bpp, bool *has_palette, bool *is_panel_native, painter_compression_t *compression_scheme, uint32_t *total_bytes) {
     14     // Seek to the start
     15     qp_stream_setpos(stream, 0);
     16 
     17     // Read and validate the font descriptor
     18     qff_font_descriptor_v1_t font_descriptor;
     19     if (qp_stream_read(&font_descriptor, sizeof(qff_font_descriptor_v1_t), 1, stream) != 1) {
     20         qp_dprintf("Failed to read font_descriptor, expected length was not %d\n", (int)sizeof(qff_font_descriptor_v1_t));
     21         return false;
     22     }
     23 
     24     // Make sure this block is valid
     25     if (!qgf_validate_block_header(&font_descriptor.header, QFF_FONT_DESCRIPTOR_TYPEID, (sizeof(qff_font_descriptor_v1_t) - sizeof(qgf_block_header_v1_t)))) {
     26         return false;
     27     }
     28 
     29     // Make sure the magic and version are correct
     30     if (font_descriptor.magic != QFF_MAGIC || font_descriptor.qff_version != 0x01) {
     31         qp_dprintf("Failed to validate font_descriptor, expected magic 0x%06X was 0x%06X, expected version = 0x%02X was 0x%02X\n", (int)QFF_MAGIC, (int)font_descriptor.magic, (int)0x01, (int)font_descriptor.qff_version);
     32         return false;
     33     }
     34 
     35     // Make sure the file length is valid
     36     if (font_descriptor.neg_total_file_size != ~font_descriptor.total_file_size) {
     37         qp_dprintf("Failed to validate font_descriptor, expected negated length 0x%08X was 0x%08X\n", (int)(~font_descriptor.total_file_size), (int)font_descriptor.neg_total_file_size);
     38         return false;
     39     }
     40 
     41     // Copy out the required info
     42     if (line_height) {
     43         *line_height = font_descriptor.line_height;
     44     }
     45     if (has_ascii_table) {
     46         *has_ascii_table = font_descriptor.has_ascii_table;
     47     }
     48     if (num_unicode_glyphs) {
     49         *num_unicode_glyphs = font_descriptor.num_unicode_glyphs;
     50     }
     51     if (bpp || has_palette) {
     52         if (!qgf_parse_format(font_descriptor.format, bpp, has_palette, is_panel_native)) {
     53             return false;
     54         }
     55     }
     56     if (compression_scheme) {
     57         *compression_scheme = font_descriptor.compression_scheme;
     58     }
     59     if (total_bytes) {
     60         *total_bytes = font_descriptor.total_file_size;
     61     }
     62 
     63     return true;
     64 }
     65 
     66 static bool qff_validate_ascii_descriptor(qp_stream_t *stream) {
     67     // Read the raw descriptor
     68     qff_ascii_glyph_table_v1_t ascii_descriptor;
     69     if (qp_stream_read(&ascii_descriptor, sizeof(qff_ascii_glyph_table_v1_t), 1, stream) != 1) {
     70         qp_dprintf("Failed to read ascii_descriptor, expected length was not %d\n", (int)sizeof(qff_ascii_glyph_table_v1_t));
     71         return false;
     72     }
     73 
     74     // Make sure this block is valid
     75     if (!qgf_validate_block_header(&ascii_descriptor.header, QFF_ASCII_GLYPH_DESCRIPTOR_TYPEID, (sizeof(qff_ascii_glyph_table_v1_t) - sizeof(qgf_block_header_v1_t)))) {
     76         return false;
     77     }
     78 
     79     return true;
     80 }
     81 
     82 static bool qff_validate_unicode_descriptor(qp_stream_t *stream, uint16_t num_unicode_glyphs) {
     83     // Read the raw descriptor
     84     qff_unicode_glyph_table_v1_t unicode_descriptor;
     85     if (qp_stream_read(&unicode_descriptor, sizeof(qff_unicode_glyph_table_v1_t), 1, stream) != 1) {
     86         qp_dprintf("Failed to read unicode_descriptor, expected length was not %d\n", (int)sizeof(qff_unicode_glyph_table_v1_t));
     87         return false;
     88     }
     89 
     90     // Make sure this block is valid
     91     if (!qgf_validate_block_header(&unicode_descriptor.header, QFF_UNICODE_GLYPH_DESCRIPTOR_TYPEID, num_unicode_glyphs * 6)) {
     92         return false;
     93     }
     94 
     95     // Skip the necessary amount of data to get to the next block
     96     qp_stream_seek(stream, num_unicode_glyphs * sizeof(qff_unicode_glyph_v1_t), SEEK_CUR);
     97 
     98     return true;
     99 }
    100 
    101 bool qff_validate_stream(qp_stream_t *stream) {
    102     bool     has_ascii_table;
    103     uint16_t num_unicode_glyphs;
    104 
    105     if (!qff_read_font_descriptor(stream, NULL, &has_ascii_table, &num_unicode_glyphs, NULL, NULL, NULL, NULL, NULL)) {
    106         return false;
    107     }
    108 
    109     if (has_ascii_table) {
    110         if (!qff_validate_ascii_descriptor(stream)) {
    111             return false;
    112         }
    113     }
    114 
    115     if (num_unicode_glyphs > 0) {
    116         if (!qff_validate_unicode_descriptor(stream, num_unicode_glyphs)) {
    117             return false;
    118         }
    119     }
    120 
    121     return true;
    122 }
    123 
    124 uint32_t qff_get_total_size(qp_stream_t *stream) {
    125     // Get the original location
    126     uint32_t oldpos = qp_stream_tell(stream);
    127 
    128     // Read the font descriptor, grabbing the size
    129     uint32_t total_size;
    130     if (!qff_read_font_descriptor(stream, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &total_size)) {
    131         return false;
    132     }
    133 
    134     // Restore the original location
    135     qp_stream_setpos(stream, oldpos);
    136     return total_size;
    137 }