2008-01-31 07:04:26 +01:00
|
|
|
/*
|
2008-05-20 17:18:38 +02:00
|
|
|
* streamfile.h - definitions for buffered file reading with STREAMFILE
|
|
|
|
*/
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2008-05-06 05:35:37 +02:00
|
|
|
#ifndef _STREAMFILE_H
|
|
|
|
#define _STREAMFILE_H
|
|
|
|
|
2008-04-03 15:40:36 +02:00
|
|
|
#ifdef _MSC_VER
|
2008-04-03 15:56:50 +02:00
|
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
2008-04-03 15:40:36 +02:00
|
|
|
#endif
|
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include "streamtypes.h"
|
2008-01-31 23:26:11 +01:00
|
|
|
#include "util.h"
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2018-09-23 03:01:13 +02:00
|
|
|
|
|
|
|
/* MSVC fixes (though mingw uses MSVCRT but not MSC_VER, maybe use AND?) */
|
2018-03-30 07:22:03 +02:00
|
|
|
#if defined(__MSVCRT__) || defined(_MSC_VER)
|
2018-09-23 03:01:13 +02:00
|
|
|
#include <io.h>
|
|
|
|
|
|
|
|
#ifndef fseeko
|
|
|
|
#define fseeko fseek
|
|
|
|
#endif
|
|
|
|
#ifndef ftello
|
|
|
|
#define ftello ftell
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define dup _dup
|
|
|
|
|
|
|
|
#ifdef fileno
|
|
|
|
#undef fileno
|
|
|
|
#endif
|
|
|
|
#define fileno _fileno
|
|
|
|
#define fdopen _fdopen
|
|
|
|
|
|
|
|
// #ifndef off64_t
|
|
|
|
// #define off_t __int64
|
|
|
|
// #endif
|
2008-02-06 01:27:51 +01:00
|
|
|
#endif
|
|
|
|
|
2009-01-27 15:25:16 +01:00
|
|
|
#if defined(XBMC)
|
|
|
|
#define fseeko fseek
|
|
|
|
#endif
|
|
|
|
|
2017-01-15 20:48:00 +01:00
|
|
|
#define STREAMFILE_DEFAULT_BUFFER_SIZE 0x8000
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2016-11-27 19:35:26 +01:00
|
|
|
#ifndef DIR_SEPARATOR
|
|
|
|
#if defined (_WIN32) || defined (WIN32)
|
|
|
|
#define DIR_SEPARATOR '\\'
|
|
|
|
#else
|
|
|
|
#define DIR_SEPARATOR '/'
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2017-08-12 11:14:16 +02:00
|
|
|
/* struct representing a file with callbacks. Code should use STREAMFILEs and not std C functions
|
2018-03-30 18:10:23 +02:00
|
|
|
* to do file operations, as plugins may need to provide their own callbacks.
|
|
|
|
* Reads from arbitrary offsets, meaning internally may need fseek equivalents during reads. */
|
2008-05-20 17:18:38 +02:00
|
|
|
typedef struct _STREAMFILE {
|
|
|
|
size_t (*read)(struct _STREAMFILE *,uint8_t * dest, off_t offset, size_t length);
|
|
|
|
size_t (*get_size)(struct _STREAMFILE *);
|
|
|
|
off_t (*get_offset)(struct _STREAMFILE *);
|
2017-08-12 11:14:16 +02:00
|
|
|
/* for dual-file support */
|
2008-05-20 17:18:38 +02:00
|
|
|
void (*get_name)(struct _STREAMFILE *,char *name,size_t length);
|
|
|
|
struct _STREAMFILE * (*open)(struct _STREAMFILE *,const char * const filename,size_t buffersize);
|
|
|
|
void (*close)(struct _STREAMFILE *);
|
2017-08-12 11:14:16 +02:00
|
|
|
|
2017-08-12 11:23:09 +02:00
|
|
|
|
2018-01-19 00:16:14 +01:00
|
|
|
/* Substream selection for files with subsongs. Manually used in metas if supported.
|
2017-08-12 11:23:09 +02:00
|
|
|
* Not ideal here, but it's the simplest way to pass to all init_vgmstream_x functions. */
|
|
|
|
int stream_index; /* 0=default/auto (first), 1=first, N=Nth */
|
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
} STREAMFILE;
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a standard STREAMFILE, opening from path.
|
|
|
|
* Uses stdio (FILE) for operations, thus plugins may not want to use it. */
|
|
|
|
STREAMFILE *open_stdio_streamfile(const char * filename);
|
2017-08-13 19:58:01 +02:00
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a standard STREAMFILE from a pre-opened FILE. */
|
|
|
|
STREAMFILE *open_stdio_streamfile_by_file(FILE * file, const char * filename);
|
2017-08-12 11:14:16 +02:00
|
|
|
|
2018-04-19 22:19:30 +02:00
|
|
|
/* Opens a STREAMFILE that does buffered IO.
|
|
|
|
* Can be used when the underlying IO may be slow (like when using custom IO).
|
|
|
|
* Buffer size is optional. */
|
|
|
|
STREAMFILE *open_buffer_streamfile(STREAMFILE *streamfile, size_t buffer_size);
|
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a STREAMFILE that doesn't close the underlying streamfile.
|
2018-01-20 01:59:36 +01:00
|
|
|
* Calls to open won't wrap the new SF (assumes it needs to be closed).
|
|
|
|
* Can be used in metas to test custom IO without closing the external SF. */
|
|
|
|
STREAMFILE *open_wrap_streamfile(STREAMFILE *streamfile);
|
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a STREAMFILE that clamps reads to a section of a larger streamfile.
|
|
|
|
* Can be used with subfiles inside a bigger file (to fool metas, or to simplify custom IO). */
|
2018-01-20 01:59:36 +01:00
|
|
|
STREAMFILE *open_clamp_streamfile(STREAMFILE *streamfile, off_t start, size_t size);
|
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a STREAMFILE that uses custom IO for streamfile reads.
|
|
|
|
* Can be used to modify data on the fly (ex. decryption), or even transform it from a format to another. */
|
2018-03-30 18:10:23 +02:00
|
|
|
STREAMFILE *open_io_streamfile(STREAMFILE *streamfile, void* data, size_t data_size, void* read_callback, void* size_callback);
|
2018-01-20 01:59:36 +01:00
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a STREAMFILE that reports a fake name, but still re-opens itself properly.
|
2018-01-27 11:07:45 +01:00
|
|
|
* Can be used to trick a meta's extension check (to call from another, with a modified SF).
|
|
|
|
* When fakename isn't supplied it's read from the streamfile, and the extension swapped with fakeext.
|
|
|
|
* If the fakename is an existing file, open won't work on it as it'll reopen the fake-named streamfile. */
|
2018-03-03 19:07:59 +01:00
|
|
|
STREAMFILE *open_fakename_streamfile(STREAMFILE *streamfile, const char * fakename, const char * fakeext);
|
2018-01-27 11:07:45 +01:00
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
//todo probably could simply use custom IO
|
|
|
|
/* Opens streamfile formed from multiple streamfiles, their data joined during reads.
|
2018-01-27 13:58:46 +01:00
|
|
|
* Can be used when data is segmented in multiple separate files.
|
|
|
|
* The first streamfile is used to get names, stream index and so on. */
|
|
|
|
STREAMFILE *open_multifile_streamfile(STREAMFILE **streamfiles, size_t streamfiles_size);
|
|
|
|
|
2018-08-04 20:42:00 +02:00
|
|
|
/* Opens a STREAMFILE from a (path)+filename.
|
|
|
|
* Just a wrapper, to avoid having to access the STREAMFILE's callbacks directly. */
|
|
|
|
STREAMFILE * open_streamfile(STREAMFILE *streamFile, const char * pathname);
|
|
|
|
|
2018-03-29 22:34:21 +02:00
|
|
|
/* Opens a STREAMFILE from a base pathname + new extension
|
|
|
|
* Can be used to get companion headers. */
|
|
|
|
STREAMFILE * open_streamfile_by_ext(STREAMFILE *streamFile, const char * ext);
|
|
|
|
|
|
|
|
/* Opens a STREAMFILE from a base path + new filename
|
|
|
|
* Can be used to get companion files. */
|
|
|
|
STREAMFILE * open_streamfile_by_filename(STREAMFILE *streamFile, const char * filename);
|
|
|
|
|
2019-01-01 23:21:08 +01:00
|
|
|
/* Reopen a STREAMFILE with a different buffer size, for fine-tuned bigfile parsing.
|
|
|
|
* Uses default buffer size when buffer_size is 0 */
|
|
|
|
STREAMFILE * reopen_streamfile(STREAMFILE *streamFile, size_t buffer_size);
|
|
|
|
|
2017-08-12 11:14:16 +02:00
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
/* close a file, destroy the STREAMFILE object */
|
2008-05-20 17:18:38 +02:00
|
|
|
static inline void close_streamfile(STREAMFILE * streamfile) {
|
2018-03-29 22:34:21 +02:00
|
|
|
if (streamfile!=NULL)
|
|
|
|
streamfile->close(streamfile);
|
2008-05-20 17:18:38 +02:00
|
|
|
}
|
2008-01-31 23:26:11 +01:00
|
|
|
|
2017-08-12 11:14:16 +02:00
|
|
|
/* read from a file, returns number of bytes read */
|
2008-01-31 23:26:11 +01:00
|
|
|
static inline size_t read_streamfile(uint8_t * dest, off_t offset, size_t length, STREAMFILE * streamfile) {
|
2008-05-20 17:18:38 +02:00
|
|
|
return streamfile->read(streamfile,dest,offset,length);
|
2008-01-31 23:26:11 +01:00
|
|
|
}
|
2008-01-31 07:04:26 +01:00
|
|
|
|
|
|
|
/* return file size */
|
2008-05-20 17:18:38 +02:00
|
|
|
static inline size_t get_streamfile_size(STREAMFILE * streamfile) {
|
|
|
|
return streamfile->get_size(streamfile);
|
|
|
|
}
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2008-05-20 20:56:44 +02:00
|
|
|
|
2008-01-31 07:04:26 +01:00
|
|
|
/* Sometimes you just need an int, and we're doing the buffering.
|
2008-05-20 17:18:38 +02:00
|
|
|
* Note, however, that if these fail to read they'll return -1,
|
|
|
|
* so that should not be a valid value or there should be some backup. */
|
2008-01-31 23:26:11 +01:00
|
|
|
static inline int16_t read_16bitLE(off_t offset, STREAMFILE * streamfile) {
|
2008-05-20 17:18:38 +02:00
|
|
|
uint8_t buf[2];
|
2008-01-31 23:26:11 +01:00
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
if (read_streamfile(buf,offset,2,streamfile)!=2) return -1;
|
|
|
|
return get_16bitLE(buf);
|
2008-01-31 23:26:11 +01:00
|
|
|
}
|
|
|
|
static inline int16_t read_16bitBE(off_t offset, STREAMFILE * streamfile) {
|
2008-05-20 17:18:38 +02:00
|
|
|
uint8_t buf[2];
|
2008-01-31 23:26:11 +01:00
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
if (read_streamfile(buf,offset,2,streamfile)!=2) return -1;
|
|
|
|
return get_16bitBE(buf);
|
2008-01-31 23:26:11 +01:00
|
|
|
}
|
|
|
|
static inline int32_t read_32bitLE(off_t offset, STREAMFILE * streamfile) {
|
2008-05-20 17:18:38 +02:00
|
|
|
uint8_t buf[4];
|
2008-01-31 23:26:11 +01:00
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
if (read_streamfile(buf,offset,4,streamfile)!=4) return -1;
|
|
|
|
return get_32bitLE(buf);
|
2008-01-31 23:26:11 +01:00
|
|
|
}
|
|
|
|
static inline int32_t read_32bitBE(off_t offset, STREAMFILE * streamfile) {
|
2008-05-20 17:18:38 +02:00
|
|
|
uint8_t buf[4];
|
2008-01-31 23:26:11 +01:00
|
|
|
|
2008-05-20 17:18:38 +02:00
|
|
|
if (read_streamfile(buf,offset,4,streamfile)!=4) return -1;
|
|
|
|
return get_32bitBE(buf);
|
2008-01-31 23:26:11 +01:00
|
|
|
}
|
2017-08-28 15:11:52 +02:00
|
|
|
static inline int64_t read_64bitLE(off_t offset, STREAMFILE * streamfile) {
|
|
|
|
uint8_t buf[8];
|
|
|
|
|
|
|
|
if (read_streamfile(buf,offset,8,streamfile)!=8) return -1;
|
|
|
|
return get_64bitLE(buf);
|
|
|
|
}
|
|
|
|
static inline int64_t read_64bitBE(off_t offset, STREAMFILE * streamfile) {
|
|
|
|
uint8_t buf[8];
|
|
|
|
|
|
|
|
if (read_streamfile(buf,offset,8,streamfile)!=8) return -1;
|
|
|
|
return get_64bitBE(buf);
|
|
|
|
}
|
2008-01-31 23:26:11 +01:00
|
|
|
static inline int8_t read_8bit(off_t offset, STREAMFILE * streamfile) {
|
2008-05-20 17:18:38 +02:00
|
|
|
uint8_t buf[1];
|
|
|
|
|
|
|
|
if (read_streamfile(buf,offset,1,streamfile)!=1) return -1;
|
|
|
|
return buf[0];
|
|
|
|
}
|
2008-01-31 23:26:11 +01:00
|
|
|
|
2018-07-17 22:54:24 +02:00
|
|
|
/* guess byte endianness from a given value, return true if big endian and false if little endian */
|
|
|
|
static inline int guess_endianness16bit(off_t offset, STREAMFILE * streamfile) {
|
2019-02-03 01:46:05 +01:00
|
|
|
uint8_t buf[0x02];
|
|
|
|
if (read_streamfile(buf,offset,0x02,streamfile) != 0x02) return -1; /* ? */
|
|
|
|
return (uint16_t)get_16bitLE(buf) > (uint16_t)get_16bitBE(buf) ? 1 : 0;
|
2018-07-17 22:54:24 +02:00
|
|
|
}
|
|
|
|
static inline int guess_endianness32bit(off_t offset, STREAMFILE * streamfile) {
|
2019-02-03 01:46:05 +01:00
|
|
|
uint8_t buf[0x04];
|
|
|
|
if (read_streamfile(buf,offset,0x04,streamfile) != 0x04) return -1; /* ? */
|
|
|
|
return (uint32_t)get_32bitLE(buf) > (uint32_t)get_32bitBE(buf) ? 1 : 0;
|
2018-07-17 22:54:24 +02:00
|
|
|
}
|
|
|
|
|
2018-12-31 21:01:46 +01:00
|
|
|
static inline size_t align_size_to_block(size_t value, size_t block_align) {
|
2018-12-30 21:39:27 +01:00
|
|
|
size_t extra_size = value % block_align;
|
|
|
|
if (extra_size == 0) return value;
|
|
|
|
return (value + block_align - extra_size);
|
2018-12-30 20:25:14 +01:00
|
|
|
}
|
|
|
|
|
2017-08-12 11:14:16 +02:00
|
|
|
/* various STREAMFILE helpers functions */
|
2008-01-31 07:04:26 +01:00
|
|
|
|
2017-11-23 22:53:43 +01:00
|
|
|
size_t get_streamfile_text_line(int dst_length, char * dst, off_t offset, STREAMFILE * streamfile, int *line_done_ptr);
|
2008-07-21 01:28:16 +02:00
|
|
|
|
2018-03-29 20:42:52 +02:00
|
|
|
size_t read_string(char * buf, size_t bufsize, off_t offset, STREAMFILE *streamFile);
|
2016-11-27 19:35:26 +01:00
|
|
|
|
2018-01-20 20:06:15 +01:00
|
|
|
size_t read_key_file(uint8_t * buf, size_t bufsize, STREAMFILE *streamFile);
|
2016-11-27 19:35:26 +01:00
|
|
|
|
2018-11-24 00:44:17 +01:00
|
|
|
void fix_dir_separators(char * filename);
|
|
|
|
|
2017-01-14 00:59:54 +01:00
|
|
|
int check_extensions(STREAMFILE *streamFile, const char * cmp_exts);
|
|
|
|
|
2017-01-14 01:37:53 +01:00
|
|
|
int find_chunk_be(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size);
|
|
|
|
int find_chunk_le(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size);
|
2017-04-02 12:23:42 +02:00
|
|
|
int find_chunk(STREAMFILE *streamFile, uint32_t chunk_id, off_t start_offset, int full_chunk_size, off_t *out_chunk_offset, size_t *out_chunk_size, int size_big_endian, int zero_size_end);
|
2017-07-15 11:28:42 +02:00
|
|
|
|
2018-03-29 21:03:25 +02:00
|
|
|
void get_streamfile_name(STREAMFILE *streamFile, char * buffer, size_t size);
|
|
|
|
void get_streamfile_filename(STREAMFILE *streamFile, char * buffer, size_t size);
|
2018-08-04 20:42:00 +02:00
|
|
|
void get_streamfile_basename(STREAMFILE *streamFile, char * buffer, size_t size);
|
2018-03-29 21:03:25 +02:00
|
|
|
void get_streamfile_path(STREAMFILE *streamFile, char * buffer, size_t size);
|
|
|
|
void get_streamfile_ext(STREAMFILE *streamFile, char * filename, size_t size);
|
2018-08-11 17:58:16 +02:00
|
|
|
|
|
|
|
void dump_streamfile(STREAMFILE *streamFile, const char* out);
|
2008-01-31 07:04:26 +01:00
|
|
|
#endif
|