/*----------------------------------------------------------------------------*/ /*-- rle.c - RLE coding for Nintendo GBA/DS --*/ /*-- Copyright (C) 2011 CUE --*/ /*-- --*/ /*-- This program is free software: you can redistribute it and/or modify --*/ /*-- it under the terms of the GNU 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 General Public License for more details. --*/ /*-- --*/ /*-- You should have received a copy of the GNU General Public License --*/ /*-- along with this program. If not, see . --*/ /*----------------------------------------------------------------------------*/ /*----------------------------------------------------------------------------*/ #include #include #include /*----------------------------------------------------------------------------*/ #define CMD_DECODE 0x00 // decode #define CMD_CODE_30 0x30 // RLE magic number #define RLE_CHECK 1 // bits to check #define RLE_MASK 0x80 // bits position: // ((((1 << RLE_CHECK) - 1) << (8 - RLE_CHECK) #define RLE_LENGTH 0x7F // length, (0xFF & ~RLE_MASK) #define RLE_THRESHOLD 2 // max number of bytes to not encode #define RLE_N 0x80 // max store, (RLE_LENGTH + 1) #define RLE_F 0x82 // max coded, (RLE_LENGTH + RLE_THRESHOLD + 1) #define RAW_MINIM 0x00000000 // empty file, 0 bytes #define RAW_MAXIM 0x00FFFFFF // 3-bytes length, 16MB - 1 #define RLE_MINIM 0x00000004 // header only (empty RAW file) #define RLE_MAXIM 0x01400000 // 0x01020003, padded to 20MB: // * header, 4 // * length, RAW_MAXIM // * flags, (RAW_MAXIM + RLE_N - 1) / RLE_N // 4 + 0x00FFFFFF + 0x00020000 + padding /*----------------------------------------------------------------------------*/ #define BREAK(text) { printf(text); return; } #define EXIT(text) { printf(text); exit(-1); } /*----------------------------------------------------------------------------*/ void Title(void); void Usage(void); char *Load(char *filename, int *length, int min, int max); void Save(char *filename, char *buffer, int length); char *Memory(int length, int size); void RLE_Decode(char *filename); void RLE_Encode(char *filename); char *RLE_Code(unsigned char *raw_buffer, int raw_len, int *new_len); /*----------------------------------------------------------------------------*/ char *Memory(int length, int size) { char *fb; fb = (char *) calloc(length, size); if (fb == NULL) EXIT("\nMemory error\n"); return(fb); } /*----------------------------------------------------------------------------*/ char *RLE_Code(unsigned char *raw_buffer, int raw_len, int *new_len) { unsigned char *pak_buffer, *pak, *raw, *raw_end, store[RLE_N]; unsigned int pak_len, len, store_len, count; pak_len = 4 + raw_len + ((raw_len + RLE_N - 1) / RLE_N); pak_buffer = (unsigned char *) Memory(pak_len, sizeof(char)); *(unsigned int *)pak_buffer = CMD_CODE_30 | (raw_len << 8); pak = pak_buffer + 4; raw = raw_buffer; raw_end = raw_buffer + raw_len; store_len = 0; while (raw < raw_end) { for (len = 1; len < RLE_F; len++) { if (raw + len == raw_end) break; if (*(raw + len) != *raw) break; } if (len <= RLE_THRESHOLD) store[store_len++] = *raw++; if ((store_len == RLE_N) || (store_len && (len > RLE_THRESHOLD))) { *pak++ = store_len - 1; for (count = 0; count < store_len; count++) *pak++ = store[count]; store_len = 0; } if (len > RLE_THRESHOLD) { *pak++ = RLE_MASK | (len - (RLE_THRESHOLD + 1)); *pak++ = *raw; raw += len; } } if (store_len) { *pak++ = store_len - 1; for (count = 0; count < store_len; count++) *pak++ = store[count]; } *new_len = pak - pak_buffer; return(pak_buffer); } /*----------------------------------------------------------------------------*/ /*-- EOF Copyright (C) 2011 CUE --*/ /*----------------------------------------------------------------------------*/