logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

qgf.c (11601B)


  1. // Copyright 2021 Nick Brassel (@tzarc)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. // Quantum Graphics File "QGF" File Format.
  4. // See https://docs.qmk.fm/#/quantum_painter_qgf for more information.
  5. #include "qgf.h"
  6. #include "qp_draw.h"
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. // QGF API
  9. bool qgf_validate_block_header(qgf_block_header_v1_t *desc, uint8_t expected_typeid, int32_t expected_length) {
  10. if (desc->type_id != expected_typeid || desc->neg_type_id != ((~expected_typeid) & 0xFF)) {
  11. qp_dprintf("Failed to validate header, expected typeid 0x%02X, was 0x%02X, expected negated typeid 0x%02X, was 0x%02X\n", (int)expected_typeid, (int)desc->type_id, (int)((~desc->type_id) & 0xFF), (int)desc->neg_type_id);
  12. return false;
  13. }
  14. if (expected_length >= 0 && desc->length != expected_length) {
  15. qp_dprintf("Failed to validate header (typeid 0x%02X), expected length %d, was %d\n", (int)desc->type_id, (int)expected_length, (int)desc->length);
  16. return false;
  17. }
  18. return true;
  19. }
  20. bool qgf_parse_format(qp_image_format_t format, uint8_t *bpp, bool *has_palette, bool *is_panel_native) {
  21. // clang-format off
  22. static const struct QP_PACKED {
  23. uint8_t bpp;
  24. bool has_palette;
  25. bool is_panel_native;
  26. } formats[] = {
  27. [GRAYSCALE_1BPP] = {.bpp = 1, .has_palette = false, .is_panel_native = false},
  28. [GRAYSCALE_2BPP] = {.bpp = 2, .has_palette = false, .is_panel_native = false},
  29. [GRAYSCALE_4BPP] = {.bpp = 4, .has_palette = false, .is_panel_native = false},
  30. [GRAYSCALE_8BPP] = {.bpp = 8, .has_palette = false, .is_panel_native = false},
  31. [PALETTE_1BPP] = {.bpp = 1, .has_palette = true, .is_panel_native = false},
  32. [PALETTE_2BPP] = {.bpp = 2, .has_palette = true, .is_panel_native = false},
  33. [PALETTE_4BPP] = {.bpp = 4, .has_palette = true, .is_panel_native = false},
  34. [PALETTE_8BPP] = {.bpp = 8, .has_palette = true, .is_panel_native = false},
  35. [RGB565_16BPP] = {.bpp = 16, .has_palette = false, .is_panel_native = true},
  36. [RGB888_24BPP] = {.bpp = 24, .has_palette = false, .is_panel_native = true},
  37. };
  38. // clang-format on
  39. // Copy out the required info
  40. if (format > RGB888_24BPP) {
  41. qp_dprintf("Failed to parse frame_descriptor, invalid format 0x%02X\n", (int)format);
  42. return false;
  43. }
  44. // Copy out the required info
  45. if (bpp) {
  46. *bpp = formats[format].bpp;
  47. }
  48. if (has_palette) {
  49. *has_palette = formats[format].has_palette;
  50. }
  51. if (is_panel_native) {
  52. *is_panel_native = formats[format].is_panel_native;
  53. }
  54. return true;
  55. }
  56. bool qgf_parse_frame_descriptor(qgf_frame_v1_t *frame_descriptor, uint8_t *bpp, bool *has_palette, bool *is_panel_native, bool *is_delta, painter_compression_t *compression_scheme, uint16_t *delay) {
  57. // Decode the format
  58. qgf_parse_format(frame_descriptor->format, bpp, has_palette, is_panel_native);
  59. // Copy out the required info
  60. if (is_delta) {
  61. *is_delta = (frame_descriptor->flags & QGF_FRAME_FLAG_DELTA) == QGF_FRAME_FLAG_DELTA;
  62. }
  63. if (compression_scheme) {
  64. *compression_scheme = frame_descriptor->compression_scheme;
  65. }
  66. if (delay) {
  67. *delay = frame_descriptor->delay;
  68. }
  69. return true;
  70. }
  71. bool qgf_read_graphics_descriptor(qp_stream_t *stream, uint16_t *image_width, uint16_t *image_height, uint16_t *frame_count, uint32_t *total_bytes) {
  72. // Seek to the start
  73. qp_stream_setpos(stream, 0);
  74. // Read and validate the graphics descriptor
  75. qgf_graphics_descriptor_v1_t graphics_descriptor;
  76. if (qp_stream_read(&graphics_descriptor, sizeof(qgf_graphics_descriptor_v1_t), 1, stream) != 1) {
  77. qp_dprintf("Failed to read graphics_descriptor, expected length was not %d\n", (int)sizeof(qgf_graphics_descriptor_v1_t));
  78. return false;
  79. }
  80. // Make sure this block is valid
  81. if (!qgf_validate_block_header(&graphics_descriptor.header, QGF_GRAPHICS_DESCRIPTOR_TYPEID, (sizeof(qgf_graphics_descriptor_v1_t) - sizeof(qgf_block_header_v1_t)))) {
  82. return false;
  83. }
  84. // Make sure the magic and version are correct
  85. if (graphics_descriptor.magic != QGF_MAGIC || graphics_descriptor.qgf_version != 0x01) {
  86. qp_dprintf("Failed to validate graphics_descriptor, expected magic 0x%06X was 0x%06X, expected version = 0x%02X was 0x%02X\n", (int)QGF_MAGIC, (int)graphics_descriptor.magic, (int)0x01, (int)graphics_descriptor.qgf_version);
  87. return false;
  88. }
  89. // Make sure the file length is valid
  90. if (graphics_descriptor.neg_total_file_size != ~graphics_descriptor.total_file_size) {
  91. qp_dprintf("Failed to validate graphics_descriptor, expected negated length 0x%08X was 0x%08X\n", (int)(~graphics_descriptor.total_file_size), (int)graphics_descriptor.neg_total_file_size);
  92. return false;
  93. }
  94. // Copy out the required info
  95. if (image_width) {
  96. *image_width = graphics_descriptor.image_width;
  97. }
  98. if (image_height) {
  99. *image_height = graphics_descriptor.image_height;
  100. }
  101. if (frame_count) {
  102. *frame_count = graphics_descriptor.frame_count;
  103. }
  104. if (total_bytes) {
  105. *total_bytes = graphics_descriptor.total_file_size;
  106. }
  107. return true;
  108. }
  109. static bool qgf_read_frame_offset(qp_stream_t *stream, uint16_t frame_number, uint32_t *frame_offset) {
  110. uint16_t frame_count;
  111. if (!qgf_read_graphics_descriptor(stream, NULL, NULL, &frame_count, NULL)) {
  112. return false;
  113. }
  114. // Read the frame offsets descriptor
  115. qgf_frame_offsets_v1_t frame_offsets;
  116. if (qp_stream_read(&frame_offsets, sizeof(qgf_frame_offsets_v1_t), 1, stream) != 1) {
  117. qp_dprintf("Failed to read frame_offsets, expected length was not %d\n", (int)sizeof(qgf_frame_offsets_v1_t));
  118. return false;
  119. }
  120. // Make sure this block is valid
  121. if (!qgf_validate_block_header(&frame_offsets.header, QGF_FRAME_OFFSET_DESCRIPTOR_TYPEID, (frame_count * sizeof(uint32_t)))) {
  122. return false;
  123. }
  124. if (frame_number >= frame_count) {
  125. qp_dprintf("Invalid frame number, was %d but only %d frames in image\n", (int)frame_number, (int)frame_count);
  126. return false;
  127. }
  128. // Skip the necessary amount of data to get to the requested frame offset
  129. qp_stream_seek(stream, frame_number * sizeof(uint32_t), SEEK_CUR);
  130. // Read the frame offset
  131. uint32_t offset = 0;
  132. if (qp_stream_read(&offset, sizeof(uint32_t), 1, stream) != 1) {
  133. qp_dprintf("Failed to read frame offset, expected length was not %d\n", (int)sizeof(uint32_t));
  134. return false;
  135. }
  136. // Copy out the required info
  137. if (frame_offset) {
  138. *frame_offset = offset;
  139. }
  140. return true;
  141. }
  142. void qgf_seek_to_frame_descriptor(qp_stream_t *stream, uint16_t frame_number) {
  143. // Read the offset
  144. uint32_t offset = 0;
  145. qgf_read_frame_offset(stream, frame_number, &offset);
  146. // Move to the offset
  147. qp_stream_setpos(stream, offset);
  148. }
  149. bool qgf_validate_frame_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t *bpp, bool *has_palette, bool *is_panel_native, bool *is_delta) {
  150. // Seek to the correct location
  151. qgf_seek_to_frame_descriptor(stream, frame_number);
  152. // Read the raw descriptor
  153. qgf_frame_v1_t frame_descriptor;
  154. if (qp_stream_read(&frame_descriptor, sizeof(qgf_frame_v1_t), 1, stream) != 1) {
  155. qp_dprintf("Failed to read frame_descriptor, expected length was not %d\n", (int)sizeof(qgf_frame_v1_t));
  156. return false;
  157. }
  158. // Make sure this block is valid
  159. if (!qgf_validate_block_header(&frame_descriptor.header, QGF_FRAME_DESCRIPTOR_TYPEID, (sizeof(qgf_frame_v1_t) - sizeof(qgf_block_header_v1_t)))) {
  160. return false;
  161. }
  162. return qgf_parse_frame_descriptor(&frame_descriptor, bpp, has_palette, is_panel_native, is_delta, NULL, NULL);
  163. }
  164. bool qgf_validate_palette_descriptor(qp_stream_t *stream, uint16_t frame_number, uint8_t bpp) {
  165. // Read the palette descriptor
  166. qgf_palette_v1_t palette_descriptor;
  167. if (qp_stream_read(&palette_descriptor, sizeof(qgf_palette_v1_t), 1, stream) != 1) {
  168. qp_dprintf("Failed to read palette_descriptor, expected length was not %d\n", (int)sizeof(qgf_palette_v1_t));
  169. return false;
  170. }
  171. // Make sure this block is valid
  172. uint32_t expected_length = (1 << bpp) * 3 * sizeof(uint8_t);
  173. if (!qgf_validate_block_header(&palette_descriptor.header, QGF_FRAME_PALETTE_DESCRIPTOR_TYPEID, expected_length)) {
  174. return false;
  175. }
  176. // Move forward in the stream to the next block
  177. qp_stream_seek(stream, expected_length, SEEK_CUR);
  178. return true;
  179. }
  180. bool qgf_validate_delta_descriptor(qp_stream_t *stream, uint16_t frame_number) {
  181. // Read the delta descriptor
  182. qgf_delta_v1_t delta_descriptor;
  183. if (qp_stream_read(&delta_descriptor, sizeof(qgf_delta_v1_t), 1, stream) != 1) {
  184. qp_dprintf("Failed to read delta_descriptor, expected length was not %d\n", (int)sizeof(qgf_delta_v1_t));
  185. return false;
  186. }
  187. // Make sure this block is valid
  188. if (!qgf_validate_block_header(&delta_descriptor.header, QGF_FRAME_DELTA_DESCRIPTOR_TYPEID, (sizeof(qgf_delta_v1_t) - sizeof(qgf_block_header_v1_t)))) {
  189. return false;
  190. }
  191. return true;
  192. }
  193. bool qgf_validate_frame_data_descriptor(qp_stream_t *stream, uint16_t frame_number) {
  194. // Read and validate the data block
  195. qgf_data_v1_t data_descriptor;
  196. if (qp_stream_read(&data_descriptor, sizeof(qgf_data_v1_t), 1, stream) != 1) {
  197. qp_dprintf("Failed to read data_descriptor, expected length was not %d\n", (int)sizeof(qgf_data_v1_t));
  198. return false;
  199. }
  200. if (!qgf_validate_block_header(&data_descriptor.header, QGF_FRAME_DATA_DESCRIPTOR_TYPEID, -1)) {
  201. return false;
  202. }
  203. return true;
  204. }
  205. bool qgf_validate_stream(qp_stream_t *stream) {
  206. uint16_t frame_count;
  207. if (!qgf_read_graphics_descriptor(stream, NULL, NULL, &frame_count, NULL)) {
  208. return false;
  209. }
  210. // Read and validate all the frames (automatically validates the frame offset descriptor in the process)
  211. for (uint16_t i = 0; i < frame_count; ++i) {
  212. // Validate the frame descriptor block
  213. uint8_t bpp = 0;
  214. bool has_palette = false;
  215. bool is_panel_native = false;
  216. bool has_delta = false;
  217. if (!qgf_validate_frame_descriptor(stream, i, &bpp, &has_palette, &is_panel_native, &has_delta)) {
  218. return false;
  219. }
  220. // If we've got a palette block, check it
  221. if (has_palette && !qgf_validate_palette_descriptor(stream, i, bpp)) {
  222. return false;
  223. }
  224. // If we've got a delta block, check it
  225. if (has_delta && !qgf_validate_delta_descriptor(stream, i)) {
  226. return false;
  227. }
  228. // Check the data block
  229. if (!qgf_validate_frame_data_descriptor(stream, i)) {
  230. return false;
  231. }
  232. }
  233. return true;
  234. }
  235. // Work out the total size of an image definition, assuming we can read far enough into the file
  236. uint32_t qgf_get_total_size(qp_stream_t *stream) {
  237. // Get the original location
  238. uint32_t oldpos = qp_stream_tell(stream);
  239. // Read the graphics descriptor, grabbing the size
  240. uint32_t total_size;
  241. if (!qgf_read_graphics_descriptor(stream, NULL, NULL, NULL, &total_size)) {
  242. return false;
  243. }
  244. // Restore the original location
  245. qp_stream_setpos(stream, oldpos);
  246. return total_size;
  247. }