/* * Copyright © 2013 stag019 * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include uint8_t *compressed; int xrows; int xwidth; int curbit; int curbyte; void writebit(int bit) { if(++curbit == 8) { curbyte++; curbit = 0; } compressed[curbyte] |= bit << (7 - curbit); } void method_1(uint8_t *RAM) { int i; int j; int nibble_1; int nibble_2; int code_1; int code_2; int table; static int method_1[2][0x10] = {{0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4, 0xC, 0xD, 0xF, 0xE, 0xA, 0xB, 0x9, 0x8}, {0x8, 0x9, 0xB, 0xA, 0xE, 0xF, 0xD, 0xC, 0x4, 0x5, 0x7, 0x6, 0x2, 0x3, 0x1, 0x0}}; for(i = 0; i < xrows * xwidth * 8; i++) { j = i / xrows; j += i % xrows * xwidth * 8; if(!(i % xrows)) { nibble_2 = 0; } nibble_1 = (RAM[j] >> 4) & 0x0F; table = 0; if(nibble_2 & 1) { table = 1; } code_1 = method_1[table][nibble_1]; nibble_2 = RAM[j] & 0x0F; table = 0; if(nibble_1 & 1) { table = 1; } code_2 = method_1[table][nibble_2]; RAM[j] = (code_1 << 4) | code_2; } } void RLE(int nums) { int search; int i; int j; int bitcount; int number; static unsigned int RLE[0x10] = {0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; bitcount = -1; search = ++nums; while(search > 0) { for(i = 0; i < 0xF; i++) { if(RLE[i] == search) { bitcount = i; break; } } if(bitcount != -1) { break; } search--; } number = nums - RLE[bitcount]; for(j = 0; j < bitcount; j++) { writebit(1); } writebit(0); for(j = bitcount; j >= 0; j--) { writebit((number >> j) & 1); } } void data_packet(uint8_t *bitgroups, int bgi) { int i; for(i = 0; i < bgi; i++) { writebit((bitgroups[i] >> 1) & 1); writebit(bitgroups[i] & 1); } } int interpret_compress(uint8_t *RAM_1, uint8_t *RAM_2, int interpretation, int switchram) { uint8_t *_1_RAM; uint8_t *_2_RAM; int i; int ram; int type; int nums; uint8_t *bitgroups; int x; int y; int byte; int bit; int bitgroup; int bgi = 0; _1_RAM = (uint8_t*) calloc(0x188, 1); _2_RAM = (uint8_t*) calloc(0x188, 1); if(switchram) { memcpy(_1_RAM, RAM_2, 0x188); memcpy(_2_RAM, RAM_1, 0x188); } else { memcpy(_1_RAM, RAM_1, 0x188); memcpy(_2_RAM, RAM_2, 0x188); } switch(interpretation) { case 1: method_1(_1_RAM); method_1(_2_RAM); break; case 2: case 3: for(i = 0; i < xrows * xwidth * 8; i++) { _2_RAM[i] ^= _1_RAM[i]; } method_1(_1_RAM); break; } if(interpretation == 3) { method_1(_2_RAM); } curbit = 7; curbyte = 0; compressed = (uint8_t*) calloc(0x310, 1); compressed[0] = (xrows << 4) | xwidth; writebit(switchram); for(ram = 0; ram < 2; ram++) { type = 0; nums = 0; bitgroups = (uint8_t*) calloc(0x1000, 1); for(x = 0; x < xwidth; x++) { for(bit = 0; bit < 8; bit += 2) { byte = x * xrows * 8; for(y=0; y < xrows * 8; y++) { if(ram) { bitgroup = (_2_RAM[byte] >> (6 - bit)) & 3; } else { bitgroup = (_1_RAM[byte] >> (6 - bit)) & 3; } if(!bitgroup) { if(!type) { writebit(0); } else if(type == 1) { nums++; } else { data_packet(bitgroups, bgi); writebit(0); writebit(0); } type = 1; free(bitgroups); bitgroups = (uint8_t*) calloc(0x1000, 1); bgi = 0; } else { if(!type) { writebit(1); } else if(type == 1) { RLE(nums); } type = -1; bitgroups[bgi++] = bitgroup; nums = 0; } byte++; } } } if(type == 1) { RLE(nums); } else { data_packet(bitgroups, bgi); } if(!ram) { if(interpretation < 2) { writebit(0); } else { writebit(1); writebit(interpretation - 2); } } } free(bitgroups); free(_1_RAM); free(_2_RAM); return (curbyte + 1) * 8 + curbit; } int compress(uint8_t *data, int width, int height) { uint8_t *RAM_1; uint8_t *RAM_2; int i; int mode; int order; int newsize; int compressedsize; int size = -1; uint8_t *current = NULL; xrows = height; xwidth = width; RAM_1 = (uint8_t*) calloc(0x188, 1); RAM_2 = (uint8_t*) calloc(0x188, 1); for(i = 0; i < xrows * xwidth * 8; i++) { RAM_1[i] = data[(i << 1)]; RAM_2[i] = data[(i << 1) | 1]; } for(mode = 1; mode < 4; mode++) { for(order = 0; order < 2; order++) { if(!(mode == 1 && order == 0)) { newsize = interpret_compress(RAM_1, RAM_2, mode, order); if(size == -1 || newsize < size) { if(current != NULL) { free(current); } current = (uint8_t*) calloc(0x310, 1); memcpy(current, compressed, newsize / 8); free(compressed); size = newsize; } } } } compressed = (uint8_t*) calloc(0x310, 1); compressedsize = size / 8; memcpy(compressed, current, compressedsize); free(current); free(RAM_1); free(RAM_2); return compressedsize; } int main(int argc, char *argv[]) { int i; FILE *f; int fz; int size; uint8_t *contents; int tiles; int *chloc; char outfile[256]; if(argc < 2) { fputs("Usage: pkmncompress infile.2bpp [infile.2bpp ...]\n", stderr); return EXIT_FAILURE; } for(i = 1; i < argc; i++) { strcpy(outfile, argv[i]); if((chloc = (int *) strrchr(outfile, '.')) != NULL) { strcpy((char *) chloc, ".pic"); } else { strcat(outfile, ".pic"); } f = fopen(argv[i], "rb"); if(!f) { perror("Opening file failed"); return EXIT_FAILURE; } fseek(f, 0, SEEK_END); fz = ftell(f); if(fz == 0x310) { tiles = 7; } else if(fz == 0x240) { tiles = 6; } else if(fz == 0x190) { tiles = 5; } else if(fz == 0x100) { tiles = 4; } else { fputs("Error: wrong file size.\n", stderr); return EXIT_FAILURE; } contents = (uint8_t*) calloc(0x310, 1); fseek(f, 0, SEEK_SET); fread(contents, 1, fz, f); fclose(f); size = compress(contents, tiles, tiles); free(contents); f = fopen(outfile, "wb"); fwrite(compressed, 1, size, f); free(compressed); //printf("Success! File size: %i bytes\n", size); } return EXIT_SUCCESS; }