CARDS.DLL loader for SDL
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cards.c 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. /* Copyright (C) 2019 C. McEnroe <june@causal.agency>
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU Affero General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "cards.h"
  19. enum {
  20. MZ_NEOff = 0x3C,
  21. NE_ResTableOff = 0x24,
  22. ResTable_AlignShift = 0x00,
  23. ResTable_ResBlock = 0x02,
  24. ResBlock_TypeID = 0x00,
  25. ResBlock_ResCount = 0x02,
  26. ResBlock_Resource = 0x08,
  27. TypeID_Bitmap = 0x8002,
  28. Resource_Off = 0x00,
  29. Resource_Len = 0x02,
  30. Resource_ID = 0x06,
  31. Resource_Next = 0x0C,
  32. IDMask = 0x7FFF,
  33. BMPHeader_FileLen = 0x02,
  34. BMPHeader_Reserved = 0x06,
  35. BMPHeader_DataOff = 0x0A,
  36. BMPHeader_DIBHeader = 0x0E,
  37. DIBHeader_Len = 0x00,
  38. DIBHeaderCore_Bits = 0x0A,
  39. DIBHeaderCoreLen = 0x0C,
  40. };
  41. static uint16_t read16(const uint8_t *ptr, size_t off) {
  42. return (uint16_t)ptr[off] | (uint16_t)ptr[off + 1] << 8;
  43. }
  44. static uint32_t read32(const uint8_t *ptr, size_t off) {
  45. return (uint32_t)ptr[off]
  46. | (uint32_t)ptr[off + 1] << 8
  47. | (uint32_t)ptr[off + 2] << 16
  48. | (uint32_t)ptr[off + 3] << 24;
  49. }
  50. static void write32(uint8_t *ptr, size_t off, uint32_t val) {
  51. ptr[off + 0] = val & 0xFF;
  52. ptr[off + 1] = val >> 8 & 0xFF;
  53. ptr[off + 2] = val >> 16 & 0xFF;
  54. ptr[off + 3] = val >> 24;
  55. }
  56. int cardsLoad(const uint8_t *ptr, size_t len) {
  57. if (len < MZ_NEOff + 2) return -1;
  58. if (ptr[0] != 'M' || ptr[1] != 'Z') return -1;
  59. uint16_t neOff = read16(ptr, MZ_NEOff);
  60. if (len < neOff + NE_ResTableOff + 2) return -1;
  61. if (ptr[neOff + 0] != 'N' || ptr[neOff + 1] != 'E') return -1;
  62. uint16_t resTableOff = neOff + read16(ptr, neOff + NE_ResTableOff);
  63. if (len < resTableOff + ResTable_ResBlock) return -1;
  64. uint16_t alignShift = read16(ptr, resTableOff + ResTable_AlignShift);
  65. uint16_t resBlockOff = resTableOff + ResTable_ResBlock;
  66. uint16_t resCount;
  67. for (;;) {
  68. if (len < resBlockOff + ResBlock_Resource) return -1;
  69. uint16_t typeID = read16(ptr, resBlockOff + ResBlock_TypeID);
  70. resCount = read16(ptr, resBlockOff + ResBlock_ResCount);
  71. if (!typeID) return -1;
  72. if (typeID == TypeID_Bitmap) break;
  73. resBlockOff += ResBlock_Resource + resCount * Resource_Next;
  74. }
  75. uint16_t resOff = resBlockOff + ResBlock_Resource;
  76. for (uint16_t i = 0; i < resCount; ++i, resOff += Resource_Next) {
  77. if (len < resOff + Resource_Next) return -1;
  78. uint16_t id = read16(ptr, resOff + Resource_ID);
  79. if ((id & IDMask) >= CardsLen) continue;
  80. size_t dataOff = read16(ptr, resOff + Resource_Off);
  81. size_t dataLen = read16(ptr, resOff + Resource_Len);
  82. dataOff <<= alignShift;
  83. dataLen <<= alignShift;
  84. if (len < dataOff + dataLen) return -1;
  85. if (dataLen < DIBHeaderCoreLen) return -1;
  86. uint32_t dibHeaderLen = read32(ptr, dataOff + DIBHeader_Len);
  87. uint32_t bmpFileLen = BMPHeader_DIBHeader + dataLen;
  88. uint32_t bmpDataOff = BMPHeader_DIBHeader + dibHeaderLen;
  89. if (dibHeaderLen == DIBHeaderCoreLen) {
  90. bmpDataOff += 3 * (1 << read16(ptr, dataOff + DIBHeaderCore_Bits));
  91. }
  92. uint8_t *bitmap = malloc(bmpFileLen);
  93. if (!bitmap) return -1;
  94. bitmap[0] = 'B';
  95. bitmap[1] = 'M';
  96. write32(bitmap, BMPHeader_FileLen, bmpFileLen);
  97. write32(bitmap, BMPHeader_Reserved, 0);
  98. write32(bitmap, BMPHeader_DataOff, bmpDataOff);
  99. memcpy(&bitmap[BMPHeader_DIBHeader], &ptr[dataOff], dataLen);
  100. cardsData[id & IDMask].ptr = bitmap;
  101. cardsData[id & IDMask].len = bmpFileLen;
  102. }
  103. return 0;
  104. }