mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-12 12:40:58 +00:00
556 lines
16 KiB
C++
556 lines
16 KiB
C++
/* ScummVM - Graphic Adventure Engine
|
|
*
|
|
* ScummVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
|
* file distributed with this source distribution.
|
|
*
|
|
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "cryo/defs.h"
|
|
#include "cryo/cryo.h"
|
|
#include "cryo/platdefs.h"
|
|
#include "cryo/cryolib.h"
|
|
#include "cryo/eden.h"
|
|
#include "cryo/sound.h"
|
|
|
|
namespace Cryo {
|
|
|
|
#define CRYO_DAT_VER 1 // 32-bit integer
|
|
|
|
// Original name: prechargephrases
|
|
void EdenGame::preloadDialogs(int16 vid) {
|
|
perso_t *perso = &_persons[PER_MORKUS];
|
|
if (vid == 170)
|
|
perso = &_persons[PER_UNKN_156];
|
|
_globals->_characterPtr = perso;
|
|
_globals->_dialogType = DialogType::dtInspect;
|
|
int num = (perso->_id << 3) | _globals->_dialogType;
|
|
Dialog *dial = (Dialog *)getElem(_gameDialogs, num);
|
|
dialoscansvmas(dial);
|
|
}
|
|
|
|
////// datfile.c
|
|
void EdenGame::verifh(byte *ptr) {
|
|
byte sum = 0;
|
|
byte *head = ptr;
|
|
|
|
for (int8 i = 0; i < 6; i++)
|
|
sum += *head++;
|
|
|
|
if (sum != 0xAB)
|
|
return;
|
|
|
|
debug("* Begin unpacking resource");
|
|
head -= 6;
|
|
uint16 h0 = READ_LE_UINT16(head);
|
|
// 3 = 2 bytes for the uint16 and 1 byte for an unused char
|
|
head += 3;
|
|
uint16 h3 = READ_LE_UINT16(head);
|
|
head += 2;
|
|
byte *data = h0 + head + 26;
|
|
h3 -= 6;
|
|
head += h3;
|
|
for (; h3; h3--)
|
|
*data-- = *head--;
|
|
head = data + 1;
|
|
data = ptr;
|
|
expandHSQ(head, data);
|
|
}
|
|
|
|
void EdenGame::openbigfile() {
|
|
_bigfile.open("EDEN.DAT");
|
|
|
|
char buf[16];
|
|
int count = _bigfile.readUint16LE();
|
|
_bigfileHeader = new PakHeaderNode(count);
|
|
for (int j = 0; j < count; j++) {
|
|
for (int k = 0; k < 16; k++)
|
|
buf[k] = _bigfile.readByte();
|
|
_bigfileHeader->_files[j]._name = Common::String(buf);
|
|
_bigfileHeader->_files[j]._size = _bigfile.readUint32LE();
|
|
_bigfileHeader->_files[j]._offs = _bigfile.readUint32LE();
|
|
_bigfileHeader->_files[j]._flag = _bigfile.readByte();
|
|
}
|
|
|
|
_vm->_video->resetInternals();
|
|
_vm->_video->setFile(&_bigfile);
|
|
}
|
|
|
|
void EdenGame::closebigfile() {
|
|
_bigfile.close();
|
|
}
|
|
|
|
int EdenGame::loadmusicfile(int16 num) {
|
|
PakHeaderItem *file = &_bigfileHeader->_files[num + 435];
|
|
int32 size = file->_size;
|
|
int32 offs = file->_offs;
|
|
_bigfile.seek(offs, SEEK_SET);
|
|
uint32 numread = size;
|
|
if (numread > kMaxMusicSize)
|
|
error("Music file %s is too big", file->_name.c_str());
|
|
_bigfile.read(_musicBuf, numread);
|
|
return size;
|
|
}
|
|
|
|
void EdenGame::loadRawFile(uint16 num, byte *buffer) {
|
|
if (_vm->getPlatform() == Common::kPlatformDOS) {
|
|
if ((_vm->isDemo() && num > 2204) || num > 2472)
|
|
error("Trying to read invalid game resource");
|
|
}
|
|
|
|
assert(num < _bigfileHeader->_count);
|
|
PakHeaderItem *file = &_bigfileHeader->_files[num];
|
|
int32 size = file->_size;
|
|
int32 offs = file->_offs;
|
|
|
|
_bigfile.seek(offs, SEEK_SET);
|
|
_bigfile.read(buffer, size);
|
|
}
|
|
|
|
void EdenGame::loadIconFile(uint16 num, Icon *buffer) {
|
|
if (_vm->getPlatform() == Common::kPlatformDOS) {
|
|
if ((_vm->isDemo() && num > 2204) || num > 2472)
|
|
error("Trying to read invalid game resource");
|
|
}
|
|
|
|
assert(num < _bigfileHeader->_count);
|
|
PakHeaderItem *file = &_bigfileHeader->_files[num];
|
|
int32 size = file->_size;
|
|
int32 offs = file->_offs;
|
|
debug("* Loading icon - Resource %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), offs, size);
|
|
_bigfile.seek(offs, SEEK_SET);
|
|
|
|
int count = size / 18; // sizeof(Icon)
|
|
for (int i = 0; i < count; i++) {
|
|
if (_vm->getPlatform() == Common::kPlatformMacintosh) {
|
|
buffer[i].sx = _bigfile.readSint16BE();
|
|
buffer[i].sy = _bigfile.readSint16BE();
|
|
buffer[i].ex = _bigfile.readSint16BE();
|
|
buffer[i].ey = _bigfile.readSint16BE();
|
|
buffer[i]._cursorId = _bigfile.readUint16BE();
|
|
buffer[i]._actionId = _bigfile.readUint32BE();
|
|
buffer[i]._objectId = _bigfile.readUint32BE();
|
|
}
|
|
else {
|
|
buffer[i].sx = _bigfile.readSint16LE();
|
|
buffer[i].sy = _bigfile.readSint16LE();
|
|
buffer[i].ex = _bigfile.readSint16LE();
|
|
buffer[i].ey = _bigfile.readSint16LE();
|
|
buffer[i]._cursorId = _bigfile.readUint16LE();
|
|
buffer[i]._actionId = _bigfile.readUint32LE();
|
|
buffer[i]._objectId = _bigfile.readUint32LE();
|
|
}
|
|
}
|
|
}
|
|
|
|
void EdenGame::loadRoomFile(uint16 num, Room *buffer) {
|
|
if (_vm->getPlatform() == Common::kPlatformDOS) {
|
|
if ((_vm->isDemo() && num > 2204) || num > 2472)
|
|
error("Trying to read invalid game resource");
|
|
}
|
|
|
|
assert(num < _bigfileHeader->_count);
|
|
PakHeaderItem *file = &_bigfileHeader->_files[num];
|
|
int32 size = file->_size;
|
|
int32 offs = file->_offs;
|
|
debug("* Loading room - Resource %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), offs, size);
|
|
_bigfile.seek(offs, SEEK_SET);
|
|
|
|
int count = size / 14; // sizeof(Room)
|
|
for (int i = 0; i < count; i++) {
|
|
buffer[i]._id = _bigfile.readByte();
|
|
for (int j = 0; j < 4; j++)
|
|
buffer[i]._exits[j] = _bigfile.readByte();
|
|
buffer[i]._flags = _bigfile.readByte();
|
|
if (_vm->getPlatform() == Common::kPlatformMacintosh) {
|
|
buffer[i]._bank = _bigfile.readUint16BE();
|
|
buffer[i]._party = _bigfile.readUint16BE();
|
|
}
|
|
else {
|
|
buffer[i]._bank = _bigfile.readUint16LE();
|
|
buffer[i]._party = _bigfile.readUint16LE();
|
|
}
|
|
buffer[i]._level = _bigfile.readByte();
|
|
buffer[i]._video = _bigfile.readByte();
|
|
buffer[i]._location = _bigfile.readByte();
|
|
buffer[i]._backgroundBankNum = _bigfile.readByte();
|
|
}
|
|
}
|
|
|
|
// Original name: shnmfl
|
|
void EdenGame::loadHnm(uint16 num) {
|
|
unsigned int resNum = num - 1 + 485;
|
|
assert(resNum < _bigfileHeader->_count);
|
|
PakHeaderItem *file = &_bigfileHeader->_files[resNum];
|
|
int size = file->_size;
|
|
int offs = file->_offs;
|
|
debug("* Loading movie %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size);
|
|
_vm->_video->_file->seek(offs, SEEK_SET);
|
|
}
|
|
|
|
// Original name: ssndfl
|
|
int EdenGame::loadSound(uint16 num) {
|
|
unsigned int resNum = num - 1 + ((_vm->getPlatform() == Common::kPlatformDOS && _vm->isDemo()) ? 656 : 661);
|
|
assert(resNum < _bigfileHeader->_count);
|
|
PakHeaderItem *file = &_bigfileHeader->_files[resNum];
|
|
int32 size = file->_size;
|
|
int32 offs = file->_offs;
|
|
debug("* Loading sound %d (%s) at 0x%X, %d bytes", num, file->_name.c_str(), (uint)offs, size);
|
|
if (_soundAllocated) {
|
|
free(_voiceSamplesBuffer);
|
|
_voiceSamplesBuffer = nullptr;
|
|
_soundAllocated = false; //TODO: bug??? no alloc
|
|
}
|
|
else {
|
|
_voiceSamplesBuffer = (byte *)malloc(size);
|
|
_soundAllocated = true;
|
|
}
|
|
|
|
_bigfile.seek(offs, SEEK_SET);
|
|
//For PC loaded data is a VOC file, on Mac version this is a raw samples
|
|
if (_vm->getPlatform() == Common::kPlatformMacintosh)
|
|
_bigfile.read(_voiceSamplesBuffer, size);
|
|
else {
|
|
// VOC files also include extra information for lipsync
|
|
// 1. Standard VOC header
|
|
_bigfile.read(_voiceSamplesBuffer, 0x1A);
|
|
|
|
// 2. Lipsync?
|
|
unsigned char chunkType = _bigfile.readByte();
|
|
|
|
uint32 val = 0;
|
|
_bigfile.read(&val, 3);
|
|
unsigned int chunkLen = FROM_LE_32(val);
|
|
|
|
if (chunkType == 5) {
|
|
_bigfile.read(_gameLipsync + 7260, chunkLen);
|
|
chunkType = _bigfile.readByte();
|
|
_bigfile.read(&val, 3);
|
|
chunkLen = FROM_LE_32(val);
|
|
}
|
|
|
|
// 3. Normal sound data
|
|
if (chunkType == 1) {
|
|
_bigfile.readUint16LE();
|
|
size = chunkLen - 2;
|
|
_bigfile.read(_voiceSamplesBuffer, size);
|
|
}
|
|
}
|
|
|
|
return size;
|
|
}
|
|
|
|
void EdenGame::convertMacToPC() {
|
|
// Convert all mac (big-endian) resources to native format
|
|
// Array of longs
|
|
int *p = (int *)_gameLipsync;
|
|
for (int i = 0; i < 7240 / 4; i++)
|
|
p[i] = FROM_BE_32(p[i]);
|
|
}
|
|
|
|
void EdenGame::loadpermfiles() {
|
|
Common::File f;
|
|
const int kNumIcons = 136;
|
|
const int kNumRooms = 424;
|
|
const int kNumFollowers = 15;
|
|
const int kNumLabyrinthPath = 70;
|
|
const int kNumDinoSpeedForCitaLevel = 16;
|
|
const int kNumTabletView = 12;
|
|
const int kNumPersoRoomBankTable = 84;
|
|
const int kNumGotos = 130;
|
|
const int kNumObjects = 42;
|
|
const int kNumObjectLocations = 45;
|
|
const int kNumPersons = 58;
|
|
const int kNumCitadel = 7;
|
|
const int kNumCharacterRects = 19;
|
|
const int kNumCharacters = 20;
|
|
const int kNumAreas = 12;
|
|
// tab_2CEF0
|
|
// tab_2CF70
|
|
const int kNumActionCursors = 299;
|
|
|
|
const int expectedDataSize =
|
|
kNumIcons * 18 + // sizeof(Icon)
|
|
kNumRooms * 14 + // sizeof(Room)
|
|
kNumFollowers * 16 + // sizeof(Follower)
|
|
kNumLabyrinthPath +
|
|
kNumDinoSpeedForCitaLevel +
|
|
kNumTabletView +
|
|
kNumPersoRoomBankTable +
|
|
kNumGotos * 5 + // sizeof(Goto)
|
|
kNumObjects * 12 + // sizeof(object_t)
|
|
kNumObjectLocations * 2 +
|
|
kNumPersons * 18 + // sizeof(perso_t)
|
|
kNumCitadel * 34 + // sizeof(Citadel)
|
|
kNumCharacterRects * 8 +
|
|
kNumCharacters * 5 +
|
|
kNumAreas * 10 + // (sizeof(Area) - 4)
|
|
64 * 2 +
|
|
64 * 2 +
|
|
kNumActionCursors +
|
|
12 +
|
|
3 * 6 * 2 * 3 * 2;
|
|
|
|
if (f.open("cryo.dat")) {
|
|
const int dataSize = f.size() - 8 - 4; // CRYODATA + version
|
|
char headerId[9];
|
|
|
|
f.read(headerId, 8);
|
|
headerId[8] = '\0';
|
|
if (strcmp(headerId, "CRYODATA"))
|
|
error("Invalid cryo.dat aux data file");
|
|
|
|
if (f.readUint32LE() != CRYO_DAT_VER)
|
|
error("Incorrect data version for cryo.dat");
|
|
|
|
if (dataSize != expectedDataSize)
|
|
error("Mismatching data in cryo.dat aux data file (got %d, expected %d)", dataSize, expectedDataSize);
|
|
}
|
|
else
|
|
error("Can not load cryo.dat");
|
|
|
|
switch (_vm->getPlatform()) {
|
|
case Common::kPlatformDOS:
|
|
// Since PC version stores hotspots and rooms info in the executable, load them from premade resource file
|
|
for (int i = 0; i < kNumIcons; i++) {
|
|
_gameIcons[i].sx = f.readSint16LE();
|
|
_gameIcons[i].sy = f.readSint16LE();
|
|
_gameIcons[i].ex = f.readSint16LE();
|
|
_gameIcons[i].ey = f.readSint16LE();
|
|
_gameIcons[i]._cursorId = f.readUint16LE();
|
|
_gameIcons[i]._actionId = f.readUint32LE();
|
|
_gameIcons[i]._objectId = f.readUint32LE();
|
|
}
|
|
|
|
for (int i = 0; i < kNumRooms; i++) {
|
|
_gameRooms[i]._id = f.readByte();
|
|
for (int j = 0; j < 4; j++)
|
|
_gameRooms[i]._exits[j] = f.readByte();
|
|
_gameRooms[i]._flags = f.readByte();
|
|
_gameRooms[i]._bank = f.readUint16LE();
|
|
_gameRooms[i]._party = f.readUint16LE();
|
|
_gameRooms[i]._level = f.readByte();
|
|
_gameRooms[i]._video = f.readByte();
|
|
_gameRooms[i]._location = f.readByte();
|
|
_gameRooms[i]._backgroundBankNum = f.readByte();
|
|
}
|
|
break;
|
|
case Common::kPlatformMacintosh:
|
|
loadIconFile(2498, _gameIcons);
|
|
loadRoomFile(2497, _gameRooms);
|
|
loadRawFile(2486, _gameLipsync);
|
|
convertMacToPC();
|
|
|
|
// Skip the icons and rooms of the DOS version
|
|
f.skip(kNumIcons * 14 + kNumRooms * 11);
|
|
break;
|
|
default:
|
|
error("Unsupported platform");
|
|
}
|
|
|
|
// Read the common static data
|
|
|
|
for (int i = 0; i < kNumFollowers; i++) {
|
|
_followerList[i]._id = f.readSByte();
|
|
_followerList[i]._spriteNum = f.readSByte();
|
|
_followerList[i].sx = f.readSint16LE();
|
|
_followerList[i].sy = f.readSint16LE();
|
|
_followerList[i].ex = f.readSint16LE();
|
|
_followerList[i].ey = f.readSint16LE();
|
|
_followerList[i]._spriteBank = f.readSint16LE();
|
|
_followerList[i].ff_C = f.readSint16LE();
|
|
_followerList[i].ff_E = f.readSint16LE();
|
|
}
|
|
|
|
f.read(_labyrinthPath, kNumLabyrinthPath);
|
|
f.read(_dinoSpeedForCitadelLevel, kNumDinoSpeedForCitaLevel);
|
|
f.read(_tabletView, kNumTabletView);
|
|
f.read(_personRoomBankTable, kNumPersoRoomBankTable);
|
|
f.read(_gotos, kNumGotos * 5); // sizeof(Goto)
|
|
|
|
for (int i = 0; i < kNumObjects; i++) {
|
|
_objects[i]._id = f.readByte();
|
|
_objects[i]._flags = f.readByte();
|
|
_objects[i]._locations = f.readUint32LE();
|
|
_objects[i]._itemMask = f.readUint16LE();
|
|
_objects[i]._powerMask = f.readUint16LE();
|
|
_objects[i]._count = f.readSint16LE();
|
|
}
|
|
|
|
for (int i = 0; i < kNumObjectLocations; i++) {
|
|
_objectLocations[i] = f.readUint16LE();
|
|
}
|
|
|
|
for (int i = 0; i < kNumPersons; i++) {
|
|
_persons[i]._roomNum = f.readUint16LE();
|
|
_persons[i]._actionId = f.readUint16LE();
|
|
_persons[i]._partyMask = f.readUint16LE();
|
|
_persons[i]._id = f.readByte();
|
|
_persons[i]._flags = f.readByte();
|
|
_persons[i]._roomBankId = f.readByte();
|
|
_persons[i]._spriteBank = f.readByte();
|
|
_persons[i]._items = f.readUint16LE();
|
|
_persons[i]._powers = f.readUint16LE();
|
|
_persons[i]._targetLoc = f.readByte();
|
|
_persons[i]._lastLoc = f.readByte();
|
|
_persons[i]._speed = f.readByte();
|
|
_persons[i]._steps = f.readByte();
|
|
}
|
|
|
|
for (int i = 0; i < kNumCitadel; i++) {
|
|
_citadelList[i]._id = f.readSint16LE();
|
|
for (int j = 0; j < 8; j++)
|
|
_citadelList[i]._bank[j] = f.readSint16LE();
|
|
for (int j = 0; j < 8; j++)
|
|
_citadelList[i]._video[j] = f.readSint16LE();
|
|
}
|
|
|
|
for (int i = 0; i < kNumCharacterRects; i++) {
|
|
_characterRects[i].left = f.readSint16LE();
|
|
_characterRects[i].top = f.readSint16LE();
|
|
_characterRects[i].right = f.readSint16LE();
|
|
_characterRects[i].bottom = f.readSint16LE();
|
|
}
|
|
|
|
f.read(_characterArray, kNumCharacters * 5);
|
|
|
|
for (int i = 0; i < kNumAreas; i++) {
|
|
_areasTable[i]._num = f.readByte();
|
|
_areasTable[i]._type = f.readByte();
|
|
_areasTable[i]._flags = f.readUint16LE();
|
|
_areasTable[i]._firstRoomIdx = f.readUint16LE();
|
|
_areasTable[i]._citadelLevel = f.readByte();
|
|
_areasTable[i]._placeNum = f.readByte();
|
|
_areasTable[i]._citadelRoomPtr = nullptr;
|
|
_areasTable[i]._visitCount = f.readSint16LE();
|
|
}
|
|
|
|
for (int i = 0; i < 64; i++) {
|
|
tab_2CEF0[i] = f.readSint16LE();
|
|
}
|
|
|
|
for (int i = 0; i < 64; i++) {
|
|
tab_2CF70[i] = f.readSint16LE();
|
|
}
|
|
|
|
f.read(_actionCursors, kNumActionCursors);
|
|
f.read(_mapMode, 12);
|
|
f.read(_cubeTextureCoords, 3 * 6 * 2 * 3 * 2);
|
|
|
|
f.close();
|
|
|
|
loadRawFile(0, _mainBankBuf);
|
|
loadRawFile(402, _gameFont);
|
|
loadRawFile(404, _gameDialogs);
|
|
loadRawFile(403, _gameConditions);
|
|
}
|
|
|
|
bool EdenGame::ReadDataSyncVOC(unsigned int num) {
|
|
unsigned int resNum = num - 1 + ((_vm->getPlatform() == Common::kPlatformDOS && _vm->isDemo()) ? 656 : 661);
|
|
unsigned char vocHeader[0x1A];
|
|
int filePos = 0;
|
|
loadpartoffile(resNum, vocHeader, filePos, sizeof(vocHeader));
|
|
filePos += sizeof(vocHeader);
|
|
unsigned char chunkType = 0;
|
|
loadpartoffile(resNum, &chunkType, sizeof(vocHeader), 1);
|
|
filePos++;
|
|
if (chunkType == 5) {
|
|
uint32 chunkLen = 0;
|
|
loadpartoffile(resNum, &chunkLen, filePos, 3);
|
|
filePos += 3;
|
|
chunkLen = FROM_LE_32(chunkLen);
|
|
loadpartoffile(resNum, _gameLipsync + 7260, filePos, chunkLen);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool EdenGame::ReadDataSync(uint16 num) {
|
|
if (_vm->getPlatform() == Common::kPlatformMacintosh) {
|
|
long pos = READ_LE_UINT32(_gameLipsync + num * 4);
|
|
if (pos != -1) {
|
|
long len = 1024;
|
|
loadpartoffile(1936, _gameLipsync + 7260, pos, len);
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
return ReadDataSyncVOC(num + 1); //TODO: remove -1 in caller
|
|
return false;
|
|
}
|
|
|
|
void EdenGame::loadpartoffile(uint16 num, void *buffer, int32 pos, int32 len) {
|
|
assert(num < _bigfileHeader->_count);
|
|
PakHeaderItem *file = &_bigfileHeader->_files[num];
|
|
int32 offs = READ_LE_UINT32(&file->_offs);
|
|
debug("* Loading partial resource %d (%s) at 0x%X(+0x%X), %d bytes", num, file->_name.c_str(), offs, pos, len);
|
|
_bigfile.seek(offs + pos, SEEK_SET);
|
|
_bigfile.read(buffer, len);
|
|
}
|
|
|
|
void EdenGame::expandHSQ(byte *input, byte *output) {
|
|
byte *src = input;
|
|
byte *dst = output;
|
|
byte *ptr;
|
|
uint16 bit; // bit
|
|
uint16 queue = 0; // queue
|
|
uint16 len = 0;
|
|
int16 ofs;
|
|
#define GetBit \
|
|
bit = queue & 1; \
|
|
queue >>= 1; \
|
|
if (!queue) { \
|
|
queue = (src[1] << 8) | src[0]; src += 2; \
|
|
bit = queue & 1; \
|
|
queue = (queue >> 1) | 0x8000; \
|
|
}
|
|
|
|
for (;;) {
|
|
GetBit;
|
|
if (bit)
|
|
*dst++ = *src++;
|
|
else {
|
|
len = 0;
|
|
GetBit;
|
|
if (!bit) {
|
|
GetBit;
|
|
len = (len << 1) | bit;
|
|
GetBit;
|
|
len = (len << 1) | bit;
|
|
ofs = 0xFF00 | *src++; //TODO: -256
|
|
}
|
|
else {
|
|
ofs = (src[1] << 8) | src[0];
|
|
src += 2;
|
|
len = ofs & 7;
|
|
ofs = (ofs >> 3) | 0xE000;
|
|
if (!len) {
|
|
len = *src++;
|
|
if (!len)
|
|
break;
|
|
}
|
|
}
|
|
ptr = dst + ofs;
|
|
len += 2;
|
|
while (len--)
|
|
*dst++ = *ptr++;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace Cryo
|