Files
scummvm-tools/extract_agos.cpp
T
Hampus Nilsson 168e91e076 *Started on CLI interface, already works but there are many edges to sort out.
*Added a common 'Tools' class to be used by both the CLI and the GUI, right now it's NOT in use by the GUI, so there is some code clutter.
*Rename gui/tools.h to gui/tools.cpp
*Tools now know their own type.
*Some other small changes.

svn-id: r42670
2009-07-23 01:41:14 +00:00

213 lines
4.5 KiB
C++

/* extract_agos - Extracts the packed files used in the Amiga and AtariST versions
* Copyright (C) 2004-2006 The ScummVM Team
*
* 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.
*
* $URL$
* $Id$
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include "extract_agos.h"
ExtractAgos::ExtractAgos(const std::string &name) : Tool(name, TOOLTYPE_EXTRACTION) {
_filelen = 0;
ToolInput input;
input.format = "*.*";
_inputPaths.push_back(input);
_helptext = "\nUsage: " + _name + " [-o outputname] infilename\n";
}
// Run the actual tool
void ExtractAgos::execute() {
// Loop through all input files
Filename infilename(_inputPaths[0].path);
uint8 *x = (uint8 *)loadfile(infilename);
_outputPath.setFullName(infilename.getFullName());
uint32 decrlen = simon_decr_length(x, (uint32) _filelen);
uint8 *out = (uint8 *)malloc(decrlen);
if (out) {
if (simon_decr(x, out, _filelen)) {
savefile(_outputPath.getFullPath(), out, decrlen);
} else {
print("%s: decrunch error\n", infilename.getFullPath().c_str());
}
free(x);
free(out);
}
}
#define EndGetM32(a) ((((a)[0])<<24)|(((a)[1])<<16)|(((a)[2])<<8)|((a)[3]))
#define SD_GETBIT(var) do { \
if (!bits--) { s -= 4; if (s < src) return 0; bb=EndGetM32(s); bits=31; } \
(var) = bb & 1; bb >>= 1; \
} while (0)
#define SD_GETBITS(var, nbits) do { \
bc=(nbits); (var)=0; while (bc--) {(var)<<=1; SD_GETBIT(bit); (var)|=bit; } \
} while (0)
#define SD_TYPE_LITERAL (0)
#define SD_TYPE_MATCH (1)
int ExtractAgos::simon_decr(uint8 *src, uint8 *dest, uint32 srclen) {
uint8 *s = &src[srclen - 4];
uint32 destlen = EndGetM32(s);
uint32 bb, x, y;
uint8 *d = &dest[destlen];
uint8 bc, bit, bits, type;
/* initialise bit buffer */
s -= 4;
x = EndGetM32(s);
bb = x;
bits = 0;
do {
x >>= 1;
bits++;
} while (x);
bits--;
while (d > dest) {
SD_GETBIT(x);
if (x) {
SD_GETBITS(x, 2);
if (x == 0) {
type = SD_TYPE_MATCH;
x = 9;
y = 2;
} else if (x == 1) {
type = SD_TYPE_MATCH;
x = 10;
y = 3;
} else if (x == 2) {
type = SD_TYPE_MATCH;
x = 12;
SD_GETBITS(y, 8);
} else {
type = SD_TYPE_LITERAL;
x = 8;
y = 8;
}
} else {
SD_GETBIT(x);
if (x) {
type = SD_TYPE_MATCH;
x = 8;
y = 1;
} else {
type = SD_TYPE_LITERAL;
x = 3;
y = 0;
}
}
if (type == SD_TYPE_LITERAL) {
SD_GETBITS(x, x); y += x;
if ((int)(y + 1) > (d - dest)) {
return 0; /* overflow? */
}
do {
SD_GETBITS(x, 8);
*--d = x;
} while (y-- > 0);
} else {
if ((int)(y + 1) > (d - dest)) {
return 0; /* overflow? */
}
SD_GETBITS(x, x);
if ((d + x) > (dest + destlen)) {
return 0; /* offset overflow? */
}
do {
d--;
*d = d[x];
} while (y-- > 0);
}
}
/* successful decrunch */
return 1;
}
uint32 ExtractAgos::simon_decr_length(uint8 *src, uint32 srclen) {
return EndGetM32(&src[srclen - 4]);
}
/**
* loadfile(filename) loads a file from disk, and returns a pointer to that
* loaded file, or returns NULL on failure
* call free() on ptr to free memory
* size of loaded file is available in global var 'filelen'
*
* @param name The name of the file to be loaded
*/
void *ExtractAgos::loadfile(const Filename &name) {
File file(name, FILEMODE_READ);
// Using global here is not pretty
_filelen = file.size();
void *mem = malloc(file.size());
// Read data
file.read(mem, 1, _filelen);
return mem;
}
/**
* Saves N bytes from the buffer to the target file.
* Throws FileException on failure
*
* @param name The name of the file to save to
* @param mem Where to get data from
* @param length How many bytes to write
*/
void ExtractAgos::savefile(const Filename &name, void *mem, size_t length) {
File file(name, FILEMODE_WRITE);
file.write(mem, 1, length);
}
#ifdef STANDALONE_MAIN
int main(int argc, char *argv[]) {
ExtractAgos agos(argv[0]);
return agos.run(argc, argv);
}
#endif