scummvm/engines/sci/scicore/resource_patch.cpp
2009-02-20 15:41:58 +00:00

217 lines
5.7 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.
*
* $URL$
* $Id$
*
*/
#include "sci/include/sciresource.h"
#include "sci/include/sci_memory.h"
void
sci0_sprintf_patch_file_name(char *string, resource_t *res) {
sprintf(string, "%s.%03i", sci_resource_types[res->type], res->number);
}
void
sci1_sprintf_patch_file_name(char *string, resource_t *res) {
sprintf(string, "%d.%s", res->number, sci_resource_type_suffixes[res->type]);
}
/* version-agnostic patch application */
static void
process_patch(ResourceSource *source,
char *entry, int restype, int resnumber, resource_t **resource_p, int *resource_nr_p) {
int fsize;
char filename[MAXPATHLEN];
if (restype == sci_invalid_resource)
return;
printf("Patching \"%s\": ", entry);
sprintf(filename, "%s%s", source->location.dir.name, entry);
fsize = sci_file_size(filename);
if (fsize < 0)
perror("""__FILE__"": (""__LINE__""): sci_file_size()");
else {
int file;
guint8 filehdr[2];
resource_t *newrsc = _scir_find_resource_unsorted(*resource_p,
*resource_nr_p,
restype,
resnumber);
if (fsize < 3) {
printf("File too small\n");
return;
}
file = open(entry, O_RDONLY);
if (!IS_VALID_FD(file))
perror("""__FILE__"": (""__LINE__""): open()");
else {
int patch_data_offset;
read(file, filehdr, 2);
patch_data_offset = filehdr[1];
if ((filehdr[0] & 0x7f) != restype) {
printf("Failed; resource type mismatch\n");
close(file);
} else if (patch_data_offset + 2 >= fsize) {
printf("Failed; patch starting at offset %d can't be in file of size %d\n", filehdr[1] + 2, fsize);
close(file);
} else {
/* Adjust for file offset */
fsize -= patch_data_offset;
/* Prepare destination, if neccessary */
if (!newrsc) {
/* Completely new resource! */
++(*resource_nr_p);
*resource_p = (resource_t*)sci_realloc(*resource_p,
*resource_nr_p
* sizeof(resource_t));
newrsc = (*resource_p - 1) + *resource_nr_p;
newrsc->alt_sources = NULL;
}
/* Overwrite everything, because we're patching */
newrsc->size = fsize - 2;
newrsc->id = restype << 11 | resnumber;
newrsc->number = resnumber;
newrsc->status = SCI_STATUS_NOMALLOC;
newrsc->type = restype;
newrsc->source = source;
newrsc->file_offset = 2 + patch_data_offset;
_scir_add_altsource(newrsc, source, 2);
close(file);
printf("OK\n");
}
}
}
}
int
sci0_read_resource_patches(ResourceSource *source, resource_t **resource_p, int *resource_nr_p) {
sci_dir_t dir;
char *entry;
char *caller_cwd = sci_getcwd();
chdir(source->location.dir.name);
sci_init_dir(&dir);
entry = sci_find_first(&dir, "*.???");
while (entry) {
int restype = sci_invalid_resource;
int resnumber = -1;
int i;
unsigned int resname_len;
char *endptr;
for (i = sci_view; i < sci_invalid_resource; i++)
if (scumm_strnicmp(sci_resource_types[i], entry,
strlen(sci_resource_types[i])) == 0)
restype = i;
if (restype != sci_invalid_resource) {
resname_len = strlen(sci_resource_types[restype]);
if (entry[resname_len] != '.')
restype = sci_invalid_resource;
else {
resnumber = strtol(entry + 1 + resname_len,
&endptr, 10); /* Get resource number */
if ((*endptr != '\0') || (resname_len + 1 == strlen(entry)))
restype = sci_invalid_resource;
if ((resnumber < 0) || (resnumber > 1000))
restype = sci_invalid_resource;
}
}
process_patch(source, entry, restype, resnumber, resource_p, resource_nr_p);
entry = sci_find_next(&dir);
}
chdir(caller_cwd);
free(caller_cwd);
return 0;
}
int
sci1_read_resource_patches(ResourceSource *source, resource_t **resource_p, int *resource_nr_p) {
sci_dir_t dir;
char *entry;
char *caller_cwd = sci_getcwd();
chdir(source->location.dir.name);
sci_init_dir(&dir);
entry = sci_find_first(&dir, "*.*");
while (entry) {
int restype = sci_invalid_resource;
int resnumber = -1;
int i;
char *endptr;
char *dot = strchr(entry, '.');
for (i = sci_view; i < sci_invalid_resource; i++) {
if (dot != NULL) {
if (scumm_strnicmp(sci_resource_type_suffixes[i], dot + 1, 3) == 0) {
restype = i;
}
}
}
if (restype != sci_invalid_resource) {
resnumber = strtol(entry,
&endptr, 10); /* Get resource number */
if (endptr != dot)
restype = sci_invalid_resource;
if (*(dot + 4) != '\0')
restype = sci_invalid_resource;
if ((resnumber < 0) || (resnumber > 8192))
restype = sci_invalid_resource;
}
process_patch(source, entry, restype, resnumber, resource_p, resource_nr_p);
entry = sci_find_next(&dir);
}
chdir(caller_cwd);
free(caller_cwd);
return 0;
}