2013-03-11 17:46:03 +00:00
|
|
|
/* This file is part of libmspack.
|
|
|
|
* (C) 2003-2004 Stuart Caie.
|
|
|
|
*
|
|
|
|
* libmspack is free software; you can redistribute it and/or modify it under
|
|
|
|
* the terms of the GNU Lesser General Public License (LGPL) version 2.1
|
|
|
|
*
|
|
|
|
* For further details, see the file COPYING.LIB distributed with libmspack
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include <config.h>
|
|
|
|
#endif
|
|
|
|
|
2013-03-11 17:51:11 +00:00
|
|
|
#include "system-mspack.h"
|
2013-03-11 17:46:03 +00:00
|
|
|
|
|
|
|
#ifndef LARGEFILE_SUPPORT
|
|
|
|
const char *largefile_msg = "library not compiled to support large files.";
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
int mspack_version(int entity) {
|
|
|
|
switch (entity) {
|
|
|
|
/* CHM decoder version 1 -> 2 changes:
|
|
|
|
* - added mschmd_sec_mscompressed::spaninfo
|
|
|
|
* - added mschmd_header::first_pmgl
|
|
|
|
* - added mschmd_header::last_pmgl
|
|
|
|
* - added mschmd_header::chunk_cache;
|
|
|
|
*/
|
|
|
|
case MSPACK_VER_MSCHMD:
|
|
|
|
return 2;
|
|
|
|
case MSPACK_VER_LIBRARY:
|
|
|
|
case MSPACK_VER_SYSTEM:
|
|
|
|
case MSPACK_VER_MSCABD:
|
|
|
|
case MSPACK_VER_MSSZDDD:
|
|
|
|
case MSPACK_VER_MSKWAJD:
|
|
|
|
return 1;
|
|
|
|
case MSPACK_VER_MSCABC:
|
|
|
|
case MSPACK_VER_MSCHMC:
|
|
|
|
case MSPACK_VER_MSLITD:
|
|
|
|
case MSPACK_VER_MSLITC:
|
|
|
|
case MSPACK_VER_MSHLPD:
|
|
|
|
case MSPACK_VER_MSHLPC:
|
|
|
|
case MSPACK_VER_MSSZDDC:
|
|
|
|
case MSPACK_VER_MSKWAJC:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mspack_sys_selftest_internal(int offt_size) {
|
|
|
|
return (sizeof(off_t) == offt_size) ? MSPACK_ERR_OK : MSPACK_ERR_SEEK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* validates a system structure */
|
|
|
|
int mspack_valid_system(struct mspack_system *sys) {
|
|
|
|
return (sys != NULL) && (sys->open != NULL) && (sys->close != NULL) &&
|
|
|
|
(sys->read != NULL) && (sys->write != NULL) && (sys->seek != NULL) &&
|
|
|
|
(sys->tell != NULL) && (sys->message != NULL) && (sys->alloc != NULL) &&
|
|
|
|
(sys->free != NULL) && (sys->copy != NULL) && (sys->null_ptr == NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* returns the length of a file opened for reading */
|
|
|
|
int mspack_sys_filelen(struct mspack_system *system,
|
|
|
|
struct mspack_file *file, off_t *length)
|
|
|
|
{
|
|
|
|
off_t current;
|
|
|
|
|
|
|
|
if (!system || !file || !length) return MSPACK_ERR_OPEN;
|
|
|
|
|
|
|
|
/* get current offset */
|
|
|
|
current = system->tell(file);
|
|
|
|
|
|
|
|
/* seek to end of file */
|
|
|
|
if (system->seek(file, (off_t) 0, MSPACK_SYS_SEEK_END)) {
|
|
|
|
return MSPACK_ERR_SEEK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get offset of end of file */
|
|
|
|
*length = system->tell(file);
|
|
|
|
|
|
|
|
/* seek back to original offset */
|
|
|
|
if (system->seek(file, current, MSPACK_SYS_SEEK_START)) {
|
|
|
|
return MSPACK_ERR_SEEK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MSPACK_ERR_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* definition of mspack_default_system -- if the library is compiled with
|
|
|
|
* MSPACK_NO_DEFAULT_SYSTEM, no default system will be provided. Otherwise,
|
|
|
|
* an appropriate default system (e.g. the standard C library, or some native
|
|
|
|
* API calls)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef MSPACK_NO_DEFAULT_SYSTEM
|
|
|
|
struct mspack_system *mspack_default_system = NULL;
|
|
|
|
#else
|
|
|
|
|
|
|
|
/* implementation of mspack_default_system for standard C library */
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
|
|
|
struct mspack_file_p {
|
|
|
|
FILE *fh;
|
|
|
|
const char *name;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct mspack_file *msp_open(struct mspack_system *self,
|
|
|
|
const char *filename, int mode)
|
|
|
|
{
|
|
|
|
struct mspack_file_p *fh;
|
|
|
|
const char *fmode;
|
2013-11-04 23:06:50 +00:00
|
|
|
(void)self;
|
2013-03-11 17:46:03 +00:00
|
|
|
|
|
|
|
switch (mode) {
|
|
|
|
case MSPACK_SYS_OPEN_READ: fmode = "rb"; break;
|
|
|
|
case MSPACK_SYS_OPEN_WRITE: fmode = "wb"; break;
|
|
|
|
case MSPACK_SYS_OPEN_UPDATE: fmode = "r+b"; break;
|
|
|
|
case MSPACK_SYS_OPEN_APPEND: fmode = "ab"; break;
|
|
|
|
default: return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fh = (struct mspack_file_p *) malloc(sizeof(struct mspack_file_p)))) {
|
|
|
|
fh->name = filename;
|
|
|
|
if ((fh->fh = fopen(filename, fmode))) return (struct mspack_file *) fh;
|
|
|
|
free(fh);
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msp_close(struct mspack_file *file) {
|
|
|
|
struct mspack_file_p *self = (struct mspack_file_p *) file;
|
|
|
|
if (self) {
|
|
|
|
fclose(self->fh);
|
|
|
|
free(self);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msp_read(struct mspack_file *file, void *buffer, int bytes) {
|
|
|
|
struct mspack_file_p *self = (struct mspack_file_p *) file;
|
|
|
|
if (self && buffer && bytes >= 0) {
|
|
|
|
size_t count = fread(buffer, 1, (size_t) bytes, self->fh);
|
|
|
|
if (!ferror(self->fh)) return (int) count;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msp_write(struct mspack_file *file, void *buffer, int bytes) {
|
|
|
|
struct mspack_file_p *self = (struct mspack_file_p *) file;
|
|
|
|
if (self && buffer && bytes >= 0) {
|
|
|
|
size_t count = fwrite(buffer, 1, (size_t) bytes, self->fh);
|
|
|
|
if (!ferror(self->fh)) return (int) count;
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int msp_seek(struct mspack_file *file, off_t offset, int mode) {
|
|
|
|
struct mspack_file_p *self = (struct mspack_file_p *) file;
|
|
|
|
if (self) {
|
|
|
|
switch (mode) {
|
|
|
|
case MSPACK_SYS_SEEK_START: mode = SEEK_SET; break;
|
|
|
|
case MSPACK_SYS_SEEK_CUR: mode = SEEK_CUR; break;
|
|
|
|
case MSPACK_SYS_SEEK_END: mode = SEEK_END; break;
|
|
|
|
default: return -1;
|
|
|
|
}
|
|
|
|
#ifdef HAVE_FSEEKO
|
|
|
|
return fseeko(self->fh, offset, mode);
|
|
|
|
#else
|
|
|
|
return fseek(self->fh, offset, mode);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static off_t msp_tell(struct mspack_file *file) {
|
|
|
|
struct mspack_file_p *self = (struct mspack_file_p *) file;
|
|
|
|
#ifdef HAVE_FSEEKO
|
|
|
|
return (self) ? (off_t) ftello(self->fh) : 0;
|
|
|
|
#else
|
|
|
|
return (self) ? (off_t) ftell(self->fh) : 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msp_msg(struct mspack_file *file, const char *format, ...) {
|
|
|
|
va_list ap;
|
|
|
|
if (file) fprintf(stderr, "%s: ", ((struct mspack_file_p *) file)->name);
|
|
|
|
va_start(ap, format);
|
|
|
|
vfprintf(stderr, format, ap);
|
|
|
|
va_end(ap);
|
|
|
|
fputc((int) '\n', stderr);
|
|
|
|
fflush(stderr);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *msp_alloc(struct mspack_system *self, size_t bytes) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
/* make uninitialised data obvious */
|
|
|
|
char *buf = malloc(bytes + 8);
|
2013-11-04 23:06:50 +00:00
|
|
|
(void)self;
|
2013-03-11 17:46:03 +00:00
|
|
|
if (buf) memset(buf, 0xDC, bytes);
|
|
|
|
*((size_t *)buf) = bytes;
|
|
|
|
return &buf[8];
|
|
|
|
#else
|
2013-11-04 23:06:50 +00:00
|
|
|
(void)self;
|
2013-03-11 17:46:03 +00:00
|
|
|
return malloc(bytes);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msp_free(void *buffer) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
char *buf = buffer;
|
|
|
|
size_t bytes;
|
|
|
|
if (buf) {
|
|
|
|
buf -= 8;
|
|
|
|
bytes = *((size_t *)buf);
|
|
|
|
/* make freed data obvious */
|
|
|
|
memset(buf, 0xED, bytes);
|
|
|
|
free(buf);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
free(buffer);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void msp_copy(void *src, void *dest, size_t bytes) {
|
|
|
|
memcpy(dest, src, bytes);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct mspack_system msp_system = {
|
|
|
|
&msp_open, &msp_close, &msp_read, &msp_write, &msp_seek,
|
|
|
|
&msp_tell, &msp_msg, &msp_alloc, &msp_free, &msp_copy, NULL
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mspack_system *mspack_default_system = &msp_system;
|
|
|
|
|
|
|
|
#endif
|