[LIBMPG123]

- Update to version 1.25.0
CORE-13451

svn path=/trunk/; revision=75093
This commit is contained in:
Thomas Faber 2017-06-18 14:03:50 +00:00
parent f5be5e8bfe
commit d1d15ad1a6
14 changed files with 949 additions and 278 deletions

View file

@ -16,5 +16,5 @@ add_library(winemp3.acm SHARED
set_module_type(winemp3.acm win32dll)
set_target_properties(winemp3.acm PROPERTIES SUFFIX "")
target_link_libraries(winemp3.acm wine libmpg123 oldnames)
add_importlibs(winemp3.acm winmm user32 msvcrt kernel32 ntdll)
add_importlibs(winemp3.acm shlwapi winmm user32 msvcrt kernel32 ntdll)
add_cd_file(TARGET winemp3.acm DESTINATION reactos/system32 FOR all)

View file

@ -15,10 +15,14 @@
#define MPG123_COMPAT_H
#include "config.h"
#include "intsym.h"
/* Needed for strdup(), in strict mode ... */
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
/* For --nagging compilation with -std=c89, we need
to disable the inline keyword. */
#ifdef PLAIN_C89
#ifndef inline
#define inline
#endif
#endif
#include <errno.h>
@ -98,8 +102,10 @@
typedef unsigned char byte;
#ifndef __REACTOS__
#ifdef _MSC_VER
typedef long ssize_t;
#if defined(_MSC_VER) && !defined(MPG123_DEF_SSIZE_T)
#define MPG123_DEF_SSIZE_T
#include <stddef.h>
typedef ptrdiff_t ssize_t;
#endif
#endif /* __REACTOS__ */
@ -109,9 +115,9 @@ void *safe_realloc(void *ptr, size_t size);
const char *strerror(int errnum);
#endif
#ifndef HAVE_STRDUP
char *strdup(const char *s);
#endif
/* Roll our own strdup() that does not depend on libc feature test macros
and returns NULL on NULL input instead of crashing. */
char* compat_strdup(const char *s);
/* If we have the size checks enabled, try to derive some sane printfs.
Simple start: Use max integer type and format if long is not big enough.
@ -140,6 +146,10 @@ typedef intmax_t ssize_p;
typedef long ssize_p;
#endif
/* Get an environment variable, possibly converted to UTF-8 from wide string.
The return value is a copy that you shall free. */
char *compat_getenv(const char* name);
/**
* Opening a file handle can be different.
* This function here is defined to take a path in native encoding (ISO8859 / UTF-8 / ...), or, when MS Windows Unicode support is enabled, an UTF-8 string that will be converted back to native UCS-2 (wide character) before calling the system's open function.
@ -149,6 +159,10 @@ typedef long ssize_p;
*/
int compat_open(const char *filename, int flags);
FILE* compat_fopen(const char *filename, const char *mode);
/**
* Also fdopen to avoid having to define POSIX macros in various source files.
*/
FILE* compat_fdopen(int fd, const char *mode);
/**
* Closing a file handle can be platform specific.
@ -190,6 +204,67 @@ int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen);
int win32_utf8_wide(const char *const mbptr, wchar_t **wptr, size_t *buflen);
#endif
/*
A little bit of path abstraction: We always work with plain char strings
that usually represent POSIX-ish UTF-8 paths (something like c:/some/file
might appear). For Windows, those are converted to wide strings with \
instead of / and possible fun is had with prefixes to get around the old
path length limit. Outside of the compat library, that stuff should not
matter, although something like //?/UNC/server/some/file could be thrown
around as UTF-8 string, to be converted to a wide \\?\UNC\server\some\file
just before handing it to Windows API.
There is a lot of unnecessary memory allocation and string copying because
of this, but this filesystem stuff is not really relevant to mpg123
performance, so the goal is to keep the code outside the compatibility layer
simple.
*/
/*
Concatenate a prefix and a path, one of them alowed to be NULL.
If the path is already absolute, the prefix is ignored. Relative
parts (like /..) are resolved if this is sensible for the platform
(meaning: for Windows), else they are preserved (on POSIX, actual
file system access would be needed because of symlinks).
*/
char* compat_catpath(const char *prefix, const char* path);
/* Return 1 if the given path indicates an existing directory,
0 otherwise. */
int compat_isdir(const char *path);
/*
Directory traversal. This talks ASCII/UTF-8 paths externally, converts
to/from wchar_t internally if the platform wants that. Returning NULL
means failure to open/end of listing.
There is no promise about sorting entries.
*/
struct compat_dir;
/* Returns NULL if either directory failed to open or listing is empty.
Listing can still be empty even if non-NULL, so always rely on the
nextfile/nextdir functions. */
struct compat_dir* compat_diropen(char *path);
void compat_dirclose(struct compat_dir*);
/* Get the next entry that is a file (or symlink to one).
The returned string is a copy that needs to be freed after use. */
char* compat_nextfile(struct compat_dir*);
/* Get the next entry that is a directory (or symlink to one).
The returned string is a copy that needs to be freed after use. */
char* compat_nextdir (struct compat_dir*);
#ifdef USE_MODULES
/*
For keeping the path mess local, a system-specific dlopen() variant
is contained in here, too. This is very thin wrapping, even sparing
definition of a handle type, just using void pointers.
Use of absolute paths is a good idea if you want to be sure which
file is openend, as default search paths vary.
*/
void *compat_dlopen (const char *path);
void *compat_dlsym (void *handle, const char* name);
void compat_dlclose(void *handle);
#endif
/* Blocking write/read of data with signal resilience.
Both continue after being interrupted by signals and always return the
amount of processed data (shortage indicating actual problem or EOF). */

View file

@ -13,6 +13,13 @@
#include "config.h"
#include "intsym.h"
#if (defined OPT_I486) || (defined OPT_I586) || (defined OPT_I586_DITHER) \
|| (defined OPT_MMX) || (defined OPT_SSE) || (defined OPT_3DNOW) || (defined OPT_3DNOWEXT) \
|| (defined OPT_3DNOW_VINTAGE) || (defined OPT_3DNOWEXT_VINTAGE) \
|| (defined OPT_SSE_VINTAGE)
#define OPT_X86
#endif
#ifdef CCALIGN
#define MOVUAPS movaps
#else
@ -49,9 +56,17 @@
#define ALIGN32 .align 32
#define ALIGN64 .align 64
#else
#ifdef ASMALIGN_ARMASM
#define ALIGN4 ALIGN 4
#define ALIGN8 ALIGN 8
#define ALIGN16 ALIGN 16
#define ALIGN32 ALIGN 32
#define ALIGN64 ALIGN 64
#else
#error "Dunno how assembler alignment works. Please specify."
#endif
#endif
#endif
#endif
@ -61,7 +76,7 @@
#if defined(__USER_LABEL_PREFIX__)
#define ASM_NAME(a) MANGLE_MACROCAT(__USER_LABEL_PREFIX__,a)
#define ASM_VALUE(a) MANGLE_MACROCAT($,ASM_NAME(a))
#elif defined(__CYGWIN__) || defined(_WIN32) && !defined (_WIN64) || defined(__OS2__) || \
#elif defined(__CYGWIN__) || defined(_WIN32) && !defined (_WIN64) && !defined (_M_ARM) || defined(__OS2__) || \
(defined(__OpenBSD__) && !defined(__ELF__)) || defined(__APPLE__)
#define ASM_NAME(a) MANGLE_MACROCAT(_,a)
#define ASM_VALUE(a) MANGLE_MACROCAT($_,a)
@ -70,6 +85,62 @@
#define ASM_VALUE(a) MANGLE_MACROCAT($,a)
#endif
/* Enable position-independent code for certain platforms. */
#if defined(OPT_X86)
#define _EBX_ %ebx
#if defined(PIC) && defined(__ELF__)
/* ELF binaries (Unix/Linux) */
#define LOCAL_VAR(a) a ## @GOTOFF(_EBX_)
#define GLOBAL_VAR(a) ASM_NAME(a) ## @GOTOFF(_EBX_)
#define GLOBAL_VAR_PTR(a) ASM_NAME(a) ## @GOT(_EBX_)
#define FUNC(a) ASM_NAME(a)
#define EXTERNAL_FUNC(a) ASM_NAME(a) ## @PLT
#undef ASM_VALUE
#define ASM_VALUE(a) MANGLE_MACROCAT($,a) ##@GOTOFF
#define GET_GOT \
call 1f; \
1: \
pop _EBX_; \
2: \
addl $_GLOBAL_OFFSET_TABLE_ + (2b-1b), _EBX_
#define PREPARE_GOT pushl _EBX_
#define RESTORE_GOT popl _EBX_
#elif defined(PIC) && defined(__APPLE__)
/* Mach-O binaries (OSX/iOS) */
#define LOCAL_VAR(a) a ## - Lpic_base(_EBX_)
#define GLOBAL_VAR(a) #error This ABI cannot access non-local symbols directly.
#define GLOBAL_VAR_PTR(a) L_ ## a ## - Lpic_base(_EBX_)
#define FUNC(a) L_ ## a
#define EXTERNAL_FUNC(a) L_ ## a
#define GET_GOT \
call Lpic_base; \
Lpic_base: \
pop _EBX_
#define PREPARE_GOT pushl _EBX_
#define RESTORE_GOT popl _EBX_
#else
/* Dummies for everyone else. */
#define LOCAL_VAR(a) a
#define GLOBAL_VAR ASM_NAME
#define GLOBAL_VAR_PTR(a) #error Cannot use indirect addressing in non-PIC object.
#define FUNC ASM_NAME
#define EXTERNAL_FUNC ASM_NAME
#define GET_GOT
#define PREPARE_GOT
#define RESTORE_GOT
#endif /* PIC variants */
#endif /* OPT_X86 */
#if defined(__CYGWIN__) || defined(__MINGW32__) || defined(__APPLE__)
#define COMM(a,b,c) .comm a,b
#else
@ -82,6 +153,13 @@
#define BSS .bss
#endif
/* armasm for WIN32 UWP */
#ifdef _M_ARM
#define GLOBAL_SYMBOL EXPORT
#else
#define GLOBAL_SYMBOL .globl
#endif
/* Mark non-executable stack.
It's mainly for GNU on Linux... who else does (not) like this? */
#if !defined(__SUNPRO_C) && defined(__linux__) && defined(__ELF__)
@ -94,7 +172,7 @@
#define NONEXEC_STACK
#endif
#if defined(__x86_64__) && (defined(_WIN64) || defined (__CYGWIN__))
#if (defined(__x86_64__) || defined(_M_X64)) && (defined(_WIN64) || defined (__CYGWIN__))
#define IS_MSABI 1 /* Not using SYSV */
#endif

View file

@ -32,6 +32,7 @@ static inline int16_t idiv_signed_rounded(int32_t x, int shift)
/* From now on for single precision float... double precision is a possible option once we added some bits. But, it would be rather insane. */
#ifndef REAL_TO_SHORT
#if (defined FORCE_ACCURATE) || (defined ACCURATE_ROUNDING)
/* Define the accurate rounding function. */
# if (defined REAL_IS_FLOAT) && (defined IEEE_FLOAT)
/* This function is only available for IEEE754 single-precision values
@ -51,6 +52,7 @@ static inline int16_t ftoi16(float x)
/* The "proper" rounding, plain C, a bit slow. */
# define REAL_TO_SHORT_ACCURATE(x) (short)((x)>0.0?(x)+0.5:(x)-0.5)
# endif
#endif
/* Now define the normal rounding. */
# ifdef ACCURATE_ROUNDING

View file

@ -15,11 +15,12 @@
That's not memory efficient since there's doubled code, but it's easier than giving another function pointer.
Maybe I'll change it in future, but now I need something that works.
Original comment from MPlayer source follows:
Original comment from MPlayer source follows. Regarding the license history see
synth_mmx.S, which the original comment about this being licensed under GPL is
relating to.
*/
/*
* this code comes under GPL
* This code was taken from http://www.mpg123.org
* See ChangeLog of mpg123-0.59s-pre.1 for detail
* Applied to mplayer by Nick Kurshev <nickols_k@mail.ru>
@ -48,11 +49,25 @@ SYNTH_NAME:
pushl %ebp
/* stack:0=ebp 4=back 8=bandptr 12=channel 16=samples 20=buffs 24=bo 28=decwins */
movl %esp, %ebp
/* Now the old stack addresses are preserved via %epb. */
#ifdef PIC
subl $8,%esp /* What has been called temp before. */
#else
subl $4,%esp /* What has been called temp before. */
#endif
pushl %edi
pushl %esi
pushl %ebx
#ifdef PIC
#undef _EBX_
#define _EBX_ %eax
GET_GOT
#define EBXSAVE -4(%ebp)
movl _EBX_, EBXSAVE /* save PIC register */
#endif
#define TEMP 12(%esp)
/* APP */
movl 12(%ebp),%ecx
@ -94,6 +109,9 @@ SYNTH_NAME:
leal (%ecx,%ebx,2), %edx
movl (%esp),%ecx /* restore, but leave value on stack */
shrl $1, %ecx
#ifdef PIC
movl EBXSAVE, _EBX_
#endif
ALIGN16
3:
movq (%edx),%mm0
@ -130,8 +148,8 @@ SYNTH_NAME:
packssdw %mm4,%mm4
movq (%edi), %mm1
punpckldq %mm4, %mm0
pand one_null, %mm1
pand null_one, %mm0
pand LOCAL_VAR(one_null), %mm1
pand LOCAL_VAR(null_one), %mm0
por %mm0, %mm1
movq %mm1,(%edi)
leal 64(%esi),%esi
@ -166,6 +184,10 @@ SYNTH_NAME:
4:
subl $64,%esi
movl $7,%ecx
#ifdef PIC
movl EBXSAVE, _EBX_
#endif
ALIGN16
5:
movq (%edx),%mm0
@ -206,8 +228,8 @@ SYNTH_NAME:
psubsw %mm5,%mm4
movq (%edi), %mm1
punpckldq %mm4, %mm0
pand one_null, %mm1
pand null_one, %mm0
pand LOCAL_VAR(one_null), %mm1
pand LOCAL_VAR(null_one), %mm0
por %mm0, %mm1
movq %mm1,(%edi)
subl $64,%esi
@ -241,6 +263,6 @@ SYNTH_NAME:
popl %ebx
popl %esi
popl %edi
addl $4,%esp
mov %ebp, %esp
popl %ebp
ret

View file

@ -15,6 +15,7 @@ include_directories(BEFORE ${REACTOS_SOURCE_DIR}/sdk/include/reactos/libs/libmpg
list(APPEND SOURCE
compat/compat.c
compat/compat_str.c
dct64.c
dct64_i386.c
equalizer.c

View file

@ -1,16 +1,665 @@
/*
Just to ensure that libraries and programs get their separate
compatibility object. There should be a compatibility library,
I presume, but I don't want to create another glib, I just want
some internal functions to ease coding.
compat: Some compatibility functions (basic memory & string stuff in separate file)
I'll sort it out properly sometime.
The mpg123 code is determined to keep it's legacy. A legacy of old, old UNIX.
So anything possibly somewhat advanced should be considered to be put here, with proper #ifdef;-)
I smell symbol conflicts, anyway. Actually wondering why it
worked so far.
copyright 2007-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis, Windows Unicode stuff by JonY.
*/
#include "config.h"
#include "intsym.h"
#define NO_CATCHSIGNAL
#include "compat/compat_impl.h"
/* This source file does need _POSIX_SOURCE to get some sigaction. */
#define _POSIX_SOURCE
#include "compat.h"
#ifdef _MSC_VER
#include <io.h>
#if(defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_APP))
#define WINDOWS_UWP
#endif
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#endif
/* Win32 is only supported with unicode now. These headers also cover
module stuff. The WANT_WIN32_UNICODE macro is synonymous with
"want windows-specific API, and only the unicode variants of which". */
#ifdef WANT_WIN32_UNICODE
#include <wchar.h>
#include <windows.h>
#include <winnls.h>
#include <shlwapi.h>
#endif
#ifdef USE_MODULES
# ifdef HAVE_DLFCN_H
# include <dlfcn.h>
# endif
#endif
#include "debug.h"
#ifndef WINDOWS_UWP
char *compat_getenv(const char* name)
{
char *ret = NULL;
#ifdef WANT_WIN32_UNICODE
wchar_t *env;
wchar_t *wname = NULL;
if(win32_utf8_wide(name, &wname, NULL) > 0)
{
env = _wgetenv(wname);
free(wname);
if(env)
win32_wide_utf8(env, &ret, NULL);
}
#else
ret = getenv(name);
if(ret)
ret = compat_strdup(ret);
#endif
return ret;
}
#ifdef WANT_WIN32_UNICODE
/* Convert unix UTF-8 (or ASCII) paths to Windows wide character paths. */
static wchar_t* u2wpath(const char *upath)
{
wchar_t* wpath, *p;
if(!upath || win32_utf8_wide(upath, &wpath, NULL) < 1)
return NULL;
for(p=wpath; *p; ++p)
if(*p == L'/')
*p = L'\\';
return wpath;
}
/* Convert Windows wide character paths to unix UTF-8. */
static char* w2upath(const wchar_t *wpath)
{
char* upath, *p;
if(!wpath || win32_wide_utf8(wpath, &upath, NULL) < 1)
return NULL;
for(p=upath; *p; ++p)
if(*p == '\\')
*p = '/';
return upath;
}
/* An absolute path that is too long and not already marked with
\\?\ can be marked as a long one and still work. */
static int wpath_need_elongation(wchar_t *wpath)
{
if( wpath && !PathIsRelativeW(wpath)
&& wcslen(wpath) > MAX_PATH-1
&& wcsncmp(L"\\\\?\\", wpath, 4) )
return 1;
else
return 0;
}
/* Take any wide windows path and turn it into a path that is allowed
to be longer than MAX_PATH, if it is not already. */
static wchar_t* wlongpath(wchar_t *wpath)
{
size_t len, plen;
const wchar_t *prefix = L"";
wchar_t *wlpath = NULL;
if(!wpath)
return NULL;
/* Absolute paths that do not start with \\?\ get that prepended
to allow them being long. */
if(!PathIsRelativeW(wpath) && wcsncmp(L"\\\\?\\", wpath, 4))
{
if(wcslen(wpath) >= 2 && PathIsUNCW(wpath))
{
/* \\server\path -> \\?\UNC\server\path */
prefix = L"\\\\?\\UNC";
++wpath; /* Skip the first \. */
}
else /* c:\some/path -> \\?\c:\some\path */
prefix = L"\\\\?\\";
}
plen = wcslen(prefix);
len = plen + wcslen(wpath);
wlpath = malloc(len+1*sizeof(wchar_t));
if(wlpath)
{
/* Brute force memory copying, swprintf is too dandy. */
memcpy(wlpath, prefix, sizeof(wchar_t)*plen);
memcpy(wlpath+plen, wpath, sizeof(wchar_t)*(len-plen));
wlpath[len] = 0;
}
return wlpath;
}
/* Convert unix path to wide windows path, optionally marking
it as long path if necessary. */
static wchar_t* u2wlongpath(const char *upath)
{
wchar_t *wpath = NULL;
wchar_t *wlpath = NULL;
wpath = u2wpath(upath);
if(wpath_need_elongation(wpath))
{
wlpath = wlongpath(wpath);
free(wpath);
wpath = wlpath;
}
return wpath;
}
#endif
#else
static wchar_t* u2wlongpath(const char *upath)
{
wchar_t* wpath, *p;
if (!upath || win32_utf8_wide(upath, &wpath, NULL) < 1)
return NULL;
for (p = wpath; *p; ++p)
if (*p == L'/')
*p = L'\\';
return wpath;
}
#endif
/* Always add a default permission mask in case of flags|O_CREAT. */
int compat_open(const char *filename, int flags)
{
int ret;
#if defined (WANT_WIN32_UNICODE)
wchar_t *frag = NULL;
frag = u2wlongpath(filename);
/* Fallback to plain open when ucs-2 conversion fails */
if(!frag)
goto open_fallback;
/*Try _wopen */
ret = _wopen(frag, flags|_O_BINARY, _S_IREAD | _S_IWRITE);
if(ret != -1 )
goto open_ok; /* msdn says -1 means failure */
open_fallback:
#endif
#if (defined(WIN32) && !defined (__CYGWIN__))
/* MSDN says POSIX function is deprecated beginning in Visual C++ 2005 */
/* Try plain old _open(), if it fails, do nothing */
ret = _open(filename, flags|_O_BINARY, _S_IREAD | _S_IWRITE);
#else
ret = open(filename, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
#endif
#if defined (WANT_WIN32_UNICODE)
open_ok:
free(frag);
#endif
return ret;
}
/* Moved over from wav.c, logic with fallbacks added from the
example of compat_open(). */
FILE* compat_fopen(const char *filename, const char *mode)
{
FILE* stream = NULL;
#ifdef WANT_WIN32_UNICODE
int cnt = 0;
wchar_t *wname = NULL;
wchar_t *wmode = NULL;
wname = u2wlongpath(filename);
if(!wname)
goto fopen_fallback;
cnt = win32_utf8_wide(mode, &wmode, NULL);
if( (wmode == NULL) || (cnt == 0))
goto fopen_fallback;
stream = _wfopen(wname, wmode);
if(stream) goto fopen_ok;
fopen_fallback:
#endif
stream = fopen(filename, mode);
#ifdef WANT_WIN32_UNICODE
fopen_ok:
free(wmode);
free(wname);
#endif
return stream;
}
FILE* compat_fdopen(int fd, const char *mode)
{
return fdopen(fd, mode);
}
int compat_close(int infd)
{
#if (defined(WIN32) && !defined (__CYGWIN__)) /* MSDN says POSIX function is deprecated beginning in Visual C++ 2005 */
return _close(infd);
#else
return close(infd);
#endif
}
int compat_fclose(FILE *stream)
{
return fclose(stream);
}
/* Windows Unicode stuff */
#ifdef WANT_WIN32_UNICODE
int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen)
{
size_t len;
char *buf;
int ret = 0;
len = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, NULL, 0, NULL, NULL); /* Get utf-8 string length */
buf = calloc(len + 1, sizeof (char)); /* Can we assume sizeof char always = 1? */
if(!buf) len = 0;
else {
if (len != 0) ret = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, buf, len, NULL, NULL); /*Do actual conversion*/
buf[len] = '0'; /* Must terminate */
}
*mbptr = buf; /* Set string pointer to allocated buffer */
if(buflen != NULL) *buflen = (len) * sizeof (char); /* Give length of allocated memory if needed. */
return ret;
}
int win32_utf8_wide(const char *const mbptr, wchar_t **wptr, size_t *buflen)
{
size_t len;
wchar_t *buf;
int ret = 0;
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mbptr, -1, NULL, 0); /* Get converted size */
buf = calloc(len + 1, sizeof (wchar_t)); /* Allocate memory accordingly */
if(!buf) len = 0;
else {
if (len != 0) ret = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, mbptr, -1, buf, len); /* Do conversion */
buf[len] = L'0'; /* Must terminate */
}
*wptr = buf; /* Set string pointer to allocated buffer */
if (buflen != NULL) *buflen = len * sizeof (wchar_t); /* Give length of allocated memory if needed. */
return ret; /* Number of characters written */
}
#endif
#ifndef WINDOWS_UWP
/*
The Windows file and path stuff is an extract of jon_y's win32 loader
prototype from the loader_rework branch. It's been divided in to
reusable functons by ThOr in the hope to work out some generic-looking
loader code for both POSIX and Windows. The routines might be
helpful for consistent path work in other parts of mpg123, too.
This all is about getting some working code on a wide range of
systems while staying somewhat sane. If it does ridiculously inefficient
things with extraneous copies and grabbing of functions that made
it late to some official APIs, that's still fine with us.
*/
char* compat_catpath(const char *prefix, const char* path)
{
char *ret = NULL;
#ifdef WANT_WIN32_UNICODE
wchar_t *wprefix = NULL; /* Wide windows versions of */
wchar_t *wpath = NULL; /* input arguments. */
wchar_t *locwret = NULL; /* Tmp return value from LocalAlloc */
/*
This variation of combinepath can work with long and UNC paths, but
is not officially exposed in any DLLs, It also allocates all its buffers
internally via LocalAlloc, avoiding buffer overflow problems.
ThOr: I presume this hack is for supporting pre-8 Windows, as
from Windows 8 on, this is documented in the API.
*/
HRESULT (__stdcall *mypac)( const wchar_t *in, const wchar_t* more
, unsigned long flags, wchar_t **out ) = NULL;
HMODULE pathcch = NULL;
if(!prefix && !path)
goto catpath_end;
wprefix = u2wpath(prefix);
wpath = u2wpath(path);
if((prefix && !wprefix) || (path && !wpath))
goto catpath_end;
/* Again: I presume this whole fun is to get at PathAllocCombine
even when pathcch.h is not available (like in MinGW32). */
if( (pathcch = GetModuleHandleA("kernelbase")) )
mypac = (void *)GetProcAddress(pathcch, "PathAllocCombine");
if(mypac) /* PATHCCH_ALLOW_LONG_PATH = 1 per API docs */
{
debug("Actually calling PathAllocCombine!");
mypac(wprefix, wpath, 1, &locwret);
}
else
{
/* Playing safe, if we'd care much about performance, this would be on
the stack. */
locwret = LocalAlloc(LPTR, sizeof(wchar_t)*MAX_PATH);
if(locwret)
PathCombineW(locwret, wprefix, wpath);
}
ret = w2upath(locwret);
catpath_end:
LocalFree(locwret);
free(wprefix);
free(wpath);
#else
size_t len, prelen, patlen;
if(path && path[0] == '/')
prefix = NULL; /* Absolute path stays as it is. */
prelen = prefix ? strlen(prefix) : 0;
patlen = path ? strlen(path) : 0;
/* Concatenate the two, put a / in between if both present. */
len = ((prefix && path) ? 1 : 0) + prelen + patlen;
ret = malloc(len+1);
if(ret)
{
size_t off=0;
memcpy(ret, prefix, prelen);
if(prefix && path)
ret[prelen+(off++)] = '/';
memcpy(ret+prelen+off, path, patlen);
ret[len] = 0;
}
#endif
return ret;
}
int compat_isdir(const char *path)
{
int ret = 0;
#ifdef WANT_WIN32_UNICODE
wchar_t *wpath;
wpath = u2wlongpath(path);
if(wpath)
{
DWORD attr = GetFileAttributesW(wpath);
if(attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY)
ret=1;
free(wpath);
}
#else
struct stat sb;
if(path && !stat(path, &sb))
{
if(S_ISDIR(sb.st_mode))
ret=1;
}
#endif
return ret;
}
struct compat_dir
{
char *path;
#ifdef WANT_WIN32_UNICODE
int gotone; /* Got a result stored from FindFirstFileW. */
WIN32_FIND_DATAW d;
HANDLE ffn;
#else
DIR* dir;
#endif
};
struct compat_dir* compat_diropen(char *path)
{
struct compat_dir *cd;
if(!path)
return NULL;
cd = malloc(sizeof(*cd));
if(!cd)
return NULL;
#ifdef WANT_WIN32_UNICODE
cd->gotone = 0;
{
char *pattern;
wchar_t *wpattern;
pattern = compat_catpath(path, "*");
wpattern = u2wlongpath(pattern);
if(wpattern)
{
cd->ffn = FindFirstFileW(wpattern, &(cd->d));
if(cd->ffn == INVALID_HANDLE_VALUE)
{
/* FindClose() only needed after successful first find, right? */
free(cd);
cd = NULL;
}
else
cd->gotone = 1;
}
free(wpattern);
free(pattern);
}
#else
cd->dir = opendir(path);
if(!cd->dir)
{
free(cd);
cd = NULL;
}
#endif
if(cd)
{
cd->path = compat_strdup(path);
if(!cd->path)
{
compat_dirclose(cd);
cd = NULL;
}
}
return cd;
}
void compat_dirclose(struct compat_dir *cd)
{
if(cd)
{
free(cd->path);
#ifdef WANT_WIN32_UNICODE
FindClose(cd->ffn);
#else
closedir(cd->dir);
#endif
free(cd);
}
}
char* compat_nextfile(struct compat_dir *cd)
{
if(!cd)
return NULL;
#ifdef WANT_WIN32_UNICODE
while(cd->gotone || FindNextFileW(cd->ffn, &(cd->d)))
{
cd->gotone = 0;
if(!(cd->d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
char *ret;
win32_wide_utf8(cd->d.cFileName, &ret, NULL);
return ret;
}
}
#else
{
struct dirent *dp;
while((dp = readdir(cd->dir)))
{
struct stat fst;
char *fullpath = compat_catpath(cd->path, dp->d_name);
if(fullpath && !stat(fullpath, &fst) && S_ISREG(fst.st_mode))
{
free(fullpath);
return compat_strdup(dp->d_name);
}
free(fullpath);
}
}
#endif
return NULL;
}
char* compat_nextdir(struct compat_dir *cd)
{
if(!cd)
return NULL;
#ifdef WANT_WIN32_UNICODE
while(cd->gotone || FindNextFileW(cd->ffn, &(cd->d)))
{
cd->gotone = 0;
if(cd->d.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
char *ret;
win32_wide_utf8(cd->d.cFileName, &ret, NULL);
return ret;
}
}
#else
{
struct dirent *dp;
while((dp = readdir(cd->dir)))
{
struct stat fst;
char *fullpath = compat_catpath(cd->path, dp->d_name);
if(fullpath && !stat(fullpath, &fst) && S_ISDIR(fst.st_mode))
{
free(fullpath);
return compat_strdup(dp->d_name);
}
free(fullpath);
}
}
#endif
return NULL;
}
#endif
#ifdef USE_MODULES
/*
This is what I expected the platform-specific dance for dynamic module
support to be. Little did I know about the peculiarities of (long)
paths and directory/file search on Windows.
*/
void *compat_dlopen(const char *path)
{
void *handle = NULL;
#ifdef WANT_WIN32_UNICODE
wchar_t *wpath;
wpath = u2wlongpath(path);
if(wpath)
handle = LoadLibraryW(wpath);
free(wpath);
#else
handle = dlopen(path, RTLD_NOW);
#endif
return handle;
}
void *compat_dlsym(void *handle, const char *name)
{
void *sym = NULL;
if(!handle)
return NULL;
#ifdef WANT_WIN32_UNICODE
sym = GetProcAddress(handle, name);
#else
sym = dlsym(handle, name);
#endif
return sym;
}
void compat_dlclose(void *handle)
{
if(!handle)
return;
#ifdef WANT_WIN32_UNICODE
FreeLibrary(handle);
#else
dlclose(handle);
#endif
}
#endif /* USE_MODULES */
/* This shall survive signals and any return value less than given byte count
is an error */
size_t unintr_write(int fd, void const *buffer, size_t bytes)
{
size_t written = 0;
while(bytes)
{
ssize_t part = write(fd, (char*)buffer+written, bytes);
if(part < 0 && errno != EINTR)
break;
bytes -= part;
written += part;
}
return written;
}
/* Same for reading the data. */
size_t unintr_read(int fd, void *buffer, size_t bytes)
{
size_t got = 0;
while(bytes)
{
ssize_t part = read(fd, (char*)buffer+got, bytes);
if(part < 0 && errno != EINTR)
break;
bytes -= part;
got += part;
}
return got;
}
#ifndef NO_CATCHSIGNAL
#if (!defined(WIN32) || defined (__CYGWIN__)) && defined(HAVE_SIGNAL_H)
void (*catchsignal(int signum, void(*handler)()))()
{
struct sigaction new_sa;
struct sigaction old_sa;
#ifdef DONT_CATCH_SIGNALS
fprintf (stderr, "Not catching any signals.\n");
return ((void (*)()) -1);
#endif
new_sa.sa_handler = handler;
sigemptyset(&new_sa.sa_mask);
new_sa.sa_flags = 0;
if(sigaction(signum, &new_sa, &old_sa) == -1)
return ((void (*)()) -1);
return (old_sa.sa_handler);
}
#endif
#endif

View file

@ -1,236 +0,0 @@
/*
compat: Some compatibility functions.
The mpg123 code is determined to keep it's legacy. A legacy of old, old UNIX.
So anything possibly somewhat advanced should be considered to be put here, with proper #ifdef;-)
copyright 2007-8 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis, Windows Unicode stuff by JonY.
*/
#include "config.h"
#include "compat.h"
#ifdef _MSC_VER
#include <io.h>
#else
#include <fcntl.h>
#endif
#include <sys/stat.h>
#ifdef WANT_WIN32_UNICODE
#include <wchar.h>
#include <windows.h>
#include <winnls.h>
#endif
#include "debug.h"
/* A safe realloc also for very old systems where realloc(NULL, size) returns NULL. */
void *safe_realloc(void *ptr, size_t size)
{
if(ptr == NULL) return malloc(size);
else return realloc(ptr, size);
}
#ifndef HAVE_STRERROR
const char *strerror(int errnum)
{
extern int sys_nerr;
extern char *sys_errlist[];
return (errnum < sys_nerr) ? sys_errlist[errnum] : "";
}
#endif
#ifndef HAVE_STRDUP
char *strdup(const char *src)
{
char *dest;
if (!(dest = (char *) malloc(strlen(src)+1)))
return NULL;
else
return strcpy(dest, src);
}
#endif
/* Always add a default permission mask in case of flags|O_CREAT. */
int compat_open(const char *filename, int flags)
{
int ret;
#if defined (WANT_WIN32_UNICODE)
wchar_t *frag = NULL;
ret = win32_utf8_wide(filename, &frag, NULL);
/* Fallback to plain open when ucs-2 conversion fails */
if((frag == NULL) || (ret == 0))
goto open_fallback;
/*Try _wopen */
ret = _wopen(frag, flags|_O_BINARY, _S_IREAD | _S_IWRITE);
if(ret != -1 )
goto open_ok; /* msdn says -1 means failure */
open_fallback:
#endif
#if (defined(WIN32) && !defined (__CYGWIN__))
/* MSDN says POSIX function is deprecated beginning in Visual C++ 2005 */
/* Try plain old _open(), if it fails, do nothing */
ret = _open(filename, flags|_O_BINARY, _S_IREAD | _S_IWRITE);
#else
ret = open(filename, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
#endif
#if defined (WANT_WIN32_UNICODE)
open_ok:
/* A cast to void*? Does Windows need that?! */
free((void *)frag);
#endif
return ret;
}
/* Moved over from wav.c, logic with fallbacks added from the
example of compat_open(). */
FILE* compat_fopen(const char *filename, const char *mode)
{
FILE* stream = NULL;
#ifdef WANT_WIN32_UNICODE
int cnt = 0;
wchar_t *wname = NULL;
wchar_t *wmode = NULL;
cnt = win32_utf8_wide(filename, &wname, NULL);
if( (wname == NULL) || (cnt == 0))
goto fopen_fallback;
cnt = win32_utf8_wide(mode, &wmode, NULL);
if( (wmode == NULL) || (cnt == 0))
goto fopen_fallback;
stream = _wfopen(wname, wmode);
if(stream) goto fopen_ok;
fopen_fallback:
#endif
stream = fopen(filename, mode);
#ifdef WANT_WIN32_UNICODE
fopen_ok:
free(wmode);
free(wname);
#endif
return stream;
}
int compat_close(int infd)
{
#if (defined(WIN32) && !defined (__CYGWIN__)) /* MSDN says POSIX function is deprecated beginning in Visual C++ 2005 */
return _close(infd);
#else
return close(infd);
#endif
}
int compat_fclose(FILE *stream)
{
return fclose(stream);
}
/* Windows Unicode stuff */
#ifdef WANT_WIN32_UNICODE
int win32_wide_utf8(const wchar_t * const wptr, char **mbptr, size_t * buflen)
{
size_t len;
char *buf;
int ret = 0;
len = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, NULL, 0, NULL, NULL); /* Get utf-8 string length */
buf = calloc(len + 1, sizeof (char)); /* Can we assume sizeof char always = 1? */
if(!buf) len = 0;
else {
if (len != 0) ret = WideCharToMultiByte(CP_UTF8, 0, wptr, -1, buf, len, NULL, NULL); /*Do actual conversion*/
buf[len] = '0'; /* Must terminate */
}
*mbptr = buf; /* Set string pointer to allocated buffer */
if(buflen != NULL) *buflen = (len) * sizeof (char); /* Give length of allocated memory if needed. */
return ret;
}
int win32_utf8_wide(const char *const mbptr, wchar_t **wptr, size_t *buflen)
{
size_t len;
wchar_t *buf;
int ret = 0;
len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mbptr, -1, NULL, 0); /* Get converted size */
buf = calloc(len + 1, sizeof (wchar_t)); /* Allocate memory accordingly */
if(!buf) len = 0;
else {
if (len != 0) ret = MultiByteToWideChar (CP_UTF8, MB_ERR_INVALID_CHARS, mbptr, -1, buf, len); /* Do conversion */
buf[len] = L'0'; /* Must terminate */
}
*wptr = buf; /* Set string pointer to allocated buffer */
if (buflen != NULL) *buflen = len * sizeof (wchar_t); /* Give length of allocated memory if needed. */
return ret; /* Number of characters written */
}
#endif
/* This shall survive signals and any return value less than given byte count
is an error */
size_t unintr_write(int fd, void const *buffer, size_t bytes)
{
size_t written = 0;
while(bytes)
{
ssize_t part = write(fd, (char*)buffer+written, bytes);
if(part < 0 && errno != EINTR)
break;
bytes -= part;
written += part;
}
return written;
}
/* Same for reading the data. */
size_t unintr_read(int fd, void *buffer, size_t bytes)
{
size_t got = 0;
while(bytes)
{
ssize_t part = read(fd, (char*)buffer+got, bytes);
if(part < 0 && errno != EINTR)
break;
bytes -= part;
got += part;
}
return got;
}
#ifndef NO_CATCHSIGNAL
#if (!defined(WIN32) || defined (__CYGWIN__)) && defined(HAVE_SIGNAL_H)
void (*catchsignal(int signum, void(*handler)()))()
{
struct sigaction new_sa;
struct sigaction old_sa;
#ifdef DONT_CATCH_SIGNALS
fprintf (stderr, "Not catching any signals.\n");
return ((void (*)()) -1);
#endif
new_sa.sa_handler = handler;
sigemptyset(&new_sa.sa_mask);
new_sa.sa_flags = 0;
if(sigaction(signum, &new_sa, &old_sa) == -1)
return ((void (*)()) -1);
return (old_sa.sa_handler);
}
#endif
#endif

