// Copyright (C) 2002-2007 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // // This file was originally written by ZDimitor. //---------------------------------------------------------------------- // somefuncs.h - part of the My3D Tools // // This tool was created by Zhuck Dmitry (ZDimitor). // Everyone can use it as wants ( i'll be happy if it helps to someone :) ). //---------------------------------------------------------------------- //********************************************************************** // some useful functions //********************************************************************** #ifndef __C_MY3D_HELPER_H_INCLUDED__ #define __C_MY3D_HELPER_H_INCLUDED__ //-------------------------------------------------------------------------------- namespace irr { namespace core { //-----------------RLE stuff----------------------------------------- int rle_encode ( unsigned char *in_buf, int in_buf_size, unsigned char *out_buf, int out_buf_size ); unsigned long process_comp( unsigned char *buf, int buf_size, unsigned char *out_buf, int out_buf_size ); void process_uncomp( unsigned char, unsigned char *out_buf, int out_buf_size ); void flush_outbuf( unsigned char *out_buf, int out_buf_size ); unsigned long get_byte ( unsigned char *ch, unsigned char *in_buf, int in_buf_size, unsigned char *out_buf, int out_buf_size ); void put_byte( unsigned char ch, unsigned char *out_buf, int out_buf_size ); //----------------------------------------------------------- const unsigned long LIMIT = 1; // was #define LIMIT 1 const unsigned long NON_MATCH = 2; // was: #define NON_MATCH 2 const unsigned long EOD_FOUND = 3; // was: #define EOD_FOUND 3 const unsigned long EOD = 0x00454f44; // was: #define EOD 'EOD' //----------------------------------------------------------- // number of decoded bytes static int nDecodedBytes=0; // number of coded bytes static int nCodedBytes=0; // number of read bytes static int nReadedBytes=0; // table used to look for sequences of repeating bytes static unsigned char tmpbuf[4]; // we use subscripts 1 - 3 static int tmpbuf_cnt; // output buffer for non-compressed output data static unsigned char outbuf[128]; static int outbuf_cnt; //----------------------------------------------------------- int rle_encode ( unsigned char *in_buf, int in_buf_size, unsigned char *out_buf, int out_buf_size ) { unsigned long ret_code; unsigned char ch; nCodedBytes=0; nReadedBytes=0; tmpbuf_cnt = 0; // no. of char's in tmpbuf outbuf_cnt = 0; // no. of char's in outbuf while (1) { if (get_byte(&ch, in_buf, in_buf_size, out_buf, out_buf_size) == (int)EOD) // read next byte into ch break; tmpbuf[++tmpbuf_cnt] = (unsigned char) ch; if (tmpbuf_cnt == 3) { // see if all 3 match each other if ((tmpbuf[1] == tmpbuf[2]) && (tmpbuf[2] == tmpbuf[3])) { // they do - add compression // this will process all bytes in input file until // a non-match occurs, or 128 bytes are processed, // or we find eod */ ret_code = process_comp(in_buf, in_buf_size, out_buf, out_buf_size); if (ret_code == (int)EOD_FOUND) break; // stop compressing if (ret_code == (int)NON_MATCH) tmpbuf_cnt=1; /* save the char that didn't match */ else // we just compressed the max. of 128 bytes tmpbuf_cnt=0; /* start over for next chunk */ } else { // we know the first byte doesn't match 2 or more // others, so just send it out as uncompressed. */ process_uncomp(tmpbuf[1], out_buf, out_buf_size); // see if the last 2 bytes in the buffer match if (tmpbuf[2] == tmpbuf[3]) { // move byte 3 to position 1 and pretend we just // have 2 bytes -- note that the first byte was // already sent to output */ tmpbuf[1]=tmpbuf[3]; tmpbuf_cnt=2; } else { // send byte 2 and keep byte 3 - it may match the // next byte. Move byte 3 to position 1 and set // count to 1. Note that the first byte was // already sent to output process_uncomp(tmpbuf[2], out_buf, out_buf_size); tmpbuf[1]=tmpbuf[3]; tmpbuf_cnt=1; } } } } // end while flush_outbuf(out_buf, out_buf_size); return nCodedBytes; } //------------------------------------------------------------------ // This flushes any non-compressed data not yet sent, then it processes // repeating bytes until > 128, or EOD, or non-match. // return values: LIMIT, EOD_FOUND, NON_MATCH // Prior to ANY return, it writes out the 2 byte compressed code. // If a NON_MATCH was found, this returns with the non-matching char // residing in tmpbuf[0]. // Inputs: tmpbuf[0], input file // Outputs: tmpbuf[0] (sometimes), output file, and return code //------------------------------------------------------------------ unsigned long process_comp( unsigned char *buf, int buf_size, unsigned char *out_buf, int out_buf_size) { // we start out with 3 repeating bytes register int len = 3; unsigned char ch; // we're starting a repeating chunk - end the non-repeaters flush_outbuf(out_buf, out_buf_size); while (get_byte(&ch, buf, buf_size, out_buf, out_buf_size) != (int)EOD) { if (ch != tmpbuf[1]) { // send no. of repeated bytes to be encoded put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size); // send the byte's value being repeated put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size); /* save the non-matching character just read */ tmpbuf[1]=(unsigned char) ch; return NON_MATCH; } /* we know the new byte is part of the repeating seq */ len++; if (len == 128) { // send no. of repeated bytes to be encoded put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size); // send the byte's value being repeated put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size); return LIMIT; } } // end while // if flow comes here, we just read an EOD // send no. of repeated bytes to be encoded put_byte((unsigned char)((--len) | 0x80), out_buf, out_buf_size); // send the byte's value being repeated put_byte((unsigned char)tmpbuf[1], out_buf, out_buf_size); return EOD_FOUND; } //---------------------------------------------------------------- // This adds 1 non-repeating byte to outbuf. If outbuf becomes full // with 128 bytes, it flushes outbuf. // There are no return codes and no bytes are read from the input. //---------------------------------------------------------------- void process_uncomp( unsigned char char1, unsigned char *out_buf, int out_buf_size ) { outbuf[outbuf_cnt++] = char1; if (outbuf_cnt == 128) flush_outbuf(out_buf, out_buf_size); } //----------------------------------------------------------- // This flushes any non-compressed data not yet sent. // On exit, outbuf_cnt will equal zero. //----------------------------------------------------------- void flush_outbuf(unsigned char *out_buf, int out_buf_size) { register int pos=0; if(!outbuf_cnt) return; // nothing to do */ // send no. of unencoded bytes to be sent put_byte((unsigned char)(outbuf_cnt - 1), out_buf, out_buf_size); for ( ; outbuf_cnt; outbuf_cnt--) put_byte((unsigned char)outbuf[pos++], out_buf, out_buf_size); } //--------------------------------------------------- void put_byte(unsigned char ch, unsigned char *out_buf, int out_buf_size) { if (nCodedBytes<=(out_buf_size-1)) { out_buf[nCodedBytes++]=ch; out_buf[nCodedBytes]=0; } } //--------------------------------------------------- // This reads the next byte into ch. It returns EOD // at end-of-data //--------------------------------------------------- unsigned long get_byte( unsigned char *ch, unsigned char *in_buf, int in_buf_size, unsigned char *out_buf, int out_buf_size ) { if (nReadedBytes>=in_buf_size) { // there are either 0, 1, or 2 char's to write before we quit if (tmpbuf_cnt == 1) process_uncomp(tmpbuf[1], out_buf, out_buf_size); else { if (tmpbuf_cnt == 2) { process_uncomp(tmpbuf[1], out_buf, out_buf_size); process_uncomp(tmpbuf[2], out_buf, out_buf_size); } } nReadedBytes =0; return EOD; } (*ch) = (unsigned char)in_buf[nReadedBytes++]; return 0; } //----------------------------------------------------------- int rle_decode ( unsigned char *in_buf, int in_buf_size, unsigned char *out_buf, int out_buf_size ) { nDecodedBytes=0; nReadedBytes=0; int ch, i; while (1) { if (nReadedBytes>=in_buf_size) break; else ch=in_buf[nReadedBytes]; nReadedBytes++; if (ch > 127) { i = ch - 127; // i is the number of repetitions // get the byte to be repeated if (nReadedBytes>=in_buf_size) break; else ch=in_buf[nReadedBytes]; nReadedBytes++; // uncompress a chunk for ( ; i ; i--) { if (nDecodedBytes=in_buf_size) break; else ch=in_buf[nReadedBytes]; nReadedBytes++; if (nDecodedBytes