- /* Failed to read the seektable. Pretend we don't have one. */
- pFlac->pSeekpoints = NULL;
- pFlac->seekpointCount = 0;
- }
-
- /* We need to seek back to where we were. If this fails it's a critical error. */
- if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, drflac_seek_origin_start)) {
- drflac__free_from_callbacks(pFlac, &allocationCallbacks);
- return NULL;
- }
- } else {
- /* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */
- pFlac->pSeekpoints = NULL;
- pFlac->seekpointCount = 0;
- }
- }
- }
-
-
- /*
- If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode
- the first frame.
- */
- if (!init.hasStreamInfoBlock) {
- pFlac->currentFLACFrame.header = init.firstFrameHeader;
- for (;;) {
- drflac_result result = drflac__decode_flac_frame(pFlac);
- if (result == DRFLAC_SUCCESS) {
- break;
- } else {
- if (result == DRFLAC_CRC_MISMATCH) {
- if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) {
- drflac__free_from_callbacks(pFlac, &allocationCallbacks);
- return NULL;
- }
- continue;
- } else {
- drflac__free_from_callbacks(pFlac, &allocationCallbacks);
- return NULL;
- }
- }
- }
- }
-
- return pFlac;
-}
-
-
-
-#ifndef DR_FLAC_NO_STDIO
-#include <stdio.h>
-#include <wchar.h> /* For wcslen(), wcsrtombs() */
-
-/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */
-#include <errno.h>
-static drflac_result drflac_result_from_errno(int e)
-{
- switch (e)
- {
- case 0: return DRFLAC_SUCCESS;
- #ifdef EPERM
- case EPERM: return DRFLAC_INVALID_OPERATION;
- #endif
- #ifdef ENOENT
- case ENOENT: return DRFLAC_DOES_NOT_EXIST;
- #endif
- #ifdef ESRCH
- case ESRCH: return DRFLAC_DOES_NOT_EXIST;
- #endif
- #ifdef EINTR
- case EINTR: return DRFLAC_INTERRUPT;
- #endif
- #ifdef EIO
- case EIO: return DRFLAC_IO_ERROR;
- #endif
- #ifdef ENXIO
- case ENXIO: return DRFLAC_DOES_NOT_EXIST;
- #endif
- #ifdef E2BIG
- case E2BIG: return DRFLAC_INVALID_ARGS;
- #endif
- #ifdef ENOEXEC
- case ENOEXEC: return DRFLAC_INVALID_FILE;
- #endif
- #ifdef EBADF
- case EBADF: return DRFLAC_INVALID_FILE;
- #endif
- #ifdef ECHILD
- case ECHILD: return DRFLAC_ERROR;
- #endif
- #ifdef EAGAIN
- case EAGAIN: return DRFLAC_UNAVAILABLE;
- #endif
- #ifdef ENOMEM
- case ENOMEM: return DRFLAC_OUT_OF_MEMORY;
- #endif
- #ifdef EACCES
- case EACCES: return DRFLAC_ACCESS_DENIED;
- #endif
- #ifdef EFAULT
- case EFAULT: return DRFLAC_BAD_ADDRESS;
- #endif
- #ifdef ENOTBLK
- case ENOTBLK: return DRFLAC_ERROR;
- #endif
- #ifdef EBUSY
- case EBUSY: return DRFLAC_BUSY;
- #endif
- #ifdef EEXIST
- case EEXIST: return DRFLAC_ALREADY_EXISTS;
- #endif
- #ifdef EXDEV
- case EXDEV: return DRFLAC_ERROR;
- #endif
- #ifdef ENODEV
- case ENODEV: return DRFLAC_DOES_NOT_EXIST;
- #endif
- #ifdef ENOTDIR
- case ENOTDIR: return DRFLAC_NOT_DIRECTORY;
- #endif
- #ifdef EISDIR
- case EISDIR: return DRFLAC_IS_DIRECTORY;
- #endif
- #ifdef EINVAL
- case EINVAL: return DRFLAC_INVALID_ARGS;
- #endif
- #ifdef ENFILE
- case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
- #endif
- #ifdef EMFILE
- case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES;
- #endif
- #ifdef ENOTTY
- case ENOTTY: return DRFLAC_INVALID_OPERATION;
- #endif
- #ifdef ETXTBSY
- case ETXTBSY: return DRFLAC_BUSY;
- #endif
- #ifdef EFBIG
- case EFBIG: return DRFLAC_TOO_BIG;
- #endif
- #ifdef ENOSPC
- case ENOSPC: return DRFLAC_NO_SPACE;
- #endif
- #ifdef ESPIPE
- case ESPIPE: return DRFLAC_BAD_SEEK;
- #endif
- #ifdef EROFS
- case EROFS: return DRFLAC_ACCESS_DENIED;
- #endif
- #ifdef EMLINK
- case EMLINK: return DRFLAC_TOO_MANY_LINKS;
- #endif
- #ifdef EPIPE
- case EPIPE: return DRFLAC_BAD_PIPE;
- #endif
- #ifdef EDOM
- case EDOM: return DRFLAC_OUT_OF_RANGE;
- #endif
- #ifdef ERANGE
- case ERANGE: return DRFLAC_OUT_OF_RANGE;
- #endif
- #ifdef EDEADLK
- case EDEADLK: return DRFLAC_DEADLOCK;
- #endif
- #ifdef ENAMETOOLONG
- case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG;
- #endif
- #ifdef ENOLCK
- case ENOLCK: return DRFLAC_ERROR;
- #endif
- #ifdef ENOSYS
- case ENOSYS: return DRFLAC_NOT_IMPLEMENTED;
- #endif
- #ifdef ENOTEMPTY
- case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY;
- #endif
- #ifdef ELOOP
- case ELOOP: return DRFLAC_TOO_MANY_LINKS;
- #endif
- #ifdef ENOMSG
- case ENOMSG: return DRFLAC_NO_MESSAGE;
- #endif
- #ifdef EIDRM
- case EIDRM: return DRFLAC_ERROR;
- #endif
- #ifdef ECHRNG
- case ECHRNG: return DRFLAC_ERROR;
- #endif
- #ifdef EL2NSYNC
- case EL2NSYNC: return DRFLAC_ERROR;
- #endif
- #ifdef EL3HLT
- case EL3HLT: return DRFLAC_ERROR;
- #endif
- #ifdef EL3RST
- case EL3RST: return DRFLAC_ERROR;
- #endif
- #ifdef ELNRNG
- case ELNRNG: return DRFLAC_OUT_OF_RANGE;
- #endif
- #ifdef EUNATCH
- case EUNATCH: return DRFLAC_ERROR;
- #endif
- #ifdef ENOCSI
- case ENOCSI: return DRFLAC_ERROR;
- #endif
- #ifdef EL2HLT
- case EL2HLT: return DRFLAC_ERROR;
- #endif
- #ifdef EBADE
- case EBADE: return DRFLAC_ERROR;
- #endif
- #ifdef EBADR
- case EBADR: return DRFLAC_ERROR;
- #endif
- #ifdef EXFULL
- case EXFULL: return DRFLAC_ERROR;
- #endif
- #ifdef ENOANO
- case ENOANO: return DRFLAC_ERROR;
- #endif
- #ifdef EBADRQC
- case EBADRQC: return DRFLAC_ERROR;
- #endif
- #ifdef EBADSLT
- case EBADSLT: return DRFLAC_ERROR;
- #endif
- #ifdef EBFONT
- case EBFONT: return DRFLAC_INVALID_FILE;
- #endif
- #ifdef ENOSTR
- case ENOSTR: return DRFLAC_ERROR;
- #endif
- #ifdef ENODATA
- case ENODATA: return DRFLAC_NO_DATA_AVAILABLE;
- #endif
- #ifdef ETIME
- case ETIME: return DRFLAC_TIMEOUT;
- #endif
- #ifdef ENOSR
- case ENOSR: return DRFLAC_NO_DATA_AVAILABLE;
- #endif
- #ifdef ENONET
- case ENONET: return DRFLAC_NO_NETWORK;
- #endif
- #ifdef ENOPKG
- case ENOPKG: return DRFLAC_ERROR;
- #endif
- #ifdef EREMOTE
- case EREMOTE: return DRFLAC_ERROR;
- #endif
- #ifdef ENOLINK
- case ENOLINK: return DRFLAC_ERROR;
- #endif
- #ifdef EADV
- case EADV: return DRFLAC_ERROR;
- #endif
- #ifdef ESRMNT
- case ESRMNT: return DRFLAC_ERROR;
- #endif
- #ifdef ECOMM
- case ECOMM: return DRFLAC_ERROR;
- #endif
- #ifdef EPROTO
- case EPROTO: return DRFLAC_ERROR;
- #endif
- #ifdef EMULTIHOP
- case EMULTIHOP: return DRFLAC_ERROR;
- #endif
- #ifdef EDOTDOT
- case EDOTDOT: return DRFLAC_ERROR;
- #endif
- #ifdef EBADMSG
- case EBADMSG: return DRFLAC_BAD_MESSAGE;
- #endif
- #ifdef EOVERFLOW
- case EOVERFLOW: return DRFLAC_TOO_BIG;
- #endif
- #ifdef ENOTUNIQ
- case ENOTUNIQ: return DRFLAC_NOT_UNIQUE;
- #endif
- #ifdef EBADFD
- case EBADFD: return DRFLAC_ERROR;
- #endif
- #ifdef EREMCHG
- case EREMCHG: return DRFLAC_ERROR;
- #endif
- #ifdef ELIBACC
- case ELIBACC: return DRFLAC_ACCESS_DENIED;
- #endif
- #ifdef ELIBBAD
- case ELIBBAD: return DRFLAC_INVALID_FILE;
- #endif
- #ifdef ELIBSCN
- case ELIBSCN: return DRFLAC_INVALID_FILE;
- #endif
- #ifdef ELIBMAX
- case ELIBMAX: return DRFLAC_ERROR;
- #endif
- #ifdef ELIBEXEC
- case ELIBEXEC: return DRFLAC_ERROR;
- #endif
- #ifdef EILSEQ
- case EILSEQ: return DRFLAC_INVALID_DATA;
- #endif
- #ifdef ERESTART
- case ERESTART: return DRFLAC_ERROR;
- #endif
- #ifdef ESTRPIPE
- case ESTRPIPE: return DRFLAC_ERROR;
- #endif
- #ifdef EUSERS
- case EUSERS: return DRFLAC_ERROR;
- #endif
- #ifdef ENOTSOCK
- case ENOTSOCK: return DRFLAC_NOT_SOCKET;
- #endif
- #ifdef EDESTADDRREQ
- case EDESTADDRREQ: return DRFLAC_NO_ADDRESS;
- #endif
- #ifdef EMSGSIZE
- case EMSGSIZE: return DRFLAC_TOO_BIG;
- #endif
- #ifdef EPROTOTYPE
- case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL;
- #endif
- #ifdef ENOPROTOOPT
- case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE;
- #endif
- #ifdef EPROTONOSUPPORT
- case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED;
- #endif
- #ifdef ESOCKTNOSUPPORT
- case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED;
- #endif
- #ifdef EOPNOTSUPP
- case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION;
- #endif
- #ifdef EPFNOSUPPORT
- case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED;
- #endif
- #ifdef EAFNOSUPPORT
- case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED;
- #endif
- #ifdef EADDRINUSE
- case EADDRINUSE: return DRFLAC_ALREADY_IN_USE;
- #endif
- #ifdef EADDRNOTAVAIL
- case EADDRNOTAVAIL: return DRFLAC_ERROR;
- #endif
- #ifdef ENETDOWN
- case ENETDOWN: return DRFLAC_NO_NETWORK;
- #endif
- #ifdef ENETUNREACH
- case ENETUNREACH: return DRFLAC_NO_NETWORK;
- #endif
- #ifdef ENETRESET
- case ENETRESET: return DRFLAC_NO_NETWORK;
- #endif
- #ifdef ECONNABORTED
- case ECONNABORTED: return DRFLAC_NO_NETWORK;
- #endif
- #ifdef ECONNRESET
- case ECONNRESET: return DRFLAC_CONNECTION_RESET;
- #endif
- #ifdef ENOBUFS
- case ENOBUFS: return DRFLAC_NO_SPACE;
- #endif
- #ifdef EISCONN
- case EISCONN: return DRFLAC_ALREADY_CONNECTED;
- #endif
- #ifdef ENOTCONN
- case ENOTCONN: return DRFLAC_NOT_CONNECTED;
- #endif
- #ifdef ESHUTDOWN
- case ESHUTDOWN: return DRFLAC_ERROR;
- #endif
- #ifdef ETOOMANYREFS
- case ETOOMANYREFS: return DRFLAC_ERROR;
- #endif
- #ifdef ETIMEDOUT
- case ETIMEDOUT: return DRFLAC_TIMEOUT;
- #endif
- #ifdef ECONNREFUSED
- case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED;
- #endif
- #ifdef EHOSTDOWN
- case EHOSTDOWN: return DRFLAC_NO_HOST;
- #endif
- #ifdef EHOSTUNREACH
- case EHOSTUNREACH: return DRFLAC_NO_HOST;
- #endif
- #ifdef EALREADY
- case EALREADY: return DRFLAC_IN_PROGRESS;
- #endif
- #ifdef EINPROGRESS
- case EINPROGRESS: return DRFLAC_IN_PROGRESS;
- #endif
- #ifdef ESTALE
- case ESTALE: return DRFLAC_INVALID_FILE;
- #endif
- #ifdef EUCLEAN
- case EUCLEAN: return DRFLAC_ERROR;
- #endif
- #ifdef ENOTNAM
- case ENOTNAM: return DRFLAC_ERROR;
- #endif
- #ifdef ENAVAIL
- case ENAVAIL: return DRFLAC_ERROR;
- #endif
- #ifdef EISNAM
- case EISNAM: return DRFLAC_ERROR;
- #endif
- #ifdef EREMOTEIO
- case EREMOTEIO: return DRFLAC_IO_ERROR;
- #endif
- #ifdef EDQUOT
- case EDQUOT: return DRFLAC_NO_SPACE;
- #endif
- #ifdef ENOMEDIUM
- case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST;
- #endif
- #ifdef EMEDIUMTYPE
- case EMEDIUMTYPE: return DRFLAC_ERROR;
- #endif
- #ifdef ECANCELED
- case ECANCELED: return DRFLAC_CANCELLED;
- #endif
- #ifdef ENOKEY
- case ENOKEY: return DRFLAC_ERROR;
- #endif
- #ifdef EKEYEXPIRED
- case EKEYEXPIRED: return DRFLAC_ERROR;
- #endif
- #ifdef EKEYREVOKED
- case EKEYREVOKED: return DRFLAC_ERROR;
- #endif
- #ifdef EKEYREJECTED
- case EKEYREJECTED: return DRFLAC_ERROR;
- #endif
- #ifdef EOWNERDEAD
- case EOWNERDEAD: return DRFLAC_ERROR;
- #endif
- #ifdef ENOTRECOVERABLE
- case ENOTRECOVERABLE: return DRFLAC_ERROR;
- #endif
- #ifdef ERFKILL
- case ERFKILL: return DRFLAC_ERROR;
- #endif
- #ifdef EHWPOISON
- case EHWPOISON: return DRFLAC_ERROR;
- #endif
- default: return DRFLAC_ERROR;
- }
-}
-
-static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode)
-{
-#if defined(_MSC_VER) && _MSC_VER >= 1400
- errno_t err;
-#endif
-
- if (ppFile != NULL) {
- *ppFile = NULL; /* Safety. */
- }
-
- if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
- return DRFLAC_INVALID_ARGS;
- }
-
-#if defined(_MSC_VER) && _MSC_VER >= 1400
- err = fopen_s(ppFile, pFilePath, pOpenMode);
- if (err != 0) {
- return drflac_result_from_errno(err);
- }
-#else
-#if defined(_WIN32) || defined(__APPLE__)
- *ppFile = fopen(pFilePath, pOpenMode);
-#else
- #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE)
- *ppFile = fopen64(pFilePath, pOpenMode);
- #else
- *ppFile = fopen(pFilePath, pOpenMode);
- #endif
-#endif
- if (*ppFile == NULL) {
- drflac_result result = drflac_result_from_errno(errno);
- if (result == DRFLAC_SUCCESS) {
- result = DRFLAC_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */
- }
-
- return result;
- }
-#endif
-
- return DRFLAC_SUCCESS;
-}
-
-/*
-_wfopen() isn't always available in all compilation environments.
-
- * Windows only.
- * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back).
- * MinGW-64 (both 32- and 64-bit) seems to support it.
- * MinGW wraps it in !defined(__STRICT_ANSI__).
- * OpenWatcom wraps it in !defined(_NO_EXT_KEYS).
-
-This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs()
-fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support.
-*/
-#if defined(_WIN32)
- #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS))
- #define DRFLAC_HAS_WFOPEN
- #endif
-#endif
-
-static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks)
-{
- if (ppFile != NULL) {
- *ppFile = NULL; /* Safety. */
- }
-
- if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) {
- return DRFLAC_INVALID_ARGS;
- }
-
-#if defined(DRFLAC_HAS_WFOPEN)
- {
- /* Use _wfopen() on Windows. */
- #if defined(_MSC_VER) && _MSC_VER >= 1400
- errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode);
- if (err != 0) {
- return drflac_result_from_errno(err);
- }
- #else
- *ppFile = _wfopen(pFilePath, pOpenMode);
- if (*ppFile == NULL) {
- return drflac_result_from_errno(errno);
- }
- #endif
- (void)pAllocationCallbacks;
- }
-#else
- /*
- Use fopen() on anything other than Windows. Requires a conversion. This is annoying because fopen() is locale specific. The only real way I can
- think of to do this is with wcsrtombs(). Note that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for
- maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler error I'll look into improving compatibility.
- */
- {
- mbstate_t mbs;
- size_t lenMB;
- const wchar_t* pFilePathTemp = pFilePath;
- char* pFilePathMB = NULL;
- char pOpenModeMB[32] = {0};
-
- /* Get the length first. */
- DRFLAC_ZERO_OBJECT(&mbs);
- lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs);
- if (lenMB == (size_t)-1) {
- return drflac_result_from_errno(errno);
- }
-
- pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks);
- if (pFilePathMB == NULL) {
- return DRFLAC_OUT_OF_MEMORY;
- }
-
- pFilePathTemp = pFilePath;
- DRFLAC_ZERO_OBJECT(&mbs);
- wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs);
-
- /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */
- {
- size_t i = 0;
- for (;;) {
- if (pOpenMode[i] == 0) {
- pOpenModeMB[i] = '\0';
- break;
- }
-
- pOpenModeMB[i] = (char)pOpenMode[i];
- i += 1;
- }
- }
-
- *ppFile = fopen(pFilePathMB, pOpenModeMB);
-
- drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks);
- }
-
- if (*ppFile == NULL) {
- return DRFLAC_ERROR;
- }
-#endif
-
- return DRFLAC_SUCCESS;
-}
-
-static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead)
-{
- return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData);
-}
-
-static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin)
-{
- DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */
-
- return fseek((FILE*)pUserData, offset, (origin == drflac_seek_origin_current) ? SEEK_CUR : SEEK_SET) == 0;
-}
-
-
-DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
-{
- drflac* pFlac;
- FILE* pFile;
-
- if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
- return NULL;
- }
-
- pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
- if (pFlac == NULL) {
- fclose(pFile);
- return NULL;
- }
-
- return pFlac;
-}
-
-DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks)
-{
- drflac* pFlac;
- FILE* pFile;
-
- if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) {
- return NULL;
- }
-
- pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, (void*)pFile, pAllocationCallbacks);
- if (pFlac == NULL) {
- fclose(pFile);
- return NULL;
- }
-
- return pFlac;
-}
-
-DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks)
-{
- drflac* pFlac;
- FILE* pFile;
-
- if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) {
- return NULL;
- }