Logo Search packages:      
Sourcecode: scummvm version File versions

util.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2002-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/scumm/util.cpp,v 1.1.2.2 2005/01/28 19:40:56 arisme Exp $
 *
 */

#include "scumm/util.h"

namespace Scumm {

#pragma mark -
#pragma mark --- ScummFile ---
#pragma mark -


ScummFile::ScummFile() : _encbyte(0), _subFileStart(0), _subFileLen(0) {
}

void ScummFile::setEnc(byte value) {
      _encbyte = value;
}

void ScummFile::setSubfileRange(uint32 start, uint32 len) {
      // TODO: Add sanity checks
      const uint32 fileSize = File::size();
      assert(start <= fileSize);
      assert(start + len <= fileSize);
      _subFileStart = start;
      _subFileLen = len;
      seek(0, SEEK_SET);
}

void ScummFile::resetSubfile() {
      _subFileStart = 0;
      _subFileLen = 0;
      seek(0, SEEK_SET);
}

bool ScummFile::open(const char *filename, AccessMode mode) {
      if (File::open(filename, mode)) {
            resetSubfile();
            return true;
      } else {
            return false;
      }
}

bool ScummFile::openSubFile(const char *filename) {
      assert(isOpen());

      // Disable the XOR encryption and reset any current subfile range
      setEnc(0);
      resetSubfile();

      // Read in the filename table and look for the specified file

      unsigned long file_off, file_len;
      char file_name[0x20+1];
      unsigned long i;

      // Get the length of the data file to use for consistency checks
      const uint32 data_file_len = size();
      
      // Read offset and length to the file records */
      const uint32 file_record_off = readUint32BE();
      const uint32 file_record_len = readUint32BE();

      // Do a quick check to make sure the offset and length are good
      if (file_record_off + file_record_len > data_file_len) {
            return false;
      }

      // Do a little consistancy check on file_record_length
      if (file_record_len % 0x28) {
            return false;
      }

      // Scan through the files
      for (i = 0; i < file_record_len; i += 0x28) {
            // read a file record
            seek(file_record_off + i, SEEK_SET);
            file_off = readUint32BE();
            file_len = readUint32BE();
            read(file_name, 0x20);
            file_name[0x20] = 0;

            assert(file_name[0]);
            //debug(7, "  extracting \'%s\'", file_name);
            
            // Consistency check. make sure the file data is in the file
            if (file_off + file_len > data_file_len) {
                  return false;
            }
            
            if (scumm_stricmp(file_name, filename) == 0) {
                  // We got a match!
                  setSubfileRange(file_off, file_len);
                  return true;
            }
      }

      return false;
}


bool ScummFile::eof() {
      return _subFileLen ? (pos() >= _subFileLen) : File::eof();
}

uint32 ScummFile::pos() {
      return File::pos() - _subFileStart;
}

uint32 ScummFile::size() {
      return _subFileLen ? _subFileLen : File::size();
}

void ScummFile::seek(int32 offs, int whence) {
      if (_subFileLen) {
            // Constrain the seek to the subfile
            switch (whence) {
            case SEEK_END:
                  offs = _subFileStart + _subFileLen - offs;
                  break;
            case SEEK_SET:
                  offs += _subFileStart;
                  break;
            case SEEK_CUR:
                  offs += File::pos();
                  break;
            }
            assert((int32)_subFileStart <= offs && offs <= (int32)(_subFileStart + _subFileLen));
            whence = SEEK_SET;
      }
      File::seek(offs, whence);
}

uint32 ScummFile::read(void *ptr, uint32 len) {
      uint32 realLen;
      
      if (_subFileLen) {
            // Limit the amount we read by the subfile boundaries.
            const uint32 curPos = pos();
            assert(_subFileLen >= curPos);
            uint32 newPos = curPos + len;
            if (newPos > _subFileLen) {
                  len = _subFileLen - curPos;
                  _ioFailed = true;
            }
      }
      
      realLen = File::read(ptr, len);
      
      
      // If an encryption byte was specified, XOR the data we just read by it.
      // This simple kind of "encryption" was used by some of the older SCUMM
      // games.
      if (_encbyte) {
            byte *p = (byte *)ptr;
            byte *end = p + realLen;
            while (p < end)
                  *p++ ^= _encbyte;
      }

      return realLen;
}

uint32 ScummFile::write(const void *, uint32) {
      error("ScummFile does not support writing!");
      return 0;
}

#pragma mark -
#pragma mark --- Utilities ---
#pragma mark -

void checkRange(int max, int min, int no, const char *str) {
      if (no < min || no > max) {
            char buf[256];
            snprintf(buf, sizeof(buf), str, no);
            error("Value %d is out of bounds (%d,%d) (%s)", no, min, max, buf);
      }
}

/**
 * Convert an old style direction to a new style one (angle),
 */
int newDirToOldDir(int dir) {
      if (dir >= 71 && dir <= 109)
            return 1;
      if (dir >= 109 && dir <= 251)
            return 2;
      if (dir >= 251 && dir <= 289)
            return 0;
      return 3;
}

/**
 * Convert an new style (angle) direction to an old style one.
 */
int oldDirToNewDir(int dir) {
      assert(0 <= dir && dir <= 3);
      const int new_dir_table[4] = { 270, 90, 180, 0 };
      return new_dir_table[dir];
}

/**
 * Convert an angle to a simple direction.
 */
int toSimpleDir(int dirType, int dir) {
      if (dirType) {
            const int16 directions[] = { 22,  72, 107, 157, 202, 252, 287, 337 };
            for (int i = 0; i < 7; i++)
                  if (dir >= directions[i] && dir <= directions[i+1])
                        return i+1;
      } else {
            const int16 directions[] = { 71, 109, 251, 289 };
            for (int i = 0; i < 3; i++)
                  if (dir >= directions[i] && dir <= directions[i+1])
                        return i+1;
      }

      return 0;
}

/**
 * Convert a simple direction to an angle.
 */
int fromSimpleDir(int dirType, int dir) {
      if (dirType)
            return dir * 45;
      else
            return dir * 90;
}

/**
 * Normalize the given angle - that means, ensure it is positive, and
 * change it to the closest multiple of 45 degree by abusing toSimpleDir.
 */
int normalizeAngle(int angle) {
      int temp;

      temp = (angle + 360) % 360;

      return toSimpleDir(1, temp) * 45;
}

const char *tag2str(uint32 tag) {
      static char str[5];
      str[0] = (char)(tag >> 24);
      str[1] = (char)(tag >> 16);
      str[2] = (char)(tag >> 8);
      str[3] = (char)tag;
      str[4] = '\0';
      return str;
}

} // End of namespace Scumm

Generated by  Doxygen 1.6.0   Back to index