qgf.c 11 KB

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