Logo Search packages:      
Sourcecode: scummvm version File versions

codecs.cpp

/* ScummVM - Kyrandia Interpreter
 * Copyright (C) 2003-2004 The ScummVM project
 *
 * 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 2
 * 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, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * $Header: /cvsroot/scummvm/scummvm/kyra/codecs.cpp,v 1.7 2004/11/11 13:35:21 ender Exp $
 *
 */


#include "stdafx.h"
#include "codecs.h"

/*****************************************************************************
 * decode.c - Decoding routines for format80, format40, format20 
 * and format3 type graphics
 * Author: Olaf van der spek
 * Modified for FreeCNC by Kareem Dana
 * Modified for Kyra by Jack Burton
 * Format3 decoding added by Jack Burton
 * Modified for ScummVM by Johannes Schickel
 ****************************************************************************/

namespace Kyra {

/** decompress format 80 compressed data.
 * @param image_in      compressed data.
 * @param image_out     pointer to output uncompressed data.
 * @returns size of uncompressed data.
 */
int Compression::decode80(const uint8* image_in, uint8* image_out) {
      /*
      0 copy 0cccpppp p
      1 copy 10cccccc
      2 copy 11cccccc p p
      3 fill 11111110 c c v
      4 copy 11111111 c c p p
      */

      const uint8* copyp;
      const uint8* readp = image_in;
      uint8* writep = image_out;
      uint16 code;
      uint16 count;

      while (1) {
            code = *readp++;
            if (~code & 0x80) {
                  //bit 7 = 0
                  //command 0 (0cccpppp p): copy
                  count = (code >> 4) + 3;
                  copyp = writep - (((code & 0xf) << 8) + *readp++);
                  while (count--)
                        *writep++ = *copyp++;
            } else {
                  //bit 7 = 1
                  count = code & 0x3f;
                  if (~code & 0x40) {
                        //bit 6 = 0
                        if (!count)
                              //end of image
                              break;
                        //command 1 (10cccccc): copy
                        while (count--)
                              *writep++ = *readp++;
                  } else {
                        //bit 6 = 1
                        if (count < 0x3e) {
                              //command 2 (11cccccc p p): copy
                              count += 3;

                              copyp = (const uint8*)&image_out[READ_LE_UINT16(readp)];
                              readp += 2;

                              // FIXME: Using memmove sometimes segfaults 
                              // (reproducably for Ender), which suggests something Bad here
                              //memmove(writep, copyp, count);
                              //writep += count;
                              //copyp += count;
                              while (count--)
                                    *writep++ = *copyp++;
                        } else if (count == 0x3e) {
                              //command 3 (11111110 c c v): fill

                              count = READ_LE_UINT16(readp);
                              readp += 2;
                              code = *readp++;
                              memset(writep, code, count);
                              writep += count;
                        } else {
                              //command 4 (copy 11111111 c c p p): copy

                              count = READ_LE_UINT16(readp);
                              readp += 2;

                              copyp = (const uint8*)&image_out[READ_LE_UINT16(readp)];
                              readp += 2;
                              while (count--)
                                    *writep++ = *copyp++;
                        }
                  }
            }
      }

      return (writep - image_out);
}

/** decompress format 40 compressed data.
 * @param image_in      compressed data.
 * @param image_out     pointer to put uncompressed data in.
 * @returns size of uncompressed data.
 */
int Compression::decode40(const uint8* image_in, uint8* image_out) {
      /*
      0 fill 00000000 c v
      1 copy 0ccccccc
      2 skip 10000000 c 0ccccccc
      3 copy 10000000 c 10cccccc
      4 fill 10000000 c 11cccccc v
      5 skip 1ccccccc
      */

      const uint8* readp = image_in;
      uint8* writep = image_out;
      uint16 code;
      uint16 count;

      while (1) {
            code = *readp++;
            if (~code & 0x80) {
                  //bit 7 = 0
                  if (!code) {
                        //command 0 (00000000 c v): fill
                        count = *readp++;
                        code = *readp++;
                        while (count--)
                              *writep++ ^= code;
                  } else {
                        //command 1 (0ccccccc): copy
                        count = code;
                        while (count--)
                              *writep++ ^= *readp++;
                  }

            } else {
                  //bit 7 = 1
                  if (!(count = code & 0x7f)) {

                        count = READ_LE_UINT16(readp);
                        readp += 2;
                        code = count >> 8;
                        if (~code & 0x80) {
                              //bit 7 = 0
                              //command 2 (10000000 c 0ccccccc): skip
                              if (!count)
                                    // end of image
                                    break;
                              writep += count;
                        } else {
                              //bit 7 = 1
                              count &= 0x3fff;
                              if (~code & 0x40) {
                                    //bit 6 = 0
                                    //command 3 (10000000 c 10cccccc): copy
                                    while (count--)
                                          *writep++ ^= *readp++;
                              } else {
                                    //bit 6 = 1
                                    //command 4 (10000000 c 11cccccc v): fill
                                    code = *readp++;
                                    while (count--)
                                          *writep++ ^= code;
                              }
                        }
                  } else //command 5 (1ccccccc): skip
                        writep += count;
            }
      }
      return (writep - image_out);
}

/** decompress format 3 compressed data.
 * @param image_in      compressed data.
 * @param image_out     pointer to put uncompressed data in.
 * @param size of uncompressed image.
 */
int Compression::decode3(const uint8* image_in, uint8* image_out, int size) {
      /* Untested on BIG-Endian machines */
      
      /*
      0 copy
      1 fill 
      2 fill 
      */
      const uint8* readp = image_in;
      uint8* writep = image_out;
      int16 code;
      int16 count;
      
      do {
            code = *const_cast<int8*>((const int8*)readp++);
            if (code > 0) { // Copy 
                  count = code ;
                  while (count--)
                        *writep++ = *readp++;
            } else if (code == 0) { // Fill(1)
                  count = READ_BE_UINT16(readp);
 
                  readp += 2;
                  code = *readp++;
                  while (count--)
                        *writep++ = (uint8)code;
            } else if (code < 0) { // Fill (2)
                  count = -code;
                  code = *readp++;
                  while (count--)
                        *writep++ = (uint8)code;
            }
      } while ((writep - image_out) < size);    
      
      //and, to be uniform to other decomp. functions...                      
      return (writep - image_out); 
}

/** decompress format 20 compressed data.
 * @param s compressed data.
 * @param d pointer to pu uncompressed data in.
 * @param cb_s    size of compressed data?
 * @returns size of uncompressed data?
 */
int Compression::decode2(const uint8* s, uint8* d, int cb_s) {
      const uint8* r = s;
      const uint8* r_end = s + cb_s;
      uint8* w = d;
      while (r < r_end) {
            int v = *r++;
            if (v)
                  *w++ = v;
            else {
                  v = *r++;
                  memset(w, 0, v);
                  w += v;
            }
      }
      return w - d;

}
} // end of namespace Kyra


Generated by  Doxygen 1.6.0   Back to index