#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <io.h>
#endif
#if defined(__OS2__) && defined(__WATCOMC__)
#define INCL_DOSMODULEMGR
#define INCL_LONGLONG
#define INCL_DOSFILEMGR
#include <os2.h>
#endif
#include <stdlib.h>
#include <string.h>
#include "wavpack_local.h"
#include <fcntl.h>
#include <sys/stat.h>
#if (defined(__GNUC__) || defined(__sun)) && !defined(_WIN32) && !defined(__WATCOMC__)
#include <unistd.h>
#endif
#ifdef __OS2__
#include <io.h>
#endif
#ifdef _WIN32
static FILE *fopen_utf8 (const char *filename_utf8, const char *mode_utf8);
#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#endif
#endif
#ifdef HAVE_FSEEKO
#define fseek fseeko
#define ftell ftello
#endif
#ifdef __MINGW32__
#define _ftelli64 ftello64
#define _fseeki64 fseeko64
#endif
static int32_t read_bytes (void *id, void *data, int32_t bcount)
{
return (int32_t) fread (data, 1, bcount, (FILE*) id);
}
static int64_t get_pos (void *id)
{
#if defined(_WIN32) || defined(__WATCOMC__)
return _ftelli64 ((FILE*) id);
#else
return ftell ((FILE*) id);
#endif
}
static int set_pos_abs (void *id, int64_t pos)
{
#if defined(_WIN32) || defined(__WATCOMC__)
return _fseeki64 (id, pos, SEEK_SET);
#else
return fseek (id, pos, SEEK_SET);
#endif
}
static int set_pos_rel (void *id, int64_t delta, int mode)
{
#if defined(_WIN32) || defined(__WATCOMC__)
return _fseeki64 (id, delta, mode);
#else
return fseek (id, delta, mode);
#endif
}
static int push_back_byte (void *id, int c)
{
return ungetc (c, id);
}
#ifdef _WIN32
static int64_t get_length (void *id)
{
LARGE_INTEGER Size;
HANDLE fHandle;
if (id == NULL)
return 0;
fHandle = (HANDLE)_get_osfhandle(_fileno((FILE*) id));
if (fHandle == INVALID_HANDLE_VALUE)
return 0;
Size.u.LowPart = GetFileSize(fHandle, (DWORD *) &Size.u.HighPart);
if (Size.u.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR)
return 0;
return (int64_t)Size.QuadPart;
}
#elif defined(__WATCOMC__)
static int64_t get_length (void *id)
{
FILE *file = id;
struct _stati64 statbuf;
if (!file || _fstati64 (fileno (file), &statbuf) || !S_ISREG(statbuf.st_mode))
return 0;
return statbuf.st_size;
}
#else
static int64_t get_length (void *id)
{
FILE *file = id;
struct stat statbuf;
if (!file || fstat (fileno (file), &statbuf) || !S_ISREG(statbuf.st_mode))
return 0;
return statbuf.st_size;
}
#endif
#ifdef _WIN32
static int can_seek (void *id)
{
struct stat statbuf;
return id && !fstat (_fileno ((FILE *)id), &statbuf) && S_ISREG(statbuf.st_mode);
}
#else
static int can_seek (void *id)
{
FILE *file = id;
struct stat statbuf;
return file && !fstat (fileno (file), &statbuf) && S_ISREG(statbuf.st_mode);
}
#endif
static int32_t write_bytes (void *id, void *data, int32_t bcount)
{
return (int32_t) fwrite (data, 1, bcount, (FILE*) id);
}
#if defined(__WATCOMC__) && defined(_WIN32)
static int truncate_here (void *id)
{
int fd = _fileno ((FILE *)id);
HANDLE handle = (HANDLE) _get_osfhandle (fd);
return (SetEndOfFile(handle) != 0) ? 0 : -1;
}
#elif defined(__WATCOMC__) && defined(__OS2__)
static int chk_DosSetFileSizeL = 0;
#define ORD_DosSetFileSizeL 989
typedef APIRET (APIENTRY *DosSetFileSizeL_t)(HFILE,LONGLONG);
static DosSetFileSizeL_t pDosSetFileSizeL = NULL;
static void init_os2file64api (void)
{
HMODULE handle;
if (DosQueryModuleHandle("DOSCALLS", &handle) == 0) {
if (DosQueryProcAddr(handle, ORD_DosSetFileSizeL, NULL, (PFN *)&pDosSetFileSizeL) != 0) {
pDosSetFileSizeL = NULL;
}
}
chk_DosSetFileSizeL = 1;
}
static int truncate_here (void *id)
{
int fd = fileno ((FILE *)id);
HFILE handle = (HFILE) _get_osfhandle (fd);
int64_t pos = _lseeki64 (fd, 0, SEEK_CUR);
if (!chk_DosSetFileSizeL) {
init_os2file64api();
}
if (pDosSetFileSizeL) {
return (pDosSetFileSizeL(handle, pos) == 0) ? 0 : -1;
}
return (DosSetFileSize(handle,(ULONG)pos) == 0) ? 0 : -1;
}
#elif defined(_WIN32)
static int truncate_here (void *id)
{
FILE *file = id;
int64_t curr_pos = _ftelli64 (file);
return _chsize_s (_fileno (file), curr_pos);
}
#else
static int truncate_here (void *id)
{
FILE *file = id;
off_t curr_pos = ftell (file);
return ftruncate (fileno (file), curr_pos);
}
#endif
static int close_stream (void *id)
{
return fclose ((FILE*) id);
}
static WavpackStreamReader64 freader = {
read_bytes, write_bytes, get_pos, set_pos_abs, set_pos_rel,
push_back_byte, get_length, can_seek, truncate_here, close_stream
};
WavpackContext *WavpackOpenFileInput (const char *infilename, char *error, int flags, int norm_offset)
{
char *file_mode = (flags & OPEN_EDIT_TAGS) ? "r+b" : "rb";
FILE *(*fopen_func)(const char *, const char *) = fopen;
FILE *wv_id, *wvc_id;
#ifdef _WIN32
if (flags & OPEN_FILE_UTF8)
fopen_func = fopen_utf8;
#endif
if (*infilename == '-') {
wv_id = stdin;
#if defined(_WIN32)
_setmode (_fileno (stdin), O_BINARY);
#endif
#if defined(__OS2__)
setmode (fileno (stdin), O_BINARY);
#endif
}
else if ((wv_id = fopen_func (infilename, file_mode)) == NULL) {
if (error) strcpy (error, (flags & OPEN_EDIT_TAGS) ? "can't open file for editing" : "can't open file");
return NULL;
}
if (*infilename != '-' && (flags & OPEN_WVC)) {
char *in2filename = malloc (strlen (infilename) + 10);
strcpy (in2filename, infilename);
strcat (in2filename, "c");
wvc_id = fopen_func (in2filename, "rb");
free (in2filename);
}
else
wvc_id = NULL;
return WavpackOpenFileInputEx64 (&freader, wv_id, wvc_id, error, flags, norm_offset);
}
#ifdef _WIN32
static wchar_t *utf8_to_utf16(const char *input)
{
wchar_t *Buffer;
int BuffSize = 0, Result = 0;
BuffSize = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
Buffer = (wchar_t*) malloc(sizeof(wchar_t) * BuffSize);
if(Buffer)
{
Result = MultiByteToWideChar(CP_UTF8, 0, input, -1, Buffer, BuffSize);
}
return ((Result > 0) && (Result <= BuffSize)) ? Buffer : NULL;
}
static FILE *fopen_utf8(const char *filename_utf8, const char *mode_utf8)
{
FILE *ret = NULL;
wchar_t *filename_utf16 = utf8_to_utf16(filename_utf8);
wchar_t *mode_utf16 = utf8_to_utf16(mode_utf8);
if(filename_utf16 && mode_utf16)
{
ret = _wfopen(filename_utf16, mode_utf16);
}
if(filename_utf16) free(filename_utf16);
if(mode_utf16) free(mode_utf16);
return ret;
}
#endif