|
1 | 1 | /* |
2 | 2 | FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. |
3 | | -dr_flac - v0.13.0 - 2025-07-23 |
| 3 | +dr_flac - v0.13.2 - TBD |
4 | 4 |
|
5 | 5 | |
6 | 6 |
|
@@ -126,7 +126,7 @@ extern "C" { |
126 | 126 |
|
127 | 127 | #define DRFLAC_VERSION_MAJOR 0 |
128 | 128 | #define DRFLAC_VERSION_MINOR 13 |
129 | | -#define DRFLAC_VERSION_REVISION 0 |
| 129 | +#define DRFLAC_VERSION_REVISION 2 |
130 | 130 | #define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) |
131 | 131 |
|
132 | 132 | #include <stddef.h> /* For size_t. */ |
@@ -331,16 +331,19 @@ typedef struct |
331 | 331 | */ |
332 | 332 | drflac_uint32 type; |
333 | 333 |
|
| 334 | + /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */ |
| 335 | + drflac_uint32 rawDataSize; |
| 336 | + |
| 337 | + /* The offset in the stream of the raw data. */ |
| 338 | + drflac_uint64 rawDataOffset; |
| 339 | + |
334 | 340 | /* |
335 | 341 | A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to |
336 | 342 | not modify the contents of this buffer. Use the structures below for more meaningful and structured |
337 | 343 | information about the metadata. It's possible for this to be null. |
338 | 344 | */ |
339 | 345 | const void* pRawData; |
340 | 346 |
|
341 | | - /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */ |
342 | | - drflac_uint32 rawDataSize; |
343 | | - |
344 | 347 | union |
345 | 348 | { |
346 | 349 | drflac_streaminfo streaminfo; |
@@ -392,6 +395,7 @@ typedef struct |
392 | 395 | drflac_uint32 colorDepth; |
393 | 396 | drflac_uint32 indexColorCount; |
394 | 397 | drflac_uint32 pictureDataSize; |
| 398 | + drflac_uint64 pictureDataOffset; /* Offset from the start of the stream. */ |
395 | 399 | const drflac_uint8* pPictureData; |
396 | 400 | } picture; |
397 | 401 | } data; |
@@ -6434,8 +6438,9 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d |
6434 | 6438 | runningFilePos += 4; |
6435 | 6439 |
|
6436 | 6440 | metadata.type = blockType; |
6437 | | - metadata.pRawData = NULL; |
6438 | 6441 | metadata.rawDataSize = 0; |
| 6442 | + metadata.rawDataOffset = runningFilePos; |
| 6443 | + metadata.pRawData = NULL; |
6439 | 6444 |
|
6440 | 6445 | switch (blockType) |
6441 | 6446 | { |
@@ -6712,59 +6717,149 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d |
6712 | 6717 | } |
6713 | 6718 |
|
6714 | 6719 | if (onMeta) { |
6715 | | - void* pRawData; |
6716 | | - const char* pRunningData; |
6717 | | - const char* pRunningDataEnd; |
| 6720 | + drflac_bool32 result = DRFLAC_TRUE; |
| 6721 | + drflac_uint32 blockSizeRemaining = blockSize; |
| 6722 | + char* pMime = NULL; |
| 6723 | + char* pDescription = NULL; |
| 6724 | + void* pPictureData = NULL; |
| 6725 | + |
| 6726 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.type, 4) != 4) { |
| 6727 | + result = DRFLAC_FALSE; |
| 6728 | + goto done_flac; |
| 6729 | + } |
| 6730 | + blockSizeRemaining -= 4; |
| 6731 | + metadata.data.picture.type = drflac__be2host_32(metadata.data.picture.type); |
6718 | 6732 |
|
6719 | | - pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); |
6720 | | - if (pRawData == NULL) { |
6721 | | - return DRFLAC_FALSE; |
| 6733 | + |
| 6734 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.mimeLength, 4) != 4) { |
| 6735 | + result = DRFLAC_FALSE; |
| 6736 | + goto done_flac; |
6722 | 6737 | } |
| 6738 | + blockSizeRemaining -= 4; |
| 6739 | + metadata.data.picture.mimeLength = drflac__be2host_32(metadata.data.picture.mimeLength); |
6723 | 6740 |
|
6724 | | - if (onRead(pUserData, pRawData, blockSize) != blockSize) { |
6725 | | - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
6726 | | - return DRFLAC_FALSE; |
| 6741 | + pMime = (char*)drflac__malloc_from_callbacks(metadata.data.picture.mimeLength + 1, pAllocationCallbacks); /* +1 for null terminator. */ |
| 6742 | + if (pMime == NULL) { |
| 6743 | + result = DRFLAC_FALSE; |
| 6744 | + goto done_flac; |
6727 | 6745 | } |
6728 | 6746 |
|
6729 | | - metadata.pRawData = pRawData; |
6730 | | - metadata.rawDataSize = blockSize; |
| 6747 | + if (blockSizeRemaining < metadata.data.picture.mimeLength || onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) { |
| 6748 | + result = DRFLAC_FALSE; |
| 6749 | + goto done_flac; |
| 6750 | + } |
| 6751 | + blockSizeRemaining -= metadata.data.picture.mimeLength; |
| 6752 | + pMime[metadata.data.picture.mimeLength] = '\0'; /* Null terminate for safety. */ |
| 6753 | + metadata.data.picture.mime = (const char*)pMime; |
6731 | 6754 |
|
6732 | | - pRunningData = (const char*)pRawData; |
6733 | | - pRunningDataEnd = (const char*)pRawData + blockSize; |
6734 | 6755 |
|
6735 | | - metadata.data.picture.type = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6736 | | - metadata.data.picture.mimeLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
| 6756 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.descriptionLength, 4) != 4) { |
| 6757 | + result = DRFLAC_FALSE; |
| 6758 | + goto done_flac; |
| 6759 | + } |
| 6760 | + blockSizeRemaining -= 4; |
| 6761 | + metadata.data.picture.descriptionLength = drflac__be2host_32(metadata.data.picture.descriptionLength); |
6737 | 6762 |
|
6738 | | - /* Need space for the rest of the block */ |
6739 | | - if ((pRunningDataEnd - pRunningData) - 24 < (drflac_int64)metadata.data.picture.mimeLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ |
6740 | | - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
6741 | | - return DRFLAC_FALSE; |
| 6763 | + pDescription = (char*)drflac__malloc_from_callbacks(metadata.data.picture.descriptionLength + 1, pAllocationCallbacks); /* +1 for null terminator. */ |
| 6764 | + if (pDescription == NULL) { |
| 6765 | + result = DRFLAC_FALSE; |
| 6766 | + goto done_flac; |
6742 | 6767 | } |
6743 | | - metadata.data.picture.mime = pRunningData; pRunningData += metadata.data.picture.mimeLength; |
6744 | | - metadata.data.picture.descriptionLength = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6745 | 6768 |
|
6746 | | - /* Need space for the rest of the block */ |
6747 | | - if ((pRunningDataEnd - pRunningData) - 20 < (drflac_int64)metadata.data.picture.descriptionLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ |
6748 | | - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
6749 | | - return DRFLAC_FALSE; |
| 6769 | + if (blockSizeRemaining < metadata.data.picture.descriptionLength || onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) { |
| 6770 | + result = DRFLAC_FALSE; |
| 6771 | + goto done_flac; |
6750 | 6772 | } |
6751 | | - metadata.data.picture.description = pRunningData; pRunningData += metadata.data.picture.descriptionLength; |
6752 | | - metadata.data.picture.width = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6753 | | - metadata.data.picture.height = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6754 | | - metadata.data.picture.colorDepth = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6755 | | - metadata.data.picture.indexColorCount = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6756 | | - metadata.data.picture.pictureDataSize = drflac__be2host_32_ptr_unaligned(pRunningData); pRunningData += 4; |
6757 | | - metadata.data.picture.pPictureData = (const drflac_uint8*)pRunningData; |
6758 | | - |
6759 | | - /* Need space for the picture after the block */ |
6760 | | - if (pRunningDataEnd - pRunningData < (drflac_int64)metadata.data.picture.pictureDataSize) { /* <-- Note the order of operations to avoid overflow to a valid value */ |
6761 | | - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
6762 | | - return DRFLAC_FALSE; |
| 6773 | + blockSizeRemaining -= metadata.data.picture.descriptionLength; |
| 6774 | + pDescription[metadata.data.picture.descriptionLength] = '\0'; /* Null terminate for safety. */ |
| 6775 | + metadata.data.picture.description = (const char*)pDescription; |
| 6776 | + |
| 6777 | + |
| 6778 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.width, 4) != 4) { |
| 6779 | + result = DRFLAC_FALSE; |
| 6780 | + goto done_flac; |
6763 | 6781 | } |
| 6782 | + blockSizeRemaining -= 4; |
| 6783 | + metadata.data.picture.width = drflac__be2host_32(metadata.data.picture.width); |
6764 | 6784 |
|
6765 | | - onMeta(pUserDataMD, &metadata); |
| 6785 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.height, 4) != 4) { |
| 6786 | + result = DRFLAC_FALSE; |
| 6787 | + goto done_flac; |
| 6788 | + } |
| 6789 | + blockSizeRemaining -= 4; |
| 6790 | + metadata.data.picture.height = drflac__be2host_32(metadata.data.picture.height); |
6766 | 6791 |
|
6767 | | - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
| 6792 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.colorDepth, 4) != 4) { |
| 6793 | + result = DRFLAC_FALSE; |
| 6794 | + goto done_flac; |
| 6795 | + } |
| 6796 | + blockSizeRemaining -= 4; |
| 6797 | + metadata.data.picture.colorDepth = drflac__be2host_32(metadata.data.picture.colorDepth); |
| 6798 | + |
| 6799 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.indexColorCount, 4) != 4) { |
| 6800 | + result = DRFLAC_FALSE; |
| 6801 | + goto done_flac; |
| 6802 | + } |
| 6803 | + blockSizeRemaining -= 4; |
| 6804 | + metadata.data.picture.indexColorCount = drflac__be2host_32(metadata.data.picture.indexColorCount); |
| 6805 | + |
| 6806 | + |
| 6807 | + /* Picture data. */ |
| 6808 | + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.pictureDataSize, 4) != 4) { |
| 6809 | + result = DRFLAC_FALSE; |
| 6810 | + goto done_flac; |
| 6811 | + } |
| 6812 | + blockSizeRemaining -= 4; |
| 6813 | + metadata.data.picture.pictureDataSize = drflac__be2host_32(metadata.data.picture.pictureDataSize); |
| 6814 | + |
| 6815 | + if (blockSizeRemaining < metadata.data.picture.pictureDataSize) { |
| 6816 | + result = DRFLAC_FALSE; |
| 6817 | + goto done_flac; |
| 6818 | + } |
| 6819 | + |
| 6820 | + /* For the actual image data we want to store the offset to the start of the stream. */ |
| 6821 | + metadata.data.picture.pictureDataOffset = runningFilePos + (blockSize - blockSizeRemaining); |
| 6822 | + |
| 6823 | + /* |
| 6824 | + For the allocation of image data, we can allow memory allocation to fail, in which case we just leave |
| 6825 | + the pointer as null. If it fails, we need to fall back to seeking past the image data. |
| 6826 | + */ |
| 6827 | + #ifndef DR_FLAC_NO_PICTURE_METADATA_MALLOC |
| 6828 | + pPictureData = drflac__malloc_from_callbacks(metadata.data.picture.pictureDataSize, pAllocationCallbacks); |
| 6829 | + if (pPictureData != NULL) { |
| 6830 | + if (onRead(pUserData, pPictureData, metadata.data.picture.pictureDataSize) != metadata.data.picture.pictureDataSize) { |
| 6831 | + result = DRFLAC_FALSE; |
| 6832 | + goto done_flac; |
| 6833 | + } |
| 6834 | + } else |
| 6835 | + #endif |
| 6836 | + { |
| 6837 | + /* Allocation failed. We need to seek past the picture data. */ |
| 6838 | + if (!onSeek(pUserData, metadata.data.picture.pictureDataSize, DRFLAC_SEEK_CUR)) { |
| 6839 | + result = DRFLAC_FALSE; |
| 6840 | + goto done_flac; |
| 6841 | + } |
| 6842 | + } |
| 6843 | + |
| 6844 | + blockSizeRemaining -= metadata.data.picture.pictureDataSize; |
| 6845 | + metadata.data.picture.pPictureData = (const drflac_uint8*)pPictureData; |
| 6846 | + |
| 6847 | + |
| 6848 | + /* Only fire the callback if we actually have a way to read the image data. We must have either a valid offset, or a valid data pointer. */ |
| 6849 | + if (metadata.data.picture.pictureDataOffset != 0 || metadata.data.picture.pPictureData != NULL) { |
| 6850 | + onMeta(pUserDataMD, &metadata); |
| 6851 | + } else { |
| 6852 | + /* Don't have a valid offset or data pointer, so just pretend we don't have a picture metadata. */ |
| 6853 | + } |
| 6854 | + |
| 6855 | + done_flac: |
| 6856 | + drflac__free_from_callbacks(pMime, pAllocationCallbacks); |
| 6857 | + drflac__free_from_callbacks(pDescription, pAllocationCallbacks); |
| 6858 | + drflac__free_from_callbacks(pPictureData, pAllocationCallbacks); |
| 6859 | + |
| 6860 | + if (result != DRFLAC_TRUE) { |
| 6861 | + return DRFLAC_FALSE; |
| 6862 | + } |
6768 | 6863 | } |
6769 | 6864 | } break; |
6770 | 6865 |
|
@@ -6800,13 +6895,16 @@ static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, d |
6800 | 6895 | */ |
6801 | 6896 | if (onMeta) { |
6802 | 6897 | void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); |
6803 | | - if (pRawData == NULL) { |
6804 | | - return DRFLAC_FALSE; |
6805 | | - } |
6806 | | - |
6807 | | - if (onRead(pUserData, pRawData, blockSize) != blockSize) { |
6808 | | - drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
6809 | | - return DRFLAC_FALSE; |
| 6898 | + if (pRawData != NULL) { |
| 6899 | + if (onRead(pUserData, pRawData, blockSize) != blockSize) { |
| 6900 | + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); |
| 6901 | + return DRFLAC_FALSE; |
| 6902 | + } |
| 6903 | + } else { |
| 6904 | + /* Allocation failed. We need to seek past the block. */ |
| 6905 | + if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) { |
| 6906 | + return DRFLAC_FALSE; |
| 6907 | + } |
6810 | 6908 | } |
6811 | 6909 |
|
6812 | 6910 | metadata.pRawData = pRawData; |
@@ -8699,7 +8797,7 @@ static drflac_bool32 drflac__on_tell_stdio(void* pUserData, drflac_int64* pCurso |
8699 | 8797 | DRFLAC_ASSERT(pFileStdio != NULL); |
8700 | 8798 | DRFLAC_ASSERT(pCursor != NULL); |
8701 | 8799 |
|
8702 | | -#if defined(_WIN32) |
| 8800 | +#if defined(_WIN32) && !defined(NXDK) |
8703 | 8801 | #if defined(_MSC_VER) && _MSC_VER > 1200 |
8704 | 8802 | result = _ftelli64(pFileStdio); |
8705 | 8803 | #else |
@@ -8821,8 +8919,6 @@ static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_ |
8821 | 8919 |
|
8822 | 8920 | DRFLAC_ASSERT(memoryStream != NULL); |
8823 | 8921 |
|
8824 | | - newCursor = memoryStream->currentReadPos; |
8825 | | - |
8826 | 8922 | if (origin == DRFLAC_SEEK_SET) { |
8827 | 8923 | newCursor = 0; |
8828 | 8924 | } else if (origin == DRFLAC_SEEK_CUR) { |
@@ -12077,6 +12173,13 @@ DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterat |
12077 | 12173 | /* |
12078 | 12174 | REVISION HISTORY |
12079 | 12175 | ================ |
| 12176 | +v0.13.2 - TBD |
| 12177 | + - Improve robustness of the parsing of picture metadata to improve support for memory constrained embedded devices. |
| 12178 | + - Fix a warning about an assigned by unused variable. |
| 12179 | + |
| 12180 | +v0.13.1 - 2025-09-10 |
| 12181 | + - Fix an error with the NXDK build. |
| 12182 | + |
12080 | 12183 | v0.13.0 - 2025-07-23 |
12081 | 12184 | - API CHANGE: Seek origin enums have been renamed to match the naming convention used by other dr_libs libraries: |
12082 | 12185 | - drflac_seek_origin_start -> DRFLAC_SEEK_SET |
|
0 commit comments