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 }