2007-06-28 10:47:08 -07:00
|
|
|
#include <stdlib.h>
|
|
|
|
#ifdef WIN32
|
|
|
|
#include <windows.h>
|
|
|
|
#endif //looks like we need this. --Qamly
|
|
|
|
#include "adpcm.h"
|
|
|
|
#include "frame.h"
|
|
|
|
#include "rpl_reader.h"
|
2006-05-08 08:10:45 -07:00
|
|
|
#include <physfs.h>
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
unsigned int rpl_decode_sound_none(RPL* rpl, short* buffer, unsigned int buffer_size);
|
|
|
|
unsigned int rpl_decode_sound_unknown(RPL* rpl, short* buffer, unsigned int buffer_size);
|
|
|
|
unsigned int rpl_decode_sound_raw(RPL* rpl, short* buffer, unsigned int buffer_size);
|
|
|
|
unsigned int rpl_decode_sound_adpcm(RPL* rpl, short* buffer, unsigned int buffer_size);
|
|
|
|
|
|
|
|
unsigned int rpl_decode_video_unknown(RPL* rpl, char* in, unsigned int in_size, char* out);
|
|
|
|
unsigned int dec130_decode(RPL* rpl, char* in, unsigned int in_size, char* out);
|
|
|
|
|
|
|
|
//*************************************************************************************
|
|
|
|
|
|
|
|
char* data_buffer = NULL;
|
|
|
|
unsigned int data_buffer_size = 0;
|
|
|
|
|
|
|
|
void resize_data_buffer(unsigned int size) {
|
|
|
|
if (size > data_buffer_size) {
|
|
|
|
if (data_buffer != NULL) {
|
|
|
|
free(data_buffer);
|
|
|
|
}
|
|
|
|
data_buffer = malloc(size);
|
|
|
|
data_buffer_size = size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//*************************************************************************************
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
static char *readline(PHYSFS_file *f, char *linebuf, size_t len) {
|
|
|
|
char c;
|
|
|
|
size_t i = 0;
|
|
|
|
|
|
|
|
for (i = 0; i < len-1; i++) {
|
|
|
|
if (PHYSFS_read(f, &c, 1, 1) != 1) {
|
|
|
|
DBERROR(("Error reading from sequence file: %s\n",
|
|
|
|
PHYSFS_getLastError()));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (c == '\n' || !isprint(c))
|
|
|
|
break;
|
|
|
|
linebuf[i] = c;
|
|
|
|
}
|
|
|
|
|
|
|
|
linebuf[i] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
static int readint(PHYSFS_file *f, char *linebuf, size_t len) {
|
|
|
|
int num;
|
|
|
|
readline(f, linebuf, len);
|
|
|
|
if (sscanf(linebuf, "%u", &num) < 1)
|
|
|
|
num = 0;
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
static float readfloat(PHYSFS_file *f, char *linebuf, size_t len) {
|
|
|
|
float num;
|
|
|
|
readline(f, linebuf, len);
|
|
|
|
if (sscanf(linebuf, "%f", &num) < 1)
|
|
|
|
num = 0.0;
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
RPL*
|
|
|
|
rpl_open(char* filename) {
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_file* f;
|
|
|
|
RPL* rpl;
|
|
|
|
char buf[80];
|
|
|
|
int tmp;
|
|
|
|
int ret;
|
|
|
|
size_t len = sizeof(buf);
|
|
|
|
|
|
|
|
/* FIXME: we should just clean up our data */
|
|
|
|
for (tmp = 0; tmp < strlen(filename); tmp++) {
|
|
|
|
if (filename[tmp] == '\\')
|
|
|
|
filename[tmp] = '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
f = PHYSFS_openRead(filename);
|
|
|
|
if (f == NULL) {
|
|
|
|
DBPRINTF(("Error reading %s: %s\n",
|
|
|
|
filename, PHYSFS_getLastError()));
|
2007-06-28 10:47:08 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
/* going to do lots of small reads, so use a buffer */
|
|
|
|
PHYSFS_setBuffer(f, 1024);
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
rpl = (RPL*)malloc(sizeof(RPL));
|
|
|
|
rpl->chunks = NULL;
|
|
|
|
|
|
|
|
rpl->f = f;
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
if (strcmp(readline(f, buf, len), "ARMovie") != 0)
|
|
|
|
DBPRINTF(("%s missing RPL magic number\n", filename));
|
|
|
|
readline(f, buf, len); /* discard filename */
|
|
|
|
readline(f, buf, len); /* discard copyright */
|
|
|
|
if (strcmp(readline(f, buf, len), "ESCAPE 2.0") != 0)
|
|
|
|
/* This field is really "author", but.. */
|
|
|
|
DBPRINTF(("%s not in \"ESCAPE 2.0\" format?\n", filename));
|
|
|
|
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
tmp = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
switch (tmp) {
|
|
|
|
case 130:
|
|
|
|
rpl->video_decoder = dec130_decode;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rpl->video_decoder = rpl_decode_video_unknown;
|
2006-05-08 08:10:45 -07:00
|
|
|
printf("Unknown video format %i\n", tmp);
|
2007-06-28 10:47:08 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->width = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("width : %i\n", rpl->width);
|
2006-05-08 08:10:45 -07:00
|
|
|
|
|
|
|
rpl->height = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("height : %i\n", rpl->height);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->bpp = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("bpp : %i\n", rpl->bpp);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->fps = readfloat(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("fps : %f\n\n", rpl->fps);
|
|
|
|
rpl->current_video_frame = 0;
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
tmp = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
switch (tmp) {
|
|
|
|
case 0:
|
|
|
|
rpl->sound_decoder = rpl_decode_sound_none;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
rpl->sound_decoder = rpl_decode_sound_raw;
|
|
|
|
break;
|
|
|
|
case 101:
|
|
|
|
rpl->sound_decoder = rpl_decode_sound_adpcm;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
rpl->sound_decoder = rpl_decode_sound_unknown;
|
|
|
|
printf("Unknown sound format %i\n", tmp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
rpl->current_sound_frame = 0;
|
2006-05-08 08:10:45 -07:00
|
|
|
|
|
|
|
rpl->samples = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("samples : %i\n", rpl->samples);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->channels = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("channels : %i\n", rpl->channels);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->bps = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("bits per sample : %i\n\n", rpl->bps);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->fpc = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("frames per chunk : %i\n", rpl->fpc);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->nb_chunks = readint(f, buf, len) + 1;
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("chunks : %i\n", rpl->nb_chunks);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->ocs = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("odd chunk size : %i\n", rpl->ocs);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->ecs = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("even chunk size : %i\n", rpl->ecs);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->otcc = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("offset to chunk cat : %i\n\n", rpl->otcc);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->ots = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("offset to sprite : %i\n", rpl->ots);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->sprite_size = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("size of sprite : %i\n\n", rpl->sprite_size);
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
rpl->otkf = readint(f, buf, len);
|
2007-06-28 10:47:08 -07:00
|
|
|
//printf("offset to key frames : %i\n", rpl->otkf);
|
|
|
|
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
unsigned int max_video_size = 0;
|
|
|
|
|
|
|
|
rpl->chunks = malloc(sizeof(RPL_chunk_info_t)*rpl->nb_chunks);
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_seek(f, rpl->otcc);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
for (i = 0; i < rpl->nb_chunks; ++i) {
|
2006-05-08 08:10:45 -07:00
|
|
|
readline(f, buf, len);
|
|
|
|
if (sscanf(buf, "%i,%i;%i", &rpl->chunks[i].offset, &rpl->chunks[i].video_size, &rpl->chunks[i].audio_size) != 3) {
|
2007-06-28 10:47:08 -07:00
|
|
|
printf("Error in chunk catalog\n");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rpl->chunks[i].video_size > max_video_size) {
|
|
|
|
max_video_size = rpl->chunks[i].video_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
resize_data_buffer(max_video_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return rpl;
|
|
|
|
|
|
|
|
error:
|
|
|
|
free(rpl->chunks);
|
|
|
|
free(rpl);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rpl_decode_sound_none(RPL* rpl, short* buffer, unsigned int buffer_size) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rpl_decode_sound_unknown(RPL* rpl, short* buffer, unsigned int buffer_size) {
|
|
|
|
unsigned int i;
|
|
|
|
unsigned total_audio_size = 0;
|
|
|
|
char* audio_buffer;
|
|
|
|
char* tmp;
|
|
|
|
FILE* out;
|
|
|
|
|
|
|
|
printf("Saving unknown sound stream to file\n");
|
|
|
|
for (i = 0; i < rpl->nb_chunks; ++i) {
|
|
|
|
total_audio_size += rpl->chunks[i].audio_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
audio_buffer = malloc(total_audio_size);
|
|
|
|
tmp = audio_buffer;
|
|
|
|
|
|
|
|
for (i = 0; i < rpl->nb_chunks; ++i) {
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_seek(rpl->f, rpl->chunks[i].offset+rpl->chunks[i].video_size);
|
|
|
|
PHYSFS_read(rpl->f, tmp, rpl->chunks[i].audio_size, 1);
|
2007-06-28 10:47:08 -07:00
|
|
|
tmp += rpl->chunks[i].audio_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
out = fopen("unknown_sound", "wb");
|
|
|
|
fwrite(audio_buffer, total_audio_size, 1, out);
|
|
|
|
fclose(out);
|
|
|
|
|
|
|
|
free(audio_buffer);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rpl_decode_sound_raw(RPL* rpl, short* buffer, unsigned int buffer_size) {
|
|
|
|
unsigned int size = 0;
|
|
|
|
short* tmp = buffer;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
unsigned int cf = rpl->current_sound_frame;
|
|
|
|
unsigned int audio_frame_size = rpl->chunks[cf].audio_size;
|
|
|
|
|
|
|
|
if (rpl->current_sound_frame >= rpl->nb_chunks) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (size + (audio_frame_size >> 1) > buffer_size) {
|
|
|
|
break;
|
|
|
|
}
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_seek(rpl->f, rpl->chunks[cf].offset+rpl->chunks[cf].video_size);
|
|
|
|
PHYSFS_read(rpl->f, tmp, audio_frame_size, 1);
|
2007-06-28 10:47:08 -07:00
|
|
|
tmp += audio_frame_size >> 1;
|
|
|
|
size += audio_frame_size >> 1;
|
|
|
|
rpl->current_sound_frame++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rpl_decode_sound_adpcm(RPL* rpl, short* buffer, unsigned int buffer_size) {
|
|
|
|
static unsigned char* tmp_buffer = NULL;
|
|
|
|
unsigned int tmp_buffer_size = 0;
|
|
|
|
unsigned int size = 0;
|
|
|
|
short* tmp = buffer;
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
unsigned int cf = rpl->current_sound_frame;
|
|
|
|
unsigned int audio_frame_size = rpl->chunks[cf].audio_size;
|
|
|
|
|
|
|
|
if (rpl->current_sound_frame >= rpl->nb_chunks) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (size + (audio_frame_size << 1) > buffer_size) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (audio_frame_size > tmp_buffer_size) {
|
|
|
|
tmp_buffer_size = audio_frame_size << 1;
|
|
|
|
free(tmp_buffer);
|
|
|
|
tmp_buffer = malloc(tmp_buffer_size);
|
|
|
|
}
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_seek(rpl->f, rpl->chunks[cf].offset+rpl->chunks[cf].video_size);
|
|
|
|
PHYSFS_read(rpl->f, tmp_buffer, audio_frame_size, 1);
|
2007-06-28 10:47:08 -07:00
|
|
|
adpcm_decode(tmp_buffer, audio_frame_size, &tmp);
|
|
|
|
size += audio_frame_size << 1;
|
|
|
|
rpl->current_sound_frame++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rpl_decode_sound(RPL* rpl, short* buffer, unsigned int buffer_size) {
|
|
|
|
return rpl->sound_decoder(rpl, buffer, buffer_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int rpl_decode_video_unknown(RPL* rpl, char* in, unsigned int in_size, char* out) {
|
|
|
|
unsigned int i, j;
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < in_size; i += 2, j += 3) {
|
|
|
|
out[j] = in[i];
|
|
|
|
out[j+1] = in[i+1];
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int rpl_decode_next_image(RPL* rpl, char* buffer)
|
|
|
|
{
|
2006-05-08 08:10:45 -07:00
|
|
|
unsigned int data_size;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
if (rpl->current_video_frame >= rpl->nb_chunks) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
data_size = rpl->chunks[rpl->current_video_frame].video_size;
|
2007-06-28 10:47:08 -07:00
|
|
|
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_seek(rpl->f, rpl->chunks[rpl->current_video_frame].offset);
|
|
|
|
PHYSFS_read(rpl->f, data_buffer, data_size, 1);
|
2007-06-28 10:47:08 -07:00
|
|
|
|
|
|
|
rpl->video_decoder(rpl, data_buffer, data_size, buffer);
|
|
|
|
|
|
|
|
return rpl->current_video_frame++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
rpl_close(RPL* rpl) {
|
|
|
|
if (rpl != NULL) {
|
2006-05-08 08:10:45 -07:00
|
|
|
PHYSFS_close(rpl->f);
|
2007-06-28 10:47:08 -07:00
|
|
|
free(rpl->chunks);
|
|
|
|
free(rpl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|