View file

@ -0,0 +1,43 @@
/*
compat: Some compatibility functions (basic memory and string stuff)
The mpg123 code is determined to keep it's legacy. A legacy of old, old UNIX.
So anything possibly somewhat advanced should be considered to be put here, with proper #ifdef;-)
copyright 2007-2016 by the mpg123 project - free software under the terms of the LGPL 2.1
see COPYING and AUTHORS files in distribution or http://mpg123.org
initially written by Thomas Orgis, Windows Unicode stuff by JonY.
*/
#include "compat.h"
#include "debug.h"
/* A safe realloc also for very old systems where realloc(NULL, size) returns NULL. */
void *safe_realloc(void *ptr, size_t size)
{
if(ptr == NULL) return malloc(size);
else return realloc(ptr, size);
}
#ifndef HAVE_STRERROR
const char *strerror(int errnum)
{
extern int sys_nerr;
extern char *sys_errlist[];
return (errnum < sys_nerr) ? sys_errlist[errnum] : "";
}
#endif
char* compat_strdup(const char *src)
{
char *dest = NULL;
if(src)
{
size_t len;
len = strlen(src)+1;
if((dest = malloc(len)))
memcpy(dest, src, len);
}
return dest;
}

View file

@ -384,7 +384,7 @@ icy2utf8(const char *src, int force)
/* Some funny streams from Apple/iTunes give ICY info in UTF-8 already.
So, be prepared and don't try to re-encode such. Unless forced. */
if(!force && is_utf8(src)) return (strdup(src));
if(!force && is_utf8(src)) return (compat_strdup(src));
srclen = strlen(src) + 1;
/* allocate conservatively */

