/****************************************************************************** * LoadRLE / SaveRLE - Load and save binary data using RLE compression. * Run-length tokens have a set MSB, while data tokens have a cleared * MSB. The value of the token's remaining bits plus one indicates the * length of the block. The minimum run length is three bytes, while * the maximum is 128. * * data - Array holding data to load or save. * size - Size of the data array. * file - The file pointer to use. * return - Total number of bytes read from or written to data[]. */ size_t LoadRLE (unsigned char data[], size_t size, FILE *file) { unsigned char token; unsigned int length; size_t total = 0; while(size && fread(&token, 1, 1, file)){ length = (token & ~0x80) + 1; if (length > size) return total; if(token & 0x80){ if(!fread(&token, 1, 1, file)) return total; memset(data, token, length); }else{ if(fread(data, 1, length, file) != length) return total; } data += length, size -= length, total += length; } return total; } /*************************************/ size_t SaveRLE (unsigned char data[], size_t size, FILE *file) { unsigned char token; unsigned int i; size_t total = 0; while(size) { /*This loop identifies blocks of repeating data:*/ i = 2; while(i < size && i < 128 && data[i] == data[i - 1] && data[i - 1] == data[i - 2]) i++; /*If repeating data was found, save it:*/ if(i > 2){ token = i - 1 | 0x80; if(!fwrite(&token, 1, 1, file)) return total; if(!fwrite(data, 1, 1, file)) return total; data += i, size -= i, total += i; } /*This loop identifies blocks of non-repeating data:*/ i = 0; while(i < size && i < 128 && (i + 2 > size ? 1 : data[i] != data[i + 1] || data[i + 1] != data[i + 2])) i++; /*If non-repeating data was found, save it:*/ if(i){ token = i - 1; if(!fwrite(&token, 1, 1, file)) return total; if(fwrite(data, 1, i, file) != i) return total; data += i, size -= i, total += i; } } return total; }