/* Copyright (C) 2019 C. McEnroe * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include #include #include "cards.h" enum { MZ_NEOff = 0x3C, NE_ResTableOff = 0x24, ResTable_AlignShift = 0x00, ResTable_ResBlock = 0x02, ResBlock_TypeID = 0x00, ResBlock_ResCount = 0x02, ResBlock_Resource = 0x08, TypeID_Bitmap = 0x8002, Resource_Off = 0x00, Resource_Len = 0x02, Resource_ID = 0x06, Resource_Next = 0x0C, IDMask = 0x7FFF, BMPHeader_FileLen = 0x02, BMPHeader_Reserved = 0x06, BMPHeader_DataOff = 0x0A, BMPHeader_DIBHeader = 0x0E, DIBHeader_Len = 0x00, DIBHeaderCore_Bits = 0x0A, DIBHeaderCoreLen = 0x0C, }; static uint16_t read16(const uint8_t *ptr, size_t off) { return (uint16_t)ptr[off] | (uint16_t)ptr[off + 1] << 8; } static uint32_t read32(const uint8_t *ptr, size_t off) { return (uint32_t)ptr[off] | (uint32_t)ptr[off + 1] << 8 | (uint32_t)ptr[off + 2] << 16 | (uint32_t)ptr[off + 3] << 24; } static void write32(uint8_t *ptr, size_t off, uint32_t val) { ptr[off + 0] = val & 0xFF; ptr[off + 1] = val >> 8 & 0xFF; ptr[off + 2] = val >> 16 & 0xFF; ptr[off + 3] = val >> 24; } int cardsLoad(const uint8_t *ptr, size_t len) { if (len < MZ_NEOff + 2) return -1; if (ptr[0] != 'M' || ptr[1] != 'Z') return -1; uint16_t neOff = read16(ptr, MZ_NEOff); if (len < neOff + NE_ResTableOff + 2) return -1; if (ptr[neOff + 0] != 'N' || ptr[neOff + 1] != 'E') return -1; uint16_t resTableOff = neOff + read16(ptr, neOff + NE_ResTableOff); if (len < resTableOff + ResTable_ResBlock) return -1; uint16_t alignShift = read16(ptr, resTableOff + ResTable_AlignShift); uint16_t resBlockOff = resTableOff + ResTable_ResBlock; uint16_t resCount; for (;;) { if (len < resBlockOff + ResBlock_Resource) return -1; uint16_t typeID = read16(ptr, resBlockOff + ResBlock_TypeID); resCount = read16(ptr, resBlockOff + ResBlock_ResCount); if (!typeID) return -1; if (typeID == TypeID_Bitmap) break; resBlockOff += ResBlock_Resource + resCount * Resource_Next; } uint16_t resOff = resBlockOff + ResBlock_Resource; for (uint16_t i = 0; i < resCount; ++i, resOff += Resource_Next) { if (len < resOff + Resource_Next) return -1; uint16_t id = read16(ptr, resOff + Resource_ID); if ((id & IDMask) >= CardsLen) continue; size_t dataOff = read16(ptr, resOff + Resource_Off); size_t dataLen = read16(ptr, resOff + Resource_Len); dataOff <<= alignShift; dataLen <<= alignShift; if (len < dataOff + dataLen) return -1; if (dataLen < DIBHeaderCoreLen) return -1; uint32_t dibHeaderLen = read32(ptr, dataOff + DIBHeader_Len); uint32_t bmpFileLen = BMPHeader_DIBHeader + dataLen; uint32_t bmpDataOff = BMPHeader_DIBHeader + dibHeaderLen; if (dibHeaderLen == DIBHeaderCoreLen) { bmpDataOff += 3 * (1 << read16(ptr, dataOff + DIBHeaderCore_Bits)); } uint8_t *bitmap = malloc(bmpFileLen); if (!bitmap) return -1; bitmap[0] = 'B'; bitmap[1] = 'M'; write32(bitmap, BMPHeader_FileLen, bmpFileLen); write32(bitmap, BMPHeader_Reserved, 0); write32(bitmap, BMPHeader_DataOff, bmpDataOff); memcpy(&bitmap[BMPHeader_DIBHeader], &ptr[dataOff], dataLen); cardsData[id & IDMask].ptr = bitmap; cardsData[id & IDMask].len = bmpFileLen; } return 0; }