View file

@ -656,6 +656,9 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
unsigned char flags = 0;
int ret = 1;
int ret2;
#ifndef NO_ID3V2
int skiptag = 0;
#endif
unsigned char major = first4bytes & 0xff;
debug1("ID3v2: major tag version: %i", major);
if(major == 0xff) return 0; /* Invalid... */
@ -706,17 +709,28 @@ int parse_new_id3(mpg123_handle *fr, unsigned long first4bytes)
#ifndef NO_ID3V2
if(VERBOSE2) fprintf(stderr,"Note: ID3v2.%i rev %i tag of %lu bytes\n", major, buf[0], length);
/* skip if unknown version/scary flags, parse otherwise */
if(fr->p.flags & MPG123_SKIP_ID3V2 || ((flags & UNKNOWN_FLAGS) || (major > 4) || (major < 2)))
if(fr->p.flags & MPG123_SKIP_ID3V2)
{
if(VERBOSE3)
fprintf(stderr, "Note: Skipping ID3v2 tag per user request.\n");
skiptag = 1;
}
if((flags & UNKNOWN_FLAGS) || (major > 4) || (major < 2))
{
if(NOQUIET)
{
if(fr->p.flags & MPG123_SKIP_ID3V2)
{
if(VERBOSE3) fprintf(stderr, "Note: Skipping ID3v2 tag per user request.\n");
}
else /* Must be because of scary Tag properties. */
warning2("ID3v2: Won't parse the ID3v2 tag with major version %u and flags 0x%xu - some extra code may be needed", major, flags);
}
warning2( "ID3v2: Won't parse the ID3v2 tag with major version"
" %u and flags 0x%xu - some extra code may be needed"
, major, flags );
skiptag = 1;
}
if(length < 10)
{
if(NOQUIET)
warning1("ID3v2: unrealistic small tag lengh %lu, skipping", length);
skiptag = 1;
}
if(skiptag)
{
#endif
if((ret2 = fr->rd->skip_bytes(fr,length)) < 0) /* will not store data in backbuff! */
ret = ret2;

View file

@ -11,6 +11,9 @@
#include "debug.h"
#include "gapless.h"
/* Want accurate rounding function regardless of decoder setup. */
#define FORCE_ACCURATE
#include "sample.h"
#define SEEKFRAME(mh) ((mh)->ignoreframe < 0 ? 0 : (mh)->ignoreframe)
@ -31,6 +34,15 @@ int attribute_align_arg mpg123_init(void)
prepare_decode_tables();
check_decoders();
initialized = 1;
#if (defined REAL_IS_FLOAT) && (defined IEEE_FLOAT)
/* This is rather pointless but it eases my mind to check that we did
not enable the special rounding on a VAX or something. */
if(12346 != REAL_TO_SHORT_ACCURATE(12345.67f))
{
error("Bad IEEE 754 rounding. Re-build libmpg123 properly.");
return MPG123_ERR;
}
#endif
return MPG123_OK;
}
@ -357,7 +369,7 @@ int attribute_align_arg mpg123_getstate(mpg123_handle *mh, enum mpg123_state key
{
size_t sval = bc_fill(&mh->rdat.buffer);
theval = (long)sval;
if((size_t)theval != sval)
if(theval < 0 || (size_t)theval != sval)
{
mh->err = MPG123_INT_OVERFLOW;
ret = MPG123_ERR;
@ -1035,7 +1047,8 @@ int attribute_align_arg mpg123_info(mpg123_handle *mh, struct mpg123_frameinfo *
return MPG123_OK;
}
int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding)
int attribute_align_arg mpg123_getformat2( mpg123_handle *mh
, long *rate, int *channels, int *encoding, int clear_flag )
{
int b;
@ -1046,10 +1059,15 @@ int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *cha
if(rate != NULL) *rate = mh->af.rate;
if(channels != NULL) *channels = mh->af.channels;
if(encoding != NULL) *encoding = mh->af.encoding;
mh->new_format = 0;
if(clear_flag) mh->new_format = 0;
return MPG123_OK;
}
int attribute_align_arg mpg123_getformat(mpg123_handle *mh, long *rate, int *channels, int *encoding)
{
return mpg123_getformat2(mh, rate, channels, encoding, 1);
}
off_t attribute_align_arg mpg123_timeframe(mpg123_handle *mh, double seconds)
{
off_t b;

View file

@ -1049,8 +1049,10 @@ static int default_init(mpg123_handle *fr)
if(fr->p.icy_interval > 0) fr->rdat.lseek = nix_lseek;
#endif
fr->rdat.filelen = get_fileinfo(fr);
fr->rdat.filelen = fr->p.flags & MPG123_NO_PEEK_END ? -1 : get_fileinfo(fr);
fr->rdat.filepos = 0;
if(fr->p.flags & MPG123_FORCE_SEEKABLE)
fr->rdat.flags |= READER_SEEKABLE;
/*
Don't enable seeking on ICY streams, just plain normal files.
This check is necessary since the client can enforce ICY parsing on files that would otherwise be seekable.

View file

@ -7,6 +7,9 @@
*/
#include "mpg123lib_intern.h"
#ifdef OPT_GENERIC_DITHER
#define FORCE_ACCURATE
#endif
#include "sample.h"
#include "debug.h"