172 #if defined(DR_FS_IMPLEMENTATION) && !defined(_WIN32)
173 #ifndef _LARGEFILE64_SOURCE
174 #define _LARGEFILE64_SOURCE
176 #ifndef _FILE_OFFSET_BITS
177 #define _FILE_OFFSET_BITS 64
183 #ifndef DR_SIZED_TYPES_DEFINED
184 #define DR_SIZED_TYPES_DEFINED
185 #if defined(_MSC_VER) && _MSC_VER < 1600
220 #ifndef DRFS_MAX_PATH
222 #define DRFS_MAX_PATH 1024
226 #define DRFS_READ (1 << 0)
227 #define DRFS_WRITE (1 << 1)
228 #define DRFS_EXISTING (1 << 2)
229 #define DRFS_TRUNCATE (1 << 3)
230 #define DRFS_CREATE_DIRS (1 << 4) // Creates the directory structure if required.
232 #define DRFS_FILE_ATTRIBUTE_DIRECTORY 0x00000001
233 #define DRFS_FILE_ATTRIBUTE_READONLY 0x00000002
679 #ifdef DR_FS_IMPLEMENTATION
693 #define DR_FS_OWNS_PARENT_ARCHIVE 0x00000001
696 static int drfs__strcpy_s(
char* dst,
size_t dstSizeInBytes,
const char* src)
699 return strcpy_s(dst, dstSizeInBytes, src);
704 if (dstSizeInBytes == 0) {
713 for (i = 0; i < dstSizeInBytes && src[i] !=
'\0'; ++i) {
717 if (i < dstSizeInBytes) {
727 static int drfs__strncpy_s(
char* dst,
size_t dstSizeInBytes,
const char* src,
size_t count)
735 if (dstSizeInBytes == 0) {
743 size_t maxcount =
count;
744 if (
count == ((
size_t)-1) ||
count >= dstSizeInBytes) {
745 maxcount = dstSizeInBytes - 1;
749 for (i = 0; i < maxcount && src[i] !=
'\0'; ++i) {
753 if (src[i] ==
'\0' || i ==
count ||
count == ((
size_t)-1)) {
763 static int drfs__strcat_s(
char* dst,
size_t dstSizeInBytes,
const char* src)
766 return strcat_s(dst, dstSizeInBytes, src);
771 if (dstSizeInBytes == 0) {
781 while (dstSizeInBytes > 0 && dst[0] !=
'\0') {
786 if (dstSizeInBytes == 0) {
791 while (dstSizeInBytes > 0 && src[0] !=
'\0') {
796 if (dstSizeInBytes > 0) {
807 static int drfs__stricmp(
const char* string1,
const char* string2)
812 return strcasecmp(string1, string2);
819 if (pBasePaths ==
NULL) {
825 pBasePaths->
count = 0;
832 if (pBasePaths ==
NULL) {
839 static dr_bool32 drfs_basedirs_inflateandinsert(
drfs_basedirs* pBasePaths,
const char* absolutePath,
unsigned int index)
841 if (pBasePaths ==
NULL) {
845 unsigned int newBufferSize = (pBasePaths->
capacity == 0) ? 2 : pBasePaths->
capacity*2;
849 if (pNewBuffer ==
NULL) {
853 for (
unsigned int iDst = 0; iDst < index; ++iDst) {
854 memcpy(pNewBuffer + iDst, pOldBuffer + iDst,
sizeof(
drfs_basepath));
857 drfs__strcpy_s((pNewBuffer + index)->absolutePath,
DRFS_MAX_PATH, absolutePath);
859 for (
unsigned int iDst = index; iDst < pBasePaths->
count; ++iDst) {
860 memcpy(pNewBuffer + iDst + 1, pOldBuffer + iDst,
sizeof(
drfs_basepath));
864 pBasePaths->
pBuffer = pNewBuffer;
865 pBasePaths->
capacity = newBufferSize;
866 pBasePaths->
count += 1;
878 for (
unsigned int iDst = pBasePaths->
count; iDst > index; --iDst) {
885 static dr_bool32 drfs_basedirs_insert(
drfs_basedirs* pBasePaths,
const char* absolutePath,
unsigned int index)
887 if (pBasePaths ==
NULL || index > pBasePaths->
count) {
892 return drfs_basedirs_inflateandinsert(pBasePaths, absolutePath, index);
894 if (!drfs_basedirs_movedown1slot(pBasePaths, index)) {
899 pBasePaths->
count += 1;
907 if (pBasePaths ==
NULL || index >= pBasePaths->
count) {
911 assert(pBasePaths->
count > 0);
913 for (
unsigned int iDst = index; iDst < pBasePaths->
count - 1; ++iDst) {
917 pBasePaths->
count -= 1;
924 if (pBasePaths ==
NULL) {
928 drfs_basedirs_uninit(pBasePaths);
929 drfs_basedirs_init(pBasePaths);
963 if (pNewBuffer ==
NULL) {
967 for (
unsigned int iDst = 0; iDst < pList->
count; ++iDst) {
983 if (!drfs_callbacklist_inflate(pList)) {
1038 #ifdef DR_FS_WIN32_USE_EVENT_MUTEX
1041 CRITICAL_SECTION lock;
1044 pthread_mutex_t lock;
1058 } drfs_drpath_segment;
1061 typedef struct drfs_drpath_iterator
1064 drfs_drpath_segment segment;
1065 } drfs_drpath_iterator;
1067 static dr_bool32 drfs_drpath_next(drfs_drpath_iterator* i)
1069 if (i ==
NULL || i->path ==
NULL) {
1073 i->segment.offset = i->segment.offset + i->segment.length;
1074 i->segment.length = 0;
1076 while (i->path[i->segment.offset] !=
'\0' && (i->path[i->segment.offset] ==
'/' || i->path[i->segment.offset] ==
'\\')) {
1077 i->segment.offset += 1;
1080 if (i->path[i->segment.offset] ==
'\0') {
1085 while (i->path[i->segment.offset + i->segment.length] !=
'\0' && (i->path[i->segment.offset + i->segment.length] !=
'/' && i->path[i->segment.offset + i->segment.length] !=
'\\')) {
1086 i->segment.length += 1;
1092 static dr_bool32 drfs_drpath_prev(drfs_drpath_iterator* i)
1094 if (i ==
NULL || i->path ==
NULL || i->segment.offset == 0) {
1098 i->segment.length = 0;
1102 i->segment.offset -= 1;
1103 }
while (i->segment.offset > 0 && (i->path[i->segment.offset] ==
'/' || i->path[i->segment.offset] ==
'\\'));
1105 if (i->segment.offset == 0) {
1106 if (i->path[i->segment.offset] ==
'/' || i->path[i->segment.offset] ==
'\\') {
1107 i->segment.length = 0;
1115 size_t offsetEnd = i->segment.offset + 1;
1116 while (i->segment.offset > 0 && (i->path[i->segment.offset] !=
'/' && i->path[i->segment.offset] !=
'\\')) {
1117 i->segment.offset -= 1;
1120 if (i->path[i->segment.offset] ==
'/' || i->path[i->segment.offset] ==
'\\') {
1121 i->segment.offset += 1;
1125 i->segment.length = offsetEnd - i->segment.offset;
1130 static dr_bool32 drfs_drpath_first(
const char* path, drfs_drpath_iterator* i)
1134 i->segment.offset = 0;
1135 i->segment.length = 0;
1137 if (path == 0 || path[0] ==
'\0') {
1141 while (i->path[i->segment.length] !=
'\0' && (i->path[i->segment.length] !=
'/' && i->path[i->segment.length] !=
'\\')) {
1142 i->segment.length += 1;
1148 static dr_bool32 drfs_drpath_last(
const char* path, drfs_drpath_iterator* i)
1152 i->segment.offset = 0;
1153 i->segment.length = 0;
1155 if (path == 0 || path[0] ==
'\0') {
1160 i->segment.offset = strlen(path);
1161 i->segment.length = 0;
1163 return drfs_drpath_prev(i);
1166 static dr_bool32 drfs_drpath_segments_equal(
const char* s0Path,
const drfs_drpath_segment s0,
const char* s1Path,
const drfs_drpath_segment s1)
1168 if (s0Path ==
NULL || s1Path ==
NULL) {
1172 if (s0.length != s1.length) {
1176 return strncmp(s0Path + s0.offset, s1Path + s1.offset, s0.length) == 0;
1179 static dr_bool32 drfs_drpath_iterators_equal(
const drfs_drpath_iterator i0,
const drfs_drpath_iterator i1)
1181 return drfs_drpath_segments_equal(i0.path, i0.segment, i1.path, i1.segment);
1184 static dr_bool32 drfs_drpath_is_linux_style_root_segment(
const drfs_drpath_iterator i)
1186 if (i.path ==
NULL) {
1190 if (i.segment.offset == 0 && i.segment.length == 0) {
1197 static dr_bool32 drfs_drpath_is_win32_style_root_segment(
const drfs_drpath_iterator i)
1199 if (i.path ==
NULL) {
1203 if (i.segment.offset == 0 && i.segment.length == 2) {
1204 if (((i.path[0] >=
'a' && i.path[0] <=
'z') || (i.path[0] >=
'A' && i.path[0] <=
'Z')) && i.path[1] ==
':') {
1212 static dr_bool32 drfs_drpath_is_root_segment(
const drfs_drpath_iterator i)
1214 return drfs_drpath_is_linux_style_root_segment(i) || drfs_drpath_is_win32_style_root_segment(i);
1217 static dr_bool32 drfs_drpath_append_iterator(
char* base,
size_t baseBufferSizeInBytes, drfs_drpath_iterator i)
1223 size_t path1Length = strlen(base);
1224 size_t path2Length = i.segment.length;
1226 if (path1Length >= baseBufferSizeInBytes) {
1230 if (drfs_drpath_is_linux_style_root_segment(i)) {
1231 if (baseBufferSizeInBytes > 1) {
1240 if (path1Length > 0 && base[path1Length - 1] !=
'/' && base[path1Length - 1] !=
'\\') {
1241 base[path1Length] =
'/';
1246 if (path1Length + path2Length >= baseBufferSizeInBytes) {
1247 path2Length = baseBufferSizeInBytes - path1Length - 1;
1250 drfs__strncpy_s(base + path1Length, baseBufferSizeInBytes - path1Length, i.path + i.segment.offset, path2Length);
1255 static dr_bool32 drfs_drpath_is_descendant(
const char* descendantAbsolutePath,
const char* parentAbsolutePath)
1257 drfs_drpath_iterator iChild;
1258 if (!drfs_drpath_first(descendantAbsolutePath, &iChild)) {
1262 drfs_drpath_iterator iParent;
1263 if (drfs_drpath_first(parentAbsolutePath, &iParent))
1268 if (!drfs_drpath_iterators_equal(iParent, iChild)) {
1272 if (!drfs_drpath_next(&iChild)) {
1276 }
while (drfs_drpath_next(&iParent));
1282 static dr_bool32 drfs_drpath_is_child(
const char* childAbsolutePath,
const char* parentAbsolutePath)
1284 drfs_drpath_iterator iChild;
1285 if (!drfs_drpath_first(childAbsolutePath, &iChild)) {
1289 drfs_drpath_iterator iParent;
1290 if (drfs_drpath_first(parentAbsolutePath, &iParent))
1295 if (!drfs_drpath_iterators_equal(iParent, iChild)) {
1299 if (!drfs_drpath_next(&iChild)) {
1303 }
while (drfs_drpath_next(&iParent));
1308 return !drfs_drpath_next(&iChild);
1311 static void drfs_drpath_base_path(
char* path)
1317 char* baseend = path;
1320 while (path[0] !=
'\0') {
1321 if (path[0] ==
'/' || path[0] ==
'\\') {
1330 while (baseend > path) {
1331 if (baseend[0] !=
'/' && baseend[0] !=
'\\') {
1343 static void drfs_drpath_copy_base_path(
const char* path,
char* baseOut,
size_t baseSizeInBytes)
1345 if (path ==
NULL || baseOut ==
NULL || baseSizeInBytes == 0) {
1349 drfs__strcpy_s(baseOut, baseSizeInBytes, path);
1350 drfs_drpath_base_path(baseOut);
1353 static const char* drfs_drpath_file_name(
const char* path)
1359 const char* fileName = path;
1362 while (path[0] !=
'\0') {
1363 if (path[0] ==
'/' || path[0] ==
'\\') {
1371 while (fileName[0] !=
'\0' && (fileName[0] ==
'/' || fileName[0] ==
'\\')) {
1378 static const char* drfs_drpath_extension(
const char* path)
1384 const char* extension = drfs_drpath_file_name(path);
1385 const char* lastoccurance = 0;
1388 while (extension[0] !=
'\0')
1392 if (extension[0] ==
'.') {
1394 lastoccurance = extension;
1398 return (lastoccurance != 0) ? lastoccurance : extension;
1401 static dr_bool32 drfs_drpath_equal(
const char* path1,
const char* path2)
1403 if (path1 ==
NULL || path2 ==
NULL) {
1407 if (path1 == path2 || (path1[0] ==
'\0' && path2[0] ==
'\0')) {
1411 drfs_drpath_iterator iPath1;
1412 drfs_drpath_iterator iPath2;
1413 if (drfs_drpath_first(path1, &iPath1) && drfs_drpath_first(path2, &iPath2))
1420 if (!drfs_drpath_iterators_equal(iPath1, iPath2)) {
1424 isPath1Valid = drfs_drpath_next(&iPath1);
1425 isPath2Valid = drfs_drpath_next(&iPath2);
1427 }
while (isPath1Valid && isPath2Valid);
1430 return isPath1Valid == isPath2Valid && iPath1.path[iPath1.segment.offset] ==
'\0' && iPath2.path[iPath2.segment.offset] ==
'\0';
1436 static dr_bool32 drfs_drpath_is_relative(
const char* path)
1442 drfs_drpath_iterator seg;
1443 if (drfs_drpath_first(path, &seg)) {
1444 return !drfs_drpath_is_root_segment(seg);
1451 static dr_bool32 drfs_drpath_is_absolute(
const char* path)
1453 return !drfs_drpath_is_relative(path);
1456 static dr_bool32 drfs_drpath_append(
char* base,
size_t baseBufferSizeInBytes,
const char* other)
1458 if (base ==
NULL || other ==
NULL) {
1462 size_t path1Length = strlen(base);
1463 size_t path2Length = strlen(other);
1465 if (path1Length >= baseBufferSizeInBytes) {
1471 if (path1Length > 0 && base[path1Length - 1] !=
'/' && base[path1Length - 1] !=
'\\') {
1472 base[path1Length] =
'/';
1477 if (path1Length + path2Length >= baseBufferSizeInBytes) {
1478 path2Length = baseBufferSizeInBytes - path1Length - 1;
1481 drfs__strncpy_s(base + path1Length, baseBufferSizeInBytes - path1Length, other, path2Length);
1486 static dr_bool32 drfs_drpath_copy_and_append(
char* dst,
size_t dstSizeInBytes,
const char* base,
const char* other)
1488 if (dst ==
NULL || dstSizeInBytes == 0) {
1492 drfs__strcpy_s(dst, dstSizeInBytes, base);
1493 return drfs_drpath_append(dst, dstSizeInBytes, other);
1500 static size_t _drfs_drpath_clean_trywrite(drfs_drpath_iterator* iterators,
unsigned int iteratorCount,
char* pathOut,
size_t pathOutSizeInBytes,
unsigned int ignoreCounter)
1502 if (iteratorCount == 0) {
1506 drfs_drpath_iterator isegment = iterators[iteratorCount - 1];
1510 int ignoreThisSegment = ignoreCounter > 0 && isegment.segment.length > 0;
1512 if (isegment.segment.length == 1 && isegment.path[isegment.segment.offset] ==
'.')
1515 ignoreThisSegment = 1;
1519 if (isegment.segment.length == 2 && isegment.path[isegment.segment.offset] ==
'.' && isegment.path[isegment.segment.offset + 1] ==
'.')
1522 ignoreThisSegment = 1;
1528 if (ignoreCounter > 0) {
1536 size_t bytesWritten = 0;
1538 drfs_drpath_iterator prev = isegment;
1539 if (!drfs_drpath_prev(&prev))
1541 if (iteratorCount > 1)
1544 prev = iterators[iteratorCount - 1];
1549 prev.segment.offset = 0;
1550 prev.segment.length = 0;
1554 if (prev.segment.length > 0)
1556 iterators[iteratorCount - 1] = prev;
1557 bytesWritten = _drfs_drpath_clean_trywrite(iterators, iteratorCount, pathOut, pathOutSizeInBytes, ignoreCounter);
1561 if (!ignoreThisSegment)
1563 if (pathOutSizeInBytes > 0)
1565 pathOut += bytesWritten;
1566 pathOutSizeInBytes -= bytesWritten;
1568 if (bytesWritten > 0)
1574 pathOutSizeInBytes -= 1;
1577 if (pathOutSizeInBytes >= isegment.segment.length)
1579 drfs__strncpy_s(pathOut, pathOutSizeInBytes, isegment.path + isegment.segment.offset, isegment.segment.length);
1580 bytesWritten += isegment.segment.length;
1584 drfs__strncpy_s(pathOut, pathOutSizeInBytes, isegment.path + isegment.segment.offset, pathOutSizeInBytes);
1585 bytesWritten += pathOutSizeInBytes;
1590 return bytesWritten;
1593 static size_t drfs_drpath_append_and_clean(
char* dst,
size_t dstSizeInBytes,
const char* base,
const char* other)
1595 if (base ==
NULL || other ==
NULL) {
1599 drfs_drpath_iterator last[2];
1600 dr_bool32 isPathEmpty0 = !drfs_drpath_last(base, last + 0);
1601 dr_bool32 isPathEmpty1 = !drfs_drpath_last(other, last + 1);
1603 if (isPathEmpty0 && isPathEmpty1) {
1607 size_t bytesWritten = 0;
1608 if (base[0] ==
'/') {
1609 if (dst !=
NULL && dstSizeInBytes > 1) {
1615 bytesWritten += _drfs_drpath_clean_trywrite(last, 2, dst + bytesWritten, dstSizeInBytes - bytesWritten - 1, 0);
1616 if (dstSizeInBytes > bytesWritten) {
1617 dst[bytesWritten] =
'\0';
1620 return bytesWritten + 1;
1627 static dr_bool32 drfs_mkdir_recursive_native(
const char* absolutePath);
1631 static dr_bool32 drfs_validate_write_path(
drfs_context* pContext,
const char* absoluteOrRelativePath,
char* absolutePathOut,
unsigned int absolutePathOutSize)
1634 if (drfs_drpath_is_relative(absoluteOrRelativePath)) {
1635 if (drfs_drpath_append_and_clean(absolutePathOut, absolutePathOutSize, pContext->
writeBaseDirectory, absoluteOrRelativePath)) {
1636 absoluteOrRelativePath = absolutePathOut;
1641 if (drfs__strcpy_s(absolutePathOut, absolutePathOutSize, absoluteOrRelativePath) != 0) {
1649 assert(drfs_drpath_is_absolute(absoluteOrRelativePath));
1650 if (!drfs_drpath_is_absolute(absoluteOrRelativePath)) {
1656 if (drfs_drpath_is_descendant(absoluteOrRelativePath, pContext->
writeBaseDirectory)) {
1668 static unsigned int drfs_archive_access_mode(
unsigned int fileAccessMode)
1681 #define DR_FS_USE_WIN32
1683 #define DR_FS_USE_STDIO
1692 static drfs_result drfs_open_native_file(
const char* absolutePath,
unsigned int accessMode,
drfs_handle* pHandleOut);
1695 static void drfs_close_native_file(
drfs_handle file);
1698 static dr_bool32 drfs_is_native_directory(
const char* absolutePath);
1701 static dr_bool32 drfs_is_native_file(
const char* absolutePath);
1704 static drfs_result drfs_delete_native_file(
const char* absolutePath);
1707 static drfs_result drfs_mkdir_native(
const char* absolutePath);
1710 static drfs_result drfs_move_native_file(
const char* absolutePathOld,
const char* absolutePathNew);
1713 static drfs_result drfs_copy_native_file(
const char* absolutePathSrc,
const char* absolutePathDst,
dr_bool32 failIfExists);
1716 static drfs_result drfs_read_native_file(
drfs_handle file,
void* pDataOut,
size_t bytesToRead,
size_t* pBytesReadOut);
1719 static drfs_result drfs_write_native_file(
drfs_handle file,
const void* pData,
size_t bytesToWrite,
size_t* pBytesWrittenOut);
1731 static void drfs_flush_native_file(
drfs_handle file);
1741 static drfs_handle drfs_begin_native_iteration(
const char* absolutePath);
1744 static void drfs_end_native_iteration(
drfs_handle iterator);
1751 #ifdef DR_FS_USE_WIN32
1754 switch (GetLastError())
1769 static drfs_result drfs_open_native_file(
const char* absolutePath,
unsigned int accessMode,
drfs_handle* pHandleOut)
1771 assert(absolutePath !=
NULL);
1772 assert(pHandleOut !=
NULL);
1774 DWORD dwDesiredAccess = 0;
1775 DWORD dwShareMode = 0;
1776 DWORD dwCreationDisposition = OPEN_EXISTING;
1779 dwDesiredAccess |= FILE_GENERIC_READ;
1780 dwShareMode |= FILE_SHARE_READ;
1784 dwDesiredAccess |= FILE_GENERIC_WRITE;
1788 dwCreationDisposition = TRUNCATE_EXISTING;
1790 dwCreationDisposition = OPEN_EXISTING;
1794 dwCreationDisposition = CREATE_ALWAYS;
1796 dwCreationDisposition = OPEN_ALWAYS;
1802 HANDLE hFile = CreateFileA(absolutePath, dwDesiredAccess, dwShareMode,
NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL,
NULL);
1803 if (hFile == INVALID_HANDLE_VALUE)
1810 drfs_drpath_copy_base_path(absolutePath, dirAbsolutePath,
sizeof(dirAbsolutePath));
1812 if (!drfs_is_native_directory(dirAbsolutePath) && drfs_mkdir_recursive_native(dirAbsolutePath)) {
1813 hFile = CreateFileA(absolutePath, dwDesiredAccess, dwShareMode,
NULL, dwCreationDisposition, FILE_ATTRIBUTE_NORMAL,
NULL);
1818 if (hFile != INVALID_HANDLE_VALUE) {
1823 return drfs__GetLastError_to_result();
1826 static void drfs_close_native_file(
drfs_handle file)
1828 CloseHandle((HANDLE)file);
1831 static dr_bool32 drfs_is_native_directory(
const char* absolutePath)
1833 DWORD attributes = GetFileAttributesA(absolutePath);
1834 return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
1837 static dr_bool32 drfs_is_native_file(
const char* absolutePath)
1839 DWORD attributes = GetFileAttributesA(absolutePath);
1840 return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
1843 static drfs_result drfs_delete_native_file(
const char* absolutePath)
1847 DWORD attributes = GetFileAttributesA(absolutePath);
1848 if (attributes == INVALID_FILE_ATTRIBUTES || (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
1849 wasSuccessful = DeleteFileA(absolutePath);
1851 wasSuccessful = RemoveDirectoryA(absolutePath);
1854 if (wasSuccessful) {
1858 return drfs__GetLastError_to_result();
1861 static drfs_result drfs_mkdir_native(
const char* absolutePath)
1863 BOOL wasSuccessful = CreateDirectoryA(absolutePath,
NULL);
1864 if (wasSuccessful) {
1868 return drfs__GetLastError_to_result();
1871 static drfs_result drfs_move_native_file(
const char* absolutePathOld,
const char* absolutePathNew)
1873 BOOL wasSuccessful = MoveFileExA(absolutePathOld, absolutePathNew, 0);
1874 if (wasSuccessful) {
1878 return drfs__GetLastError_to_result();
1881 static drfs_result drfs_copy_native_file(
const char* absolutePathSrc,
const char* absolutePathDst,
dr_bool32 failIfExists)
1883 BOOL wasSuccessful = CopyFileA(absolutePathSrc, absolutePathDst, failIfExists);
1884 if (wasSuccessful) {
1888 return drfs__GetLastError_to_result();
1891 static drfs_result drfs_read_native_file(
drfs_handle file,
void* pDataOut,
size_t bytesToRead,
size_t* pBytesReadOut)
1896 size_t totalBytesRead = 0;
1898 char* pDst = (
char*)pDataOut;
1900 while (bytesRemaining > 0)
1902 DWORD bytesToProcess;
1903 if (bytesRemaining > UINT_MAX) {
1904 bytesToProcess = UINT_MAX;
1906 bytesToProcess = (DWORD)bytesRemaining;
1911 BOOL wasSuccessful = ReadFile((HANDLE)file, pDst, bytesToProcess, &bytesRead,
NULL);
1912 if (!wasSuccessful || bytesRead != bytesToProcess)
1915 totalBytesRead += bytesRead;
1917 if (pBytesReadOut) {
1918 *pBytesReadOut = totalBytesRead;
1921 return drfs__GetLastError_to_result();
1925 bytesRemaining -= bytesRead;
1926 totalBytesRead += bytesRead;
1930 if (pBytesReadOut !=
NULL) {
1931 *pBytesReadOut = totalBytesRead;
1937 static drfs_result drfs_write_native_file(
drfs_handle file,
const void* pData,
size_t bytesToWrite,
size_t* pBytesWrittenOut)
1942 size_t totalBytesWritten = 0;
1943 const char* pSrc = (
const char*)pData;
1945 size_t bytesRemaining = bytesToWrite;
1946 while (bytesRemaining > 0)
1948 DWORD bytesToProcess;
1949 if (bytesRemaining > UINT_MAX) {
1950 bytesToProcess = UINT_MAX;
1952 bytesToProcess = (DWORD)bytesRemaining;
1956 BOOL wasSuccessful = WriteFile((HANDLE)file, pSrc, bytesToProcess, &bytesWritten,
NULL);
1957 if (!wasSuccessful || bytesWritten != bytesToProcess)
1960 totalBytesWritten += bytesWritten;
1962 if (pBytesWrittenOut) {
1963 *pBytesWrittenOut = totalBytesWritten;
1966 return drfs__GetLastError_to_result();
1969 pSrc += bytesWritten;
1970 bytesRemaining -= bytesWritten;
1971 totalBytesWritten += bytesWritten;
1974 if (pBytesWrittenOut) {
1975 *pBytesWrittenOut = totalBytesWritten;
1983 LARGE_INTEGER lNewFilePointer;
1984 LARGE_INTEGER lDistanceToMove;
1985 lDistanceToMove.QuadPart = bytesToSeek;
1987 DWORD dwMoveMethod = FILE_CURRENT;
1989 dwMoveMethod = FILE_BEGIN;
1991 dwMoveMethod = FILE_END;
1994 BOOL wasSuccessful = SetFilePointerEx((HANDLE)file, lDistanceToMove, &lNewFilePointer, dwMoveMethod);
1995 if (!wasSuccessful) {
1996 return drfs__GetLastError_to_result();
2004 LARGE_INTEGER lNewFilePointer;
2005 LARGE_INTEGER lDistanceToMove;
2006 lDistanceToMove.QuadPart = 0;
2008 if (SetFilePointerEx((HANDLE)file, lDistanceToMove, &lNewFilePointer, FILE_CURRENT)) {
2009 return (
dr_uint64)lNewFilePointer.QuadPart;
2017 LARGE_INTEGER fileSize;
2018 if (GetFileSizeEx((HANDLE)file, &fileSize)) {
2025 static void drfs_flush_native_file(
drfs_handle file)
2027 FlushFileBuffers((HANDLE)file);
2032 assert(absolutePath !=
NULL);
2036 if (GetFileAttributesA(absolutePath) != INVALID_FILE_ATTRIBUTES) {
2043 WIN32_FILE_ATTRIBUTE_DATA fad;
2044 if (GetFileAttributesExA(absolutePath, GetFileExInfoStandard, &fad))
2046 ULARGE_INTEGER liSize;
2047 liSize.LowPart = fad.nFileSizeLow;
2048 liSize.HighPart = fad.nFileSizeHigh;
2050 ULARGE_INTEGER liTime;
2051 liTime.LowPart = fad.ftLastWriteTime.dwLowDateTime;
2052 liTime.HighPart = fad.ftLastWriteTime.dwHighDateTime;
2059 if ((fad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
2062 if ((fad.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
2069 return drfs__GetLastError_to_result();
2075 WIN32_FIND_DATAA ffd;
2076 char directoryPath[1];
2077 } drfs_iterator_win32;
2079 static drfs_handle drfs_begin_native_iteration(
const char* absolutePath)
2081 assert(drfs_drpath_is_absolute(absolutePath));
2084 if (
strcpy_s(searchQuery,
sizeof(searchQuery), absolutePath) != 0) {
2088 unsigned int searchQueryLength = (
unsigned int)strlen(searchQuery);
2093 searchQuery[searchQueryLength + 0] =
'\\';
2094 searchQuery[searchQueryLength + 1] =
'*';
2095 searchQuery[searchQueryLength + 2] =
'\0';
2097 drfs_iterator_win32* pIterator = (drfs_iterator_win32*)malloc(
sizeof(*pIterator) + searchQueryLength);
2098 if (pIterator ==
NULL) {
2102 ZeroMemory(pIterator,
sizeof(*pIterator));
2104 pIterator->hFind = FindFirstFileA(searchQuery, &pIterator->ffd);
2105 if (pIterator->hFind == INVALID_HANDLE_VALUE) {
2110 strcpy_s(pIterator->directoryPath, searchQueryLength + 1, absolutePath);
2114 static void drfs_end_native_iteration(
drfs_handle iterator)
2116 drfs_iterator_win32* pIterator = (drfs_iterator_win32*)iterator;
2117 assert(pIterator !=
NULL);
2119 if (pIterator->hFind) {
2120 FindClose(pIterator->hFind);
2128 drfs_iterator_win32* pIterator = (drfs_iterator_win32*)iterator;
2129 assert(pIterator !=
NULL);
2131 if (pIterator->hFind != INVALID_HANDLE_VALUE && pIterator->hFind !=
NULL)
2134 while (strcmp(pIterator->ffd.cFileName,
".") == 0 || strcmp(pIterator->ffd.cFileName,
"..") == 0) {
2135 if (FindNextFileA(pIterator->hFind, &pIterator->ffd) == 0) {
2146 ULARGE_INTEGER liSize;
2147 liSize.LowPart = pIterator->ffd.nFileSizeLow;
2148 liSize.HighPart = pIterator->ffd.nFileSizeHigh;
2151 ULARGE_INTEGER liTime;
2152 liTime.LowPart = pIterator->ffd.ftLastWriteTime.dwLowDateTime;
2153 liTime.HighPart = pIterator->ffd.ftLastWriteTime.dwHighDateTime;
2157 if ((pIterator->ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
2160 if ((pIterator->ffd.dwFileAttributes & FILE_ATTRIBUTE_READONLY) != 0) {
2165 if (!FindNextFileA(pIterator->hFind, &pIterator->ffd)) {
2166 FindClose(pIterator->hFind);
2167 pIterator->hFind =
NULL;
2175 #endif //DR_FS_USE_WIN32
2178 #ifdef DR_FS_USE_STDIO
2180 #include <sys/stat.h>
2181 #include <sys/types.h>
2188 #include <sys/sendfile.h>
2191 #define DRFS_HANDLE_TO_FD(file) ((int)((size_t)file) - 1)
2192 #define DRFS_FD_TO_HANDLE(fd) ((drfs_handle)(size_t)(fd + 1))
2217 static int drfs__open_fd(
const char* absolutePath,
int flags)
2219 return open64(absolutePath, flags, 0666);
2222 static int drfs__stat64(
const char* filename,
struct stat64* st)
2224 return stat64(filename, st);
2227 static int drfs__fstat64(
int fd,
struct stat64* st)
2229 return fstat64(fd, st);
2232 static int drfs__mode_is_dir(
int mode)
2234 return S_ISDIR(mode);
2237 static int drfs__mode_has_write_permission(
int mode)
2239 return (mode & S_IWUSR) != 0;
2243 static drfs_result drfs_open_native_file(
const char* absolutePath,
unsigned int accessMode,
drfs_handle* pHandleOut)
2245 assert(absolutePath !=
NULL);
2246 assert(pHandleOut !=
NULL);
2273 int fd = drfs__open_fd(absolutePath, flags);
2281 drfs_drpath_copy_base_path(absolutePath, dirAbsolutePath,
sizeof(dirAbsolutePath));
2283 if (!drfs_is_native_directory(dirAbsolutePath) && drfs_mkdir_recursive_native(dirAbsolutePath)) {
2284 fd = drfs__open_fd(absolutePath, flags);
2290 return drfs__errno_to_result();
2293 *pHandleOut = DRFS_FD_TO_HANDLE(fd);
2297 static void drfs_close_native_file(
drfs_handle file)
2299 close(DRFS_HANDLE_TO_FD(file));
2302 static dr_bool32 drfs_is_native_directory(
const char* absolutePath)
2305 if (drfs__stat64(absolutePath, &info) != 0) {
2309 return drfs__mode_is_dir(info.st_mode);
2312 static dr_bool32 drfs_is_native_file(
const char* absolutePath)
2315 if (drfs__stat64(absolutePath, &info) != 0) {
2319 return !drfs__mode_is_dir(info.st_mode);
2322 static drfs_result drfs_delete_native_file(
const char* absolutePath)
2324 if (remove(absolutePath) == 0) {
2328 return drfs__errno_to_result();
2331 static drfs_result drfs_move_native_file(
const char* absolutePathOld,
const char* absolutePathNew)
2333 if (rename(absolutePathOld, absolutePathNew) == 0) {
2337 return drfs__errno_to_result();
2340 static drfs_result drfs_mkdir_native(
const char* absolutePath)
2342 if (mkdir(absolutePath, 0777) == 0) {
2346 return drfs__errno_to_result();
2349 static drfs_result drfs_copy_native_file(
const char* absolutePathSrc,
const char* absolutePathDst,
dr_bool32 failIfExists)
2351 if (drfs_drpath_equal(absolutePathSrc, absolutePathDst)) {
2352 if (!failIfExists) {
2359 int fdSrc = drfs__open_fd(absolutePathSrc, O_RDONLY);
2361 return drfs__errno_to_result();
2364 int fdDst = drfs__open_fd(absolutePathDst, O_WRONLY | O_TRUNC | O_CREAT | ((failIfExists) ? O_EXCL : 0));
2367 return drfs__errno_to_result();
2373 if (drfs__fstat64(fdSrc, &info) == 0)
2376 ssize_t bytesRemaining = info.st_size;
2377 while (bytesRemaining > 0) {
2378 ssize_t bytesCopied = sendfile(fdDst, fdSrc,
NULL, bytesRemaining);
2379 if (bytesCopied == -1) {
2380 result = drfs__errno_to_result();
2384 bytesRemaining -= bytesCopied;
2387 char buffer[BUFSIZ];
2389 while ((bytesRead = read(fdSrc, buffer,
sizeof(buffer))) > 0) {
2390 if (write(fdDst, buffer, bytesRead) != bytesRead) {
2391 result = drfs__errno_to_result();
2399 result = drfs__errno_to_result();
2406 chmod(absolutePathDst, info.st_mode & 07777);
2411 static drfs_result drfs_read_native_file(
drfs_handle file,
void* pDataOut,
size_t bytesToRead,
size_t* pBytesReadOut)
2415 char* pDataOut8 = (
char*)pDataOut;
2418 size_t totalBytesRead = 0;
2419 while (bytesToRead > 0)
2421 ssize_t bytesRead = read(DRFS_HANDLE_TO_FD(file), pDataOut8 + totalBytesRead, (bytesToRead > SSIZE_MAX) ? SSIZE_MAX : bytesToRead);
2422 if (bytesRead == -1) {
2423 result = drfs__errno_to_result();
2427 if (bytesRead == 0) {
2431 totalBytesRead += bytesRead;
2432 bytesToRead -= bytesRead;
2435 if (pBytesReadOut) {
2436 *pBytesReadOut = totalBytesRead;
2442 static drfs_result drfs_write_native_file(
drfs_handle file,
const void* pData,
size_t bytesToWrite,
size_t* pBytesWrittenOut)
2445 const char* pDataIn8 = (
const char*)pData;
2448 size_t totalBytesWritten = 0;
2449 while (bytesToWrite > 0)
2451 ssize_t bytesWritten = write(DRFS_HANDLE_TO_FD(file), pDataIn8 + totalBytesWritten, (bytesToWrite > SSIZE_MAX) ? SSIZE_MAX : bytesToWrite);
2452 if (bytesWritten == -1) {
2453 result = drfs__errno_to_result();
2457 if (bytesWritten == 0) {
2458 result = drfs__errno_to_result();
2462 totalBytesWritten += bytesWritten;
2463 bytesToWrite -= bytesWritten;
2466 if (pBytesWrittenOut !=
NULL) {
2467 *pBytesWrittenOut = totalBytesWritten;
2475 int stdioOrigin = SEEK_CUR;
2477 stdioOrigin = SEEK_SET;
2479 stdioOrigin = SEEK_END;
2482 if (lseek64(DRFS_HANDLE_TO_FD(file), bytesToSeek, stdioOrigin) == -1) {
2483 return drfs__errno_to_result();
2491 return lseek64(DRFS_HANDLE_TO_FD(file), 0, SEEK_CUR);
2497 if (drfs__fstat64(DRFS_HANDLE_TO_FD(file), &info) != 0) {
2501 return info.st_size;
2504 static void drfs_flush_native_file(
drfs_handle file)
2512 assert(absolutePath !=
NULL);
2515 if (stat64(absolutePath, &info) != 0) {
2516 return drfs__errno_to_result();
2527 if (drfs__mode_is_dir(info.st_mode)) {
2530 if (drfs__mode_has_write_permission(info.st_mode) ==
DR_FALSE) {
2541 char directoryPath[1];
2542 } drfs_iterator_posix;
2544 static drfs_handle drfs_begin_native_iteration(
const char* absolutePath)
2546 DIR* dir = opendir(absolutePath);
2551 drfs_iterator_posix* pIterator = (drfs_iterator_posix*)malloc(
sizeof(drfs_iterator_posix) + strlen(absolutePath));
2552 if (pIterator ==
NULL) {
2556 pIterator->dir = dir;
2557 drfs__strcpy_s(pIterator->directoryPath, strlen(absolutePath) + 1, absolutePath);
2562 static void drfs_end_native_iteration(
drfs_handle iterator)
2564 drfs_iterator_posix* pIterator = (drfs_iterator_posix*)iterator;
2565 if (pIterator ==
NULL) {
2569 closedir(pIterator->dir);
2575 drfs_iterator_posix* pIterator = (drfs_iterator_posix*)iterator;
2576 if (pIterator ==
NULL || pIterator->dir ==
NULL) {
2580 struct dirent* info = readdir(pIterator->dir);
2586 while (strcmp(info->d_name,
".") == 0 || strcmp(info->d_name,
"..") == 0) {
2587 info = readdir(pIterator->dir);
2594 drfs_drpath_copy_and_append(fileAbsolutePath,
sizeof(fileAbsolutePath), pIterator->directoryPath, info->d_name);
2596 if (drfs_get_native_file_info(fileAbsolutePath, fi)) {
2602 #endif //DR_FS_USE_STDIO
2605 static dr_bool32 drfs_mkdir_recursive_native(
const char* absolutePath)
2608 runningPath[0] =
'\0';
2610 drfs_drpath_iterator iPathSeg;
2611 if (!drfs_drpath_first(absolutePath, &iPathSeg)) {
2616 if (drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), iPathSeg))
2619 while (drfs_drpath_next(&iPathSeg))
2621 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), iPathSeg)) {
2625 if (!drfs_is_native_directory(runningPath)) {
2637 while (drfs_drpath_next(&iPathSeg))
2639 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), iPathSeg)) {
2643 assert(!drfs_is_native_directory(runningPath));
2663 unsigned int accessMode;
2666 char absolutePath[1];
2668 } drfs_archive_native;
2684 static drfs_result drfs_open_archive__native__special(
const char* absolutePath,
unsigned int accessMode,
drfs_handle* pHandleOut)
2686 assert(absolutePath !=
NULL);
2687 assert(pHandleOut !=
NULL);
2691 size_t absolutePathLen = strlen(absolutePath);
2693 drfs_archive_native* pNativeArchive = (drfs_archive_native*)malloc(
sizeof(*pNativeArchive) + absolutePathLen + 1);
2694 if (pNativeArchive ==
NULL) {
2698 drfs__strcpy_s(pNativeArchive->absolutePath, absolutePathLen + 1, absolutePath);
2699 pNativeArchive->accessMode = accessMode;
2705 static void drfs_close_archive__native(
drfs_handle archive)
2713 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2714 assert(pNativeArchive !=
NULL);
2717 if (!drfs_drpath_copy_and_append(absolutePath,
sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) {
2722 memset(fi, 0,
sizeof(*fi));
2725 return drfs_get_native_file_info(absolutePath, fi);
2730 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2731 assert(pNativeArchive !=
NULL);
2734 if (!drfs_drpath_copy_and_append(absolutePath,
sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) {
2738 return drfs_begin_native_iteration(absolutePath);
2744 assert(archive !=
NULL);
2745 assert(iterator !=
NULL);
2747 drfs_end_native_iteration(iterator);
2753 assert(archive !=
NULL);
2754 assert(iterator !=
NULL);
2756 return drfs_next_native_iteration(iterator, fi);
2761 assert(relativePath !=
NULL);
2763 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2764 assert(pNativeArchive !=
NULL);
2767 if (!drfs_drpath_copy_and_append(absolutePath,
sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) {
2771 return drfs_delete_native_file(absolutePath);
2774 static drfs_result drfs_move_file__native(
drfs_handle archive,
const char* relativePathOld,
const char* relativePathNew)
2776 assert(relativePathOld !=
NULL);
2777 assert(relativePathNew !=
NULL);
2779 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2780 assert(pNativeArchive !=
NULL);
2783 if (!drfs_drpath_copy_and_append(absolutePathOld,
sizeof(absolutePathOld), pNativeArchive->absolutePath, relativePathOld)) {
2788 if (!drfs_drpath_copy_and_append(absolutePathNew,
sizeof(absolutePathNew), pNativeArchive->absolutePath, relativePathNew)) {
2792 return drfs_move_native_file(absolutePathOld, absolutePathNew);
2797 assert(relativePath !=
NULL);
2799 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2800 assert(pNativeArchive !=
NULL);
2803 if (!drfs_drpath_copy_and_append(absolutePath,
sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) {
2807 return drfs_mkdir_native(absolutePath);
2812 assert(relativePathSrc !=
NULL);
2813 assert(relativePathDst !=
NULL);
2815 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2816 assert(pNativeArchive !=
NULL);
2819 if (!drfs_drpath_copy_and_append(absolutePathSrc,
sizeof(absolutePathSrc), pNativeArchive->absolutePath, relativePathSrc)) {
2824 if (!drfs_drpath_copy_and_append(absolutePathDst,
sizeof(absolutePathDst), pNativeArchive->absolutePath, relativePathDst)) {
2828 return drfs_copy_native_file(absolutePathSrc, absolutePathDst, failIfExists);
2833 assert(archive !=
NULL);
2834 assert(relativePath !=
NULL);
2836 drfs_archive_native* pNativeArchive = (drfs_archive_native*)archive;
2837 assert(pNativeArchive !=
NULL);
2840 if (drfs_drpath_copy_and_append(absolutePath,
sizeof(absolutePath), pNativeArchive->absolutePath, relativePath)) {
2841 return drfs_open_native_file(absolutePath, accessMode, pHandleOut);
2850 assert(archive !=
NULL);
2851 assert(file !=
NULL);
2853 drfs_close_native_file(file);
2859 assert(archive !=
NULL);
2860 assert(file !=
NULL);
2862 return drfs_read_native_file(file, pDataOut, bytesToRead, pBytesReadOut);
2868 assert(archive !=
NULL);
2869 assert(file !=
NULL);
2871 return drfs_write_native_file(file, pData, bytesToWrite, pBytesWrittenOut);
2877 assert(archive !=
NULL);
2878 assert(file !=
NULL);
2880 return drfs_seek_native_file(file, bytesToSeek, origin);
2886 assert(archive !=
NULL);
2887 assert(file !=
NULL);
2889 return drfs_tell_native_file(file);
2895 assert(archive !=
NULL);
2896 assert(file !=
NULL);
2898 return drfs_get_native_file_size(file);
2904 assert(archive !=
NULL);
2905 assert(file !=
NULL);
2907 drfs_flush_native_file(file);
2914 if (pContext ==
NULL || extension ==
NULL || extension[0] ==
'\0') {
2922 if (pCallbacksOut) {
2934 static void drfs_recursively_claim_ownership_or_parent_archive(
drfs_archive* pArchive)
2936 if (pArchive ==
NULL) {
2940 pArchive->flags |= DR_FS_OWNS_PARENT_ARCHIVE;
2941 drfs_recursively_claim_ownership_or_parent_archive(pArchive->pParentArchive);
2947 assert(pContext !=
NULL);
2948 assert(ppArchive !=
NULL);
2949 assert(absolutePath !=
NULL);
2954 drfs_result result = drfs_open_archive__native__special(absolutePath, accessMode, &internalArchiveHandle);
2960 if (pArchive ==
NULL) {
2961 drfs_close_archive__native(internalArchiveHandle);
2965 pArchive->pContext = pContext;
2966 pArchive->pParentArchive =
NULL;
2967 pArchive->pFile =
NULL;
2968 pArchive->internalArchiveHandle = internalArchiveHandle;
2969 pArchive->flags = 0;
2970 pArchive->callbacks.is_valid_extension =
NULL;
2971 pArchive->callbacks.open_archive = drfs_open_archive__native;
2972 pArchive->callbacks.close_archive = drfs_close_archive__native;
2973 pArchive->callbacks.get_file_info = drfs_get_file_info__native;
2974 pArchive->callbacks.begin_iteration = drfs_begin_iteration__native;
2975 pArchive->callbacks.end_iteration = drfs_end_iteration__native;
2976 pArchive->callbacks.next_iteration = drfs_next_iteration__native;
2977 pArchive->callbacks.delete_file = drfs_delete_file__native;
2978 pArchive->callbacks.create_directory = drfs_create_directory__native;
2979 pArchive->callbacks.move_file = drfs_move_file__native;
2980 pArchive->callbacks.copy_file = drfs_copy_file__native;
2981 pArchive->callbacks.open_file = drfs_open_file__native;
2982 pArchive->callbacks.close_file = drfs_close_file__native;
2983 pArchive->callbacks.read_file = drfs_read_file__native;
2984 pArchive->callbacks.write_file = drfs_write_file__native;
2985 pArchive->callbacks.seek_file = drfs_seek_file__native;
2986 pArchive->callbacks.tell_file = drfs_tell_file__native;
2987 pArchive->callbacks.file_size = drfs_file_size__native;
2988 pArchive->callbacks.flush_file = drfs_flush__native;
2989 drfs__strcpy_s(pArchive->absolutePath,
sizeof(pArchive->absolutePath), absolutePath);
2991 *ppArchive = pArchive;
2998 assert(pParentArchive !=
NULL);
2999 assert(pArchiveFile !=
NULL);
3000 assert(pBackEndCallbacks !=
NULL);
3001 assert(ppArchiveOut !=
NULL);
3003 *ppArchiveOut =
NULL;
3016 if (pArchive ==
NULL) {
3021 pArchive->pContext = pParentArchive->pContext;
3022 pArchive->pParentArchive = pParentArchive;
3023 pArchive->pFile = pArchiveFile;
3024 pArchive->internalArchiveHandle = internalArchiveHandle;
3025 pArchive->flags = 0;
3026 pArchive->callbacks = *pBackEndCallbacks;
3027 drfs_drpath_copy_and_append(pArchive->absolutePath,
sizeof(pArchive->absolutePath), pParentArchive->absolutePath, relativePath);
3029 *ppArchiveOut = pArchive;
3036 assert(pParentArchive !=
NULL);
3037 assert(ppArchiveOut !=
NULL);
3038 assert(relativePath !=
NULL);
3040 *ppArchiveOut =
NULL;
3043 if (!drfs_find_backend_by_extension(pParentArchive->pContext, drfs_drpath_extension(relativePath), &backendCallbacks)) {
3054 result = drfs_open_non_native_archive(pParentArchive, pArchiveFile, &backendCallbacks, relativePath, accessMode, &pArchive);
3055 if (pArchive ==
NULL) {
3059 *ppArchiveOut = pArchive;
3065 static drfs_result drfs_open_owner_archive_recursively_from_verbose_path(
drfs_archive* pParentArchive,
const char* relativePath,
unsigned int accessMode,
char* relativePathOut,
size_t relativePathOutSize,
drfs_archive** ppArchiveOut)
3067 assert(pParentArchive !=
NULL);
3068 assert(relativePath !=
NULL);
3069 assert(ppArchiveOut !=
NULL);
3071 *ppArchiveOut =
NULL;
3073 if (pParentArchive->callbacks.get_file_info ==
NULL) {
3078 if (pParentArchive->callbacks.get_file_info(pParentArchive->internalArchiveHandle, relativePath, &fi) ==
drfs_success)
3081 drfs__strcpy_s(relativePathOut, relativePathOutSize, relativePath);
3082 *ppArchiveOut = pParentArchive;
3088 runningPath[0] =
'\0';
3090 drfs_drpath_iterator segment;
3091 if (drfs_drpath_first(relativePath, &segment))
3095 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), segment)) {
3099 if (pParentArchive->callbacks.get_file_info(pParentArchive->internalArchiveHandle, runningPath, &fi) ==
drfs_success)
3105 if (drfs_find_backend_by_extension(pParentArchive->pContext, drfs_drpath_extension(runningPath), &backendCallbacks))
3109 if (pNextArchiveFile ==
NULL) {
3114 drfs_open_non_native_archive(pParentArchive, pNextArchiveFile, &backendCallbacks, runningPath, accessMode, &pNextArchive);
3115 if (pNextArchive ==
NULL) {
3121 drfs_drpath_iterator nextsegment = segment;
3122 if (drfs_drpath_next(&nextsegment))
3125 drfs_open_owner_archive_recursively_from_verbose_path(pNextArchive, nextsegment.path + nextsegment.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive);
3126 if (pOwnerArchive ==
NULL) {
3131 *ppArchiveOut = pOwnerArchive;
3143 }
while (drfs_drpath_next(&segment));
3148 drfs__strcpy_s(relativePathOut, relativePathOutSize, relativePath);
3149 *ppArchiveOut = pParentArchive;
3155 static drfs_result drfs_open_owner_archive_from_absolute_path(
drfs_context* pContext,
const char* absolutePath,
unsigned int accessMode,
char* relativePathOut,
size_t relativePathOutSize,
drfs_archive** ppArchiveOut)
3157 assert(pContext !=
NULL);
3158 assert(absolutePath !=
NULL);
3159 assert(ppArchiveOut !=
NULL);
3161 *ppArchiveOut =
NULL;
3167 runningPath[0] =
'\0';
3169 if (absolutePath[0] ==
'/') {
3170 runningPath[0] =
'/';
3171 runningPath[1] =
'\0';
3174 drfs_drpath_iterator segment;
3175 if (drfs_drpath_first(absolutePath, &segment))
3179 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), segment)) {
3183 if (!drfs_is_native_directory(runningPath))
3186 drfs_drpath_copy_base_path(runningPath, dirAbsolutePath,
sizeof(dirAbsolutePath));
3189 drfs_result result = drfs_open_native_archive(pContext, dirAbsolutePath, accessMode, &pNativeArchive);
3197 if (drfs_find_backend_by_extension(pContext, drfs_drpath_extension(runningPath), &backendCallbacks))
3202 result = drfs_open_owner_archive_recursively_from_verbose_path(pNativeArchive, segment.path + segment.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pArchive);
3203 if (pArchive ==
NULL) {
3208 *ppArchiveOut = pArchive;
3213 drfs__strcpy_s(relativePathOut, relativePathOutSize, segment.path + segment.segment.offset);
3214 *ppArchiveOut = pNativeArchive;
3219 }
while (drfs_drpath_next(&segment));
3226 static drfs_result drfs_open_owner_archive_recursively_from_relative_path(
drfs_archive* pParentArchive,
const char* rootSearchPath,
const char* relativePath,
unsigned int accessMode,
char* relativePathOut,
size_t relativePathOutSize,
drfs_archive** ppArchiveOut)
3228 assert(pParentArchive !=
NULL);
3229 assert(relativePath !=
NULL);
3230 assert(ppArchiveOut !=
NULL);
3232 *ppArchiveOut =
NULL;
3234 if (pParentArchive->callbacks.get_file_info ==
NULL) {
3240 if (pParentArchive->callbacks.get_file_info(pParentArchive->internalArchiveHandle, relativePath, &fi) ==
drfs_success)
3243 drfs__strcpy_s(relativePathOut, relativePathOutSize, relativePath);
3244 *ppArchiveOut = pParentArchive;
3252 drfs__strcpy_s(runningPath,
sizeof(runningPath), rootSearchPath);
3255 drfs_drpath_iterator pathSeg0;
3256 drfs_drpath_iterator pathSeg1;
3257 dr_bool32 isSeg0Valid = drfs_drpath_first(rootSearchPath, &pathSeg0);
3258 dr_bool32 isSeg1Valid = drfs_drpath_first(relativePath, &pathSeg1);
3259 while (isSeg0Valid && isSeg1Valid) {
3260 isSeg0Valid = drfs_drpath_next(&pathSeg0);
3261 isSeg1Valid = drfs_drpath_next(&pathSeg1);
3264 relativePath = pathSeg1.path + pathSeg1.segment.offset;
3273 drfs_drpath_iterator pathseg;
3274 if (drfs_drpath_first(relativePath, &pathseg))
3279 drfs__strcpy_s(runningPathBase,
sizeof(runningPathBase), runningPath);
3281 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), pathseg)) {
3286 drfs_open_non_native_archive_from_path(pParentArchive, runningPath, accessMode, &pNextArchive);
3287 if (pNextArchive !=
NULL)
3290 drfs_drpath_iterator nextseg = pathseg;
3291 if (!drfs_drpath_next(&nextseg)) {
3298 drfs_open_owner_archive_recursively_from_relative_path(pNextArchive,
"", nextseg.path + nextseg.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive);
3299 if (pOwnerArchive ==
NULL) {
3304 *ppArchiveOut = pOwnerArchive;
3310 if (pParentArchive->callbacks.begin_iteration ==
NULL || pParentArchive->callbacks.next_iteration ==
NULL || pParentArchive->callbacks.end_iteration ==
NULL) {
3314 drfs_handle iterator = pParentArchive->callbacks.begin_iteration(pParentArchive->internalArchiveHandle, runningPathBase);
3315 if (iterator ==
NULL) {
3319 while (pParentArchive->callbacks.next_iteration(pParentArchive->internalArchiveHandle, iterator, &fi))
3324 drfs_open_non_native_archive_from_path(pParentArchive, fi.
absolutePath, accessMode, &pNextArchive);
3325 if (pNextArchive !=
NULL)
3329 drfs_open_owner_archive_recursively_from_relative_path(pNextArchive,
"", pathseg.path + pathseg.segment.offset, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive);
3330 if (pOwnerArchive !=
NULL) {
3331 pParentArchive->callbacks.end_iteration(pParentArchive->internalArchiveHandle, iterator);
3332 *ppArchiveOut = pOwnerArchive;
3341 pParentArchive->callbacks.end_iteration(pParentArchive->internalArchiveHandle, iterator);
3344 }
while (drfs_drpath_next(&pathseg));
3353 static drfs_result drfs_open_owner_archive_from_relative_path(
drfs_context* pContext,
const char* absoluteBasePath,
const char* relativePath,
unsigned int accessMode,
char* relativePathOut,
size_t relativePathOutSize,
drfs_archive** ppArchiveOut)
3355 assert(pContext !=
NULL);
3356 assert(absoluteBasePath !=
NULL);
3357 assert(relativePath !=
NULL);
3358 assert(drfs_drpath_is_absolute(absoluteBasePath));
3359 assert(ppArchiveOut !=
NULL);
3361 *ppArchiveOut =
NULL;
3365 relativeBasePath[0] =
'\0';
3369 if (drfs_is_native_directory(absoluteBasePath))
3371 drfs_result result = drfs_open_native_archive(pContext, absoluteBasePath, accessMode, &pBaseArchive);
3376 if (drfs__strcpy_s(adjustedRelativePath,
sizeof(adjustedRelativePath), relativePath) != 0) {
3388 if (!drfs_drpath_copy_and_append(adjustedRelativePath,
sizeof(adjustedRelativePath), relativeBasePath, relativePath)) {
3397 drfs_result result = drfs_open_owner_archive_recursively_from_relative_path(pBaseArchive, relativeBasePath, adjustedRelativePath, accessMode, relativePathOut, relativePathOutSize, &pOwnerArchive);
3398 if (pOwnerArchive ==
NULL) {
3402 drfs_recursively_claim_ownership_or_parent_archive(pOwnerArchive);
3404 *ppArchiveOut = pOwnerArchive;
3410 static drfs_result drfs_open_archive_from_relative_path(
drfs_context* pContext,
const char* absoluteBasePath,
const char* relativePath,
unsigned int accessMode,
drfs_archive** ppArchiveOut)
3412 assert(pContext !=
NULL);
3413 assert(absoluteBasePath !=
NULL);
3414 assert(relativePath !=
NULL);
3415 assert(drfs_drpath_is_absolute(absoluteBasePath));
3416 assert(ppArchiveOut !=
NULL);
3418 *ppArchiveOut =
NULL;
3422 relativeBasePath[0] =
'\0';
3426 if (drfs_is_native_directory(absoluteBasePath))
3428 drfs_result result = drfs_open_native_archive(pContext, absoluteBasePath, accessMode, &pBaseArchive);
3433 if (drfs__strcpy_s(adjustedRelativePath,
sizeof(adjustedRelativePath), relativePath) != 0) {
3445 if (!drfs_drpath_copy_and_append(adjustedRelativePath,
sizeof(adjustedRelativePath), relativeBasePath, relativePath)) {
3455 drfs_result result = drfs_open_non_native_archive_from_path(pBaseArchive, adjustedRelativePath, accessMode, &pArchive);
3456 if (pArchive ==
NULL)
3461 result = drfs_open_owner_archive_recursively_from_relative_path(pBaseArchive, relativeBasePath, adjustedRelativePath, accessMode, archiveRelativePath,
sizeof(archiveRelativePath), &pOwnerArchive);
3462 if (pOwnerArchive !=
NULL)
3464 drfs_recursively_claim_ownership_or_parent_archive(pOwnerArchive);
3466 result = drfs_open_non_native_archive_from_path(pOwnerArchive, archiveRelativePath, accessMode, &pArchive);
3467 if (pArchive ==
NULL) {
3474 if (pArchive ==
NULL) {
3479 *ppArchiveOut = pArchive;
3485 #ifndef DR_FS_NO_ZIP
3487 static void drfs_register_zip_backend(
drfs_context* pContext);
3490 #ifndef DR_FS_NO_PAK
3492 static void drfs_register_pak_backend(
drfs_context* pContext);
3495 #ifndef DR_FS_NO_MTL
3497 static void drfs_register_mtl_backend(
drfs_context* pContext);
3507 memset(pContext, 0,
sizeof(*pContext));
3515 #ifndef DR_FS_NO_ZIP
3516 drfs_register_zip_backend(pContext);
3519 #ifndef DR_FS_NO_PAK
3520 drfs_register_pak_backend(pContext);
3523 #ifndef DR_FS_NO_MTL
3524 drfs_register_mtl_backend(pContext);
3543 if (pContext ==
NULL) {
3557 if (pContext ==
NULL) {
3568 if (pContext ==
NULL) {
3578 if (pContext ==
NULL) {
3582 drfs_basedirs_insert(&pContext->
baseDirectories, absolutePath, index);
3587 if (pContext ==
NULL) {
3596 if (pContext ==
NULL) {
3611 if (pContext ==
NULL) {
3620 if (pContext ==
NULL) {
3629 if (pContext ==
NULL) {
3648 if (pContext ==
NULL) {
3652 if (absolutePath ==
NULL) {
3661 if (pContext ==
NULL || absolutePathOut ==
NULL || absolutePathOutSize == 0) {
3665 return drfs__strcpy_s(absolutePathOut, absolutePathOutSize, pContext->
writeBaseDirectory) == 0;
3670 if (pContext ==
NULL) {
3679 if (pContext ==
NULL) {
3688 if (pContext ==
NULL) {
3700 if (ppArchiveOut ==
NULL) {
3704 *ppArchiveOut =
NULL;
3706 if (pContext ==
NULL || absoluteOrRelativePath ==
NULL) {
3710 if (drfs_drpath_is_absolute(absoluteOrRelativePath))
3712 if (drfs_is_native_directory(absoluteOrRelativePath))
3715 return drfs_open_native_archive(pContext, absoluteOrRelativePath, accessMode, ppArchiveOut);
3728 result = drfs_open_non_native_archive_from_path(pOwnerArchive, relativePath, accessMode, &pArchive);
3734 drfs_recursively_claim_ownership_or_parent_archive(pArchive);
3736 *ppArchiveOut = pArchive;
3749 drfs_recursively_claim_ownership_or_parent_archive(pArchive);
3751 *ppArchiveOut = pArchive;
3762 if (ppArchiveOut ==
NULL) {
3766 *ppArchiveOut =
NULL;
3768 if (pContext ==
NULL || absoluteOrRelativePath ==
NULL) {
3772 if (drfs_drpath_is_absolute(absoluteOrRelativePath))
3774 if (drfs_is_native_file(absoluteOrRelativePath) || drfs_is_native_directory(absoluteOrRelativePath))
3778 drfs_drpath_copy_base_path(absoluteOrRelativePath, dirAbsolutePath,
sizeof(dirAbsolutePath));
3786 if (relativePathOut) {
3787 if (drfs__strcpy_s(relativePathOut, relativePathOutSize, drfs_drpath_file_name(absoluteOrRelativePath)) != 0) {
3793 *ppArchiveOut = pArchive;
3800 drfs_result result = drfs_open_owner_archive_from_absolute_path(pContext, absoluteOrRelativePath, accessMode, relativePathOut, relativePathOutSize, &pArchive);
3801 if (pArchive ==
NULL) {
3805 drfs_recursively_claim_ownership_or_parent_archive(pArchive);
3807 *ppArchiveOut = pArchive;
3818 drfs_result result = drfs_open_owner_archive_from_relative_path(pContext,
drfs_get_base_directory_by_index(pContext, iBaseDir), absoluteOrRelativePath, accessMode, relativePathOut, relativePathOutSize, &pArchive);
3820 drfs_recursively_claim_ownership_or_parent_archive(pArchive);
3822 *ppArchiveOut = pArchive;
3833 if (pArchive ==
NULL) {
3838 if (pArchive->callbacks.close_archive) {
3839 pArchive->callbacks.close_archive(pArchive->internalArchiveHandle);
3845 if ((pArchive->flags & DR_FS_OWNS_PARENT_ARCHIVE) != 0) {
3854 if (ppFileOut ==
NULL) {
3860 if (pArchive ==
NULL || relativePath ==
NULL || pArchive->callbacks.open_file ==
NULL) {
3865 drfs_result result = pArchive->callbacks.open_file(pArchive->internalArchiveHandle, relativePath, accessMode, &internalFileHandle);
3872 if (pFile ==
NULL) {
3873 pArchive->callbacks.close_file(pArchive->internalArchiveHandle, internalFileHandle);
3877 pFile->pArchive = pArchive;
3878 pFile->internalFileHandle = internalFileHandle;
3883 #ifdef DR_FS_WIN32_USE_EVENT_MUTEX
3886 InitializeCriticalSection(&pFile->lock);
3889 if (pthread_mutex_init(&pFile->lock,
NULL) != 0) {
3902 if (ppFile ==
NULL) {
3909 if (pContext ==
NULL || absoluteOrRelativePath ==
NULL) {
3915 if (drfs_validate_write_path(pContext, absoluteOrRelativePath, absolutePathForWriteMode,
sizeof(absolutePathForWriteMode))) {
3916 absoluteOrRelativePath = absolutePathForWriteMode;
3937 pFile->flags |= DR_FS_OWNS_PARENT_ARCHIVE;
3949 if (pFile->pArchive !=
NULL && pFile->pArchive->callbacks.close_file) {
3950 pFile->pArchive->callbacks.close_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle);
3951 pFile->internalFileHandle =
NULL;
3954 if ((pFile->flags & DR_FS_OWNS_PARENT_ARCHIVE) != 0) {
3956 pFile->pArchive =
NULL;
3964 #ifdef DR_FS_WIN32_USE_EVENT_MUTEX
3965 CloseHandle(pFile->lock);
3967 DeleteCriticalSection(&pFile->lock);
3970 pthread_mutex_destroy(&pFile->lock);
3978 if (pFile ==
NULL || pDataOut ==
NULL || pFile->pArchive ==
NULL || pFile->pArchive->callbacks.read_file ==
NULL) {
3982 return pFile->pArchive->callbacks.read_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle, pDataOut, bytesToRead, pBytesReadOut);
3999 if (pFile ==
NULL || pData ==
NULL || pFile->pArchive ==
NULL || pFile->pArchive->callbacks.write_file ==
NULL) {
4003 return pFile->pArchive->callbacks.write_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle, pData, bytesToWrite, pBytesWrittenOut);
4020 if (pFile ==
NULL || pFile->pArchive ==
NULL || pFile->pArchive->callbacks.seek_file ==
NULL) {
4024 return pFile->pArchive->callbacks.seek_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle, bytesToSeek, origin);
4041 if (pFile ==
NULL || pFile->pArchive ==
NULL || pFile->pArchive->callbacks.tell_file ==
NULL) {
4045 return pFile->pArchive->callbacks.tell_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle);
4062 if (pFile ==
NULL || pFile->pArchive ==
NULL || pFile->pArchive->callbacks.file_size ==
NULL) {
4066 return pFile->pArchive->callbacks.file_size(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle);
4083 if (pFile ==
NULL || pFile->pArchive ==
NULL || pFile->pArchive->callbacks.flush_file ==
NULL) {
4087 pFile->pArchive->callbacks.flush_file(pFile->pArchive->internalArchiveHandle, pFile->internalFileHandle);
4093 if (pFile ==
NULL || pFile->internalFileHandle ==
NULL) {
4098 #ifdef DR_FS_WIN32_USE_EVENT_MUTEX
4099 WaitForSingleObject(pFile->lock, INFINITE);
4101 EnterCriticalSection(&pFile->lock);
4104 pthread_mutex_lock(&pFile->lock);
4112 if (pFile ==
NULL || pFile->internalFileHandle ==
NULL) {
4117 #ifdef DR_FS_WIN32_USE_EVENT_MUTEX
4118 SetEvent(pFile->lock);
4120 LeaveCriticalSection(&pFile->lock);
4123 pthread_mutex_unlock(&pFile->lock);
4130 if (pContext ==
NULL || absoluteOrRelativePath ==
NULL) {
4142 if (pOwnerArchive->callbacks.get_file_info) {
4143 result = pOwnerArchive->callbacks.get_file_info(pOwnerArchive->internalArchiveHandle, relativePath, fi);
4147 drfs_drpath_copy_and_append(fi->
absolutePath,
sizeof(fi->
absolutePath), pOwnerArchive->absolutePath, relativePath);
4158 memset(pIteratorOut, 0,
sizeof(*pIteratorOut));
4160 if (pContext ==
NULL || absoluteOrRelativePath ==
NULL) {
4172 relativePath[0] =
'\0';
4183 if (pIteratorOut->
pArchive->callbacks.begin_iteration) {
4204 if (pIterator ==
NULL) {
4208 memset(&pIterator->
info, 0,
sizeof(pIterator->
info));
4215 if (pIterator->
pArchive->callbacks.next_iteration) {
4222 drfs__strcpy_s(relativePath,
sizeof(relativePath), pIterator->
info.
absolutePath);
4231 if (pContext ==
NULL || pIterator ==
NULL) {
4240 memset(pIterator, 0,
sizeof(*pIterator));
4245 if (pContext ==
NULL || path ==
NULL) {
4250 if (!drfs_validate_write_path(pContext, path, absolutePath,
sizeof(absolutePath))) {
4263 if (pArchive->callbacks.delete_file) {
4264 result = pArchive->callbacks.delete_file(pArchive->internalArchiveHandle, relativePath);
4273 if (pContext ==
NULL || path ==
NULL) {
4278 if (!drfs_validate_write_path(pContext, path, absolutePath,
sizeof(absolutePath))) {
4290 if (pArchive->callbacks.create_directory) {
4291 result = pArchive->callbacks.create_directory(pArchive->internalArchiveHandle, relativePath);
4302 if (pContext ==
NULL || pathOld ==
NULL || pathNew ==
NULL) {
4308 if (drfs_validate_write_path(pContext, pathOld, absolutePathOld,
sizeof(absolutePathOld))) {
4309 pathOld = absolutePathOld;
4315 if (drfs_validate_write_path(pContext, pathNew, absolutePathNew,
sizeof(absolutePathNew))) {
4316 pathNew = absolutePathNew;
4328 if (pArchiveOld !=
NULL)
4333 if (pArchiveNew !=
NULL)
4335 dr_bool32 areBothArchivesNative = (pArchiveOld->callbacks.move_file == pArchiveNew->callbacks.move_file && pArchiveNew->callbacks.move_file == drfs_move_file__native);
4336 if (areBothArchivesNative)
4338 result = drfs_move_native_file(absolutePathOld, absolutePathNew);
4342 if (drfs_drpath_equal(pArchiveOld->absolutePath, pArchiveNew->absolutePath) && pArchiveOld->callbacks.move_file) {
4343 result = pArchiveOld->callbacks.move_file(pArchiveOld, relativePathOld, relativePathNew);
4361 if (pContext ==
NULL || srcPath ==
NULL || dstPath ==
NULL) {
4366 if (!drfs_validate_write_path(pContext, dstPath, dstPathAbsolute,
sizeof(dstPathAbsolute))) {
4390 if (strcmp(pSrcArchive->absolutePath, pDstArchive->absolutePath) == 0 && pDstArchive->callbacks.copy_file)
4393 result = pDstArchive->callbacks.copy_file(pDstArchive->internalArchiveHandle, srcRelativePath, dstRelativePath, failIfExists);
4397 dr_bool32 areBothArchivesNative = (pSrcArchive->callbacks.copy_file == pDstArchive->callbacks.copy_file && pDstArchive->callbacks.copy_file == drfs_copy_file__native);
4398 if (areBothArchivesNative)
4401 drfs_drpath_copy_and_append(srcPathAbsolute,
sizeof(srcPathAbsolute), pSrcArchive->absolutePath, srcPath);
4403 result = drfs_copy_native_file(srcPathAbsolute, dstPathAbsolute, failIfExists);
4408 if (failIfExists && pDstArchive->callbacks.get_file_info(pDstArchive, dstRelativePath,
NULL) ==
drfs_success)
4427 assert(pSrcFile !=
NULL);
4428 assert(pDstFile !=
NULL);
4456 return drfs_find_backend_by_extension(pContext, drfs_drpath_extension(path),
NULL);
4474 if (absolutePathOutSize > 0) absolutePathOut[0] =
'\0';
4476 if (pContext ==
NULL || relativePath ==
NULL || absolutePathOutSize == 0) {
4482 if (drfs__strcpy_s(absolutePathOut, absolutePathOutSize, fi.
absolutePath) == 0) {
4493 if (absolutePathOutSize > 0) absolutePathOut[0] =
'\0';
4495 if (pContext ==
NULL || relativePath ==
NULL || highestPriorityBasePath ==
NULL || absolutePathOutSize == 0) {
4511 if (pContext ==
NULL) {
4548 if (fileSize > SIZE_MAX)
4556 void* pData = malloc((
size_t)fileSize);
4568 if (pSizeInBytesOut !=
NULL) {
4569 *pSizeInBytesOut = 0;
4577 if (pSizeInBytesOut !=
NULL) {
4578 *pSizeInBytesOut = (size_t)fileSize;
4593 if (fileSize > SIZE_MAX)
4601 void* pData = malloc((
size_t)fileSize + 1);
4613 if (pSizeInBytesOut !=
NULL) {
4614 *pSizeInBytesOut = 0;
4622 ((
char*)pData)[fileSize] =
'\0';
4625 if (pSizeInBytesOut !=
NULL) {
4626 *pSizeInBytesOut = (size_t)fileSize;
4630 return (
char*)pData;
4685 if (pContext ==
NULL || path ==
NULL) {
4691 if (drfs_validate_write_path(pContext, path, absolutePath,
DRFS_MAX_PATH)) {
4692 path = absolutePath;
4699 runningPath[0] =
'\0';
4701 drfs_drpath_iterator iPathSeg;
4702 if (!drfs_drpath_first(absolutePath, &iPathSeg)) {
4707 if (drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), iPathSeg))
4710 while (drfs_drpath_next(&iPathSeg))
4712 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), iPathSeg)) {
4729 while (drfs_drpath_next(&iPathSeg))
4731 if (!drfs_drpath_append_iterator(runningPath,
sizeof(runningPath), iPathSeg)) {
4765 #ifndef DR_FS_NO_ZIP
4767 #if defined(_MSC_VER)
4768 #pragma warning(push)
4769 #pragma warning(disable:4334)
4771 #if defined(__GNUC__)
4772 #pragma GCC diagnostic push
4773 #pragma GCC diagnostic ignored "-Wunused-macros"
4774 #pragma GCC diagnostic ignored "-Wcast-align"
4775 #pragma GCC diagnostic ignored "-Wextra"
4777 #if __GNUC__ >= 6 && !defined __clang__
4778 #pragma GCC diagnostic ignored "-Wmisleading-indentation"
4782 #ifndef DRFS_MINIZ_HEADER_INCLUDED
4783 #define DRFS_MINIZ_HEADER_INCLUDED
4793 #if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
4795 #define DRFS_MINIZ_NO_TIME
4798 #if !defined(DRFS_MINIZ_NO_TIME) && !defined(DRFS_MINIZ_NO_ARCHIVE_APIS)
4802 #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
4804 #define DRFS_MINIZ_X86_OR_X64_CPU 1
4807 #if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || DRFS_MINIZ_X86_OR_X64_CPU
4809 #define DRFS_MINIZ_LITTLE_ENDIAN 1
4812 #if DRFS_MINIZ_X86_OR_X64_CPU
4814 #define DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
4817 #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
4819 #define DRFS_MINIZ_HAS_64BIT_REGISTERS 1
4829 typedef unsigned long drfs_mz_ulong;
4832 void drfs_mz_free(
void *p);
4834 #define DRFS_MZ_ADLER32_INIT (1)
4836 drfs_mz_ulong drfs_mz_adler32(drfs_mz_ulong adler,
const unsigned char *ptr,
size_t buf_len);
4838 #define DRFS_MZ_CRC32_INIT (0)
4840 drfs_mz_ulong drfs_mz_crc32(drfs_mz_ulong crc,
const unsigned char *ptr,
size_t buf_len);
4843 enum { DRFS_MZ_DEFAULT_STRATEGY = 0, DRFS_MZ_FILTERED = 1, DRFS_MZ_HUFFMAN_ONLY = 2, DRFS_MZ_RLE = 3, DRFS_MZ_FIXED = 4 };
4846 #define DRFS_MZ_DEFLATED 8
4850 typedef void *(*drfs_mz_alloc_func)(
void *opaque,
size_t items,
size_t size);
4851 typedef void (*drfs_mz_free_func)(
void *opaque,
void *address);
4852 typedef void *(*drfs_mz_realloc_func)(
void *opaque,
void *address,
size_t items,
size_t size);
4856 typedef unsigned char drfs_mz_uint8;
4857 typedef signed short drfs_mz_int16;
4858 typedef unsigned short drfs_drfs_mz_uint16;
4859 typedef unsigned int drfs_drfs_mz_uint32;
4860 typedef unsigned int drfs_mz_uint;
4861 typedef long long drfs_mz_int64;
4862 typedef unsigned long long drfs_mz_uint64;
4863 typedef int drfs_mz_bool;
4865 #define DRFS_MZ_FALSE (0)
4866 #define DRFS_MZ_TRUE (1)
4870 #define DRFS_MZ_MACRO_END while (0, 0)
4872 #define DRFS_MZ_MACRO_END while (0)
4877 #ifndef DRFS_MINIZ_NO_ARCHIVE_APIS
4881 DRFS_MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024,
4882 DRFS_MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260,
4883 DRFS_MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256
4888 drfs_drfs_mz_uint32 m_file_index;
4889 drfs_drfs_mz_uint32 m_central_dir_ofs;
4890 drfs_drfs_mz_uint16 m_version_made_by;
4891 drfs_drfs_mz_uint16 m_version_needed;
4892 drfs_drfs_mz_uint16 m_bit_flag;
4893 drfs_drfs_mz_uint16 m_method;
4894 #ifndef DRFS_MINIZ_NO_TIME
4897 drfs_drfs_mz_uint32 m_crc32;
4898 drfs_mz_uint64 m_comp_size;
4899 drfs_mz_uint64 m_uncomp_size;
4900 drfs_drfs_mz_uint16 m_internal_attr;
4901 drfs_drfs_mz_uint32 m_external_attr;
4902 drfs_mz_uint64 m_local_header_ofs;
4903 drfs_drfs_mz_uint32 m_comment_size;
4904 char m_filename[DRFS_MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
4905 char m_comment[DRFS_MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
4906 } drfs_drfs_mz_zip_archive_file_stat;
4908 typedef size_t (*drfs_mz_file_read_func)(
void *pOpaque, drfs_mz_uint64 file_ofs,
void *pBuf,
size_t n);
4909 typedef size_t (*drfs_mz_file_write_func)(
void *pOpaque, drfs_mz_uint64 file_ofs,
const void *pBuf,
size_t n);
4911 struct drfs_mz_zip_internal_state_tag;
4912 typedef struct drfs_mz_zip_internal_state_tag drfs_mz_zip_internal_state;
4916 DRFS_MZ_ZIP_MODE_INVALID = 0,
4917 DRFS_MZ_ZIP_MODE_READING = 1,
4918 DRFS_MZ_ZIP_MODE_WRITING = 2,
4919 DRFS_MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
4922 typedef struct drfs_mz_zip_archive_tag
4924 drfs_mz_uint64 m_archive_size;
4925 drfs_mz_uint64 m_central_directory_file_ofs;
4926 drfs_mz_uint m_total_files;
4927 drfs_mz_zip_mode m_zip_mode;
4929 drfs_mz_uint m_file_offset_alignment;
4931 drfs_mz_alloc_func m_pAlloc;
4932 drfs_mz_free_func m_pFree;
4933 drfs_mz_realloc_func m_pRealloc;
4934 void *m_pAlloc_opaque;
4936 drfs_mz_file_read_func m_pRead;
4937 drfs_mz_file_write_func m_pWrite;
4940 drfs_mz_zip_internal_state *m_pState;
4942 } drfs_mz_zip_archive;
4946 DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
4947 DRFS_MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
4948 DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
4949 DRFS_MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800
4950 } drfs_mz_zip_flags;
4956 drfs_mz_bool drfs_mz_zip_reader_init(drfs_mz_zip_archive *pZip, drfs_mz_uint64 size, drfs_drfs_mz_uint32 flags);
4959 drfs_mz_uint drfs_mz_zip_reader_get_num_files(drfs_mz_zip_archive *pZip);
4962 drfs_mz_bool drfs_mz_zip_reader_file_stat(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, drfs_drfs_mz_zip_archive_file_stat *pStat);
4965 drfs_mz_bool drfs_mz_zip_reader_is_file_a_directory(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index);
4969 drfs_mz_uint drfs_mz_zip_reader_get_filename(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
char *pFilename, drfs_mz_uint filename_buf_size);
4974 int drfs_mz_zip_reader_locate_file(drfs_mz_zip_archive *pZip,
const char *pName,
const char *pComment, drfs_mz_uint flags);
4977 drfs_mz_bool drfs_mz_zip_reader_extract_to_mem_no_alloc(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
void *pBuf,
size_t buf_size, drfs_mz_uint flags,
void *pUser_read_buf,
size_t user_read_buf_size);
4978 drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem_no_alloc(drfs_mz_zip_archive *pZip,
const char *pFilename,
void *pBuf,
size_t buf_size, drfs_mz_uint flags,
void *pUser_read_buf,
size_t user_read_buf_size);
4981 drfs_mz_bool drfs_mz_zip_reader_extract_to_mem(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
void *pBuf,
size_t buf_size, drfs_mz_uint flags);
4982 drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem(drfs_mz_zip_archive *pZip,
const char *pFilename,
void *pBuf,
size_t buf_size, drfs_mz_uint flags);
4985 void *drfs_mz_zip_reader_extract_to_heap(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
size_t *pSize, drfs_mz_uint flags);
4988 drfs_mz_bool drfs_mz_zip_reader_end(drfs_mz_zip_archive *pZip);
4990 #endif // #ifndef DRFS_MINIZ_NO_ARCHIVE_APIS
5001 DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
5002 DRFS_TINFL_FLAG_HAS_MORE_INPUT = 2,
5003 DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
5004 DRFS_TINFL_FLAG_COMPUTE_ADLER32 = 8
5015 void *drfs_tinfl_decompress_mem_to_heap(
const void *pSrc_buf,
size_t src_buf_len,
size_t *pOut_len,
int flags);
5019 #define DRFS_TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
5020 size_t drfs_tinfl_decompress_mem_to_mem(
void *pOut_buf,
size_t out_buf_len,
const void *pSrc_buf,
size_t src_buf_len,
int flags);
5024 typedef int (*tinfl_put_buf_func_ptr)(
const void* pBuf,
int len,
void *pUser);
5025 int drfs_tinfl_decompress_mem_to_callback(
const void *pIn_buf,
size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func,
void *pPut_buf_user,
int flags);
5027 struct drfs_tinfl_decompressor_tag;
typedef struct drfs_tinfl_decompressor_tag drfs_tinfl_decompressor;
5030 #define DRFS_TINFL_LZ_DICT_SIZE 32768
5035 DRFS_TINFL_STATUS_BAD_PARAM = -3,
5036 DRFS_TINFL_STATUS_ADLER32_MISMATCH = -2,
5037 DRFS_TINFL_STATUS_FAILED = -1,
5038 DRFS_TINFL_STATUS_DONE = 0,
5039 DRFS_TINFL_STATUS_NEEDS_MORE_INPUT = 1,
5040 DRFS_TINFL_STATUS_HAS_MORE_OUTPUT = 2
5041 } drfs_tinfl_status;
5044 #define drfs_tinfl_init(r) do { (r)->m_state = 0; } DRFS_MZ_MACRO_END
5045 #define drfs_tinfl_get_adler32(r) (r)->m_check_adler32
5049 drfs_tinfl_status drfs_tinfl_decompress(drfs_tinfl_decompressor *r,
const drfs_mz_uint8 *pIn_buf_next,
size_t *pIn_buf_size, drfs_mz_uint8 *pOut_buf_start, drfs_mz_uint8 *pOut_buf_next,
size_t *pOut_buf_size,
const drfs_drfs_mz_uint32 decomp_flags);
5054 DRFS_TINFL_MAX_HUFF_TABLES = 3, DRFS_TINFL_MAX_HUFF_SYMBOLS_0 = 288, DRFS_TINFL_MAX_HUFF_SYMBOLS_1 = 32, DRFS_TINFL_MAX_HUFF_SYMBOLS_2 = 19,
5055 DRFS_TINFL_FAST_LOOKUP_BITS = 10, DRFS_TINFL_FAST_LOOKUP_SIZE = 1 << DRFS_TINFL_FAST_LOOKUP_BITS
5060 drfs_mz_uint8 m_code_size[DRFS_TINFL_MAX_HUFF_SYMBOLS_0];
5061 drfs_mz_int16 m_look_up[DRFS_TINFL_FAST_LOOKUP_SIZE], m_tree[DRFS_TINFL_MAX_HUFF_SYMBOLS_0 * 2];
5062 } drfs_tinfl_huff_table;
5064 #if DRFS_MINIZ_HAS_64BIT_REGISTERS
5065 #define DRFS_TINFL_USE_64BIT_BITBUF 1
5068 #if DRFS_TINFL_USE_64BIT_BITBUF
5069 typedef drfs_mz_uint64 drfs_tinfl_bit_buf_t;
5070 #define DRFS_TINFL_BITBUF_SIZE (64)
5072 typedef drfs_drfs_mz_uint32 drfs_tinfl_bit_buf_t;
5073 #define DRFS_TINFL_BITBUF_SIZE (32)
5076 struct drfs_tinfl_decompressor_tag
5078 drfs_drfs_mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[DRFS_TINFL_MAX_HUFF_TABLES];
5079 drfs_tinfl_bit_buf_t m_bit_buf;
5080 size_t m_dist_from_out_buf_start;
5081 drfs_tinfl_huff_table m_tables[DRFS_TINFL_MAX_HUFF_TABLES];
5082 drfs_mz_uint8 m_raw_header[4], m_len_codes[DRFS_TINFL_MAX_HUFF_SYMBOLS_0 + DRFS_TINFL_MAX_HUFF_SYMBOLS_1 + 137];
5089 #endif // MINIZ_HEADER_INCLUDED
5093 #ifndef DRFS_MINIZ_HEADER_FILE_ONLY
5095 typedef unsigned char mz_validate_uint16[
sizeof(drfs_drfs_mz_uint16)==2 ? 1 : -1];
5096 typedef unsigned char mz_validate_uint32[
sizeof(drfs_drfs_mz_uint32)==4 ? 1 : -1];
5097 typedef unsigned char mz_validate_uint64[
sizeof(drfs_mz_uint64)==8 ? 1 : -1];
5102 #define DRFS_MZ_ASSERT(x) assert(x)
5104 #define DRFS_MZ_MALLOC(x) malloc(x)
5105 #define DRFS_MZ_FREE(x) free(x)
5106 #define DRFS_MZ_REALLOC(p, x) realloc(p, x)
5108 #define DRFS_MZ_MAX(a,b) (((a)>(b))?(a):(b))
5109 #define DRFS_MZ_MIN(a,b) (((a)<(b))?(a):(b))
5110 #define DRFS_MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
5112 #if DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES && DRFS_MINIZ_LITTLE_ENDIAN
5113 #define DRFS_MZ_READ_LE16(p) *((const drfs_drfs_mz_uint16 *)(p))
5114 #define DRFS_MZ_READ_LE32(p) *((const drfs_drfs_mz_uint32 *)(p))
5116 #define DRFS_MZ_READ_LE16(p) ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[0]) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[1]) << 8U))
5117 #define DRFS_MZ_READ_LE32(p) ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[0]) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[1]) << 8U) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[2]) << 16U) | ((drfs_drfs_mz_uint32)(((const drfs_mz_uint8 *)(p))[3]) << 24U))
5121 #define DRFS_MZ_FORCEINLINE __forceinline
5122 #elif defined(__GNUC__)
5123 #define DRFS_MZ_FORCEINLINE inline __attribute__((__always_inline__))
5125 #define DRFS_MZ_FORCEINLINE inline
5132 static void *drfs__def_alloc_func(
void *opaque,
size_t items,
size_t size) { (void)opaque, (
void)items, (void)size;
return DRFS_MZ_MALLOC(items * size); }
5133 static void drfs__def_free_func(
void *opaque,
void *address) { (void)opaque, (
void)address; DRFS_MZ_FREE(address); }
5134 static void *drfs__def_realloc_func(
void *opaque,
void *address,
size_t items,
size_t size) { (void)opaque, (
void)address, (void)items, (
void)size;
return DRFS_MZ_REALLOC(address, items * size); }
5138 drfs_mz_ulong drfs_mz_adler32(drfs_mz_ulong adler,
const unsigned char *ptr,
size_t buf_len)
5140 drfs_drfs_mz_uint32 i, s1 = (drfs_drfs_mz_uint32)(adler & 0xffff), s2 = (drfs_drfs_mz_uint32)(adler >> 16);
size_t block_len = buf_len % 5552;
5141 if (!ptr)
return DRFS_MZ_ADLER32_INIT;
5143 for (i = 0; i + 7 < block_len; i += 8, ptr += 8) {
5144 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
5145 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
5147 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
5148 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
5150 return (s2 << 16) + s1;
5154 drfs_mz_ulong drfs_mz_crc32(drfs_mz_ulong crc,
const drfs_mz_uint8 *ptr,
size_t buf_len)
5156 static const drfs_drfs_mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
5157 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
5158 drfs_drfs_mz_uint32 crcu32 = (drfs_drfs_mz_uint32)crc;
5159 if (!ptr)
return DRFS_MZ_CRC32_INIT;
5160 crcu32 = ~crcu32;
while (buf_len--) { drfs_mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; }
5164 void drfs_mz_free(
void *p)
5172 #define DRFS_TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
5173 #define DRFS_TINFL_MEMSET(p, c, l) memset(p, c, l)
5175 #define DRFS_TINFL_CR_BEGIN switch(r->m_state) { case 0:
5176 #define DRFS_TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } DRFS_MZ_MACRO_END
5177 #define DRFS_TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { DRFS_TINFL_CR_RETURN(state_index, result); } } DRFS_MZ_MACRO_END
5178 #define DRFS_TINFL_CR_FINISH }
5182 #define DRFS_TINFL_GET_BYTE(state_index, c) do { \
5183 if (pIn_buf_cur >= pIn_buf_end) { \
5185 if (decomp_flags & DRFS_TINFL_FLAG_HAS_MORE_INPUT) { \
5186 DRFS_TINFL_CR_RETURN(state_index, DRFS_TINFL_STATUS_NEEDS_MORE_INPUT); \
5187 if (pIn_buf_cur < pIn_buf_end) { \
5188 c = *pIn_buf_cur++; \
5196 } else c = *pIn_buf_cur++; } DRFS_MZ_MACRO_END
5198 #define DRFS_TINFL_NEED_BITS(state_index, n) do { drfs_mz_uint c; DRFS_TINFL_GET_BYTE(state_index, c); bit_buf |= (((drfs_tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (drfs_mz_uint)(n))
5199 #define DRFS_TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (drfs_mz_uint)(n)) { DRFS_TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } DRFS_MZ_MACRO_END
5200 #define DRFS_TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (drfs_mz_uint)(n)) { DRFS_TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } DRFS_MZ_MACRO_END
5206 #define DRFS_TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \
5208 temp = (pHuff)->m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]; \
5210 code_len = temp >> 9; \
5211 if ((code_len) && (num_bits >= code_len)) \
5213 } else if (num_bits > DRFS_TINFL_FAST_LOOKUP_BITS) { \
5214 code_len = DRFS_TINFL_FAST_LOOKUP_BITS; \
5216 temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
5217 } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \
5218 } DRFS_TINFL_GET_BYTE(state_index, c); bit_buf |= (((drfs_tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \
5219 } while (num_bits < 15);
5225 #define DRFS_TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \
5226 int temp; drfs_mz_uint code_len, c; \
5227 if (num_bits < 15) { \
5228 if ((pIn_buf_end - pIn_buf_cur) < 2) { \
5229 DRFS_TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \
5231 bit_buf |= (((drfs_tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((drfs_tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \
5234 if ((temp = (pHuff)->m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \
5235 code_len = temp >> 9, temp &= 511; \
5237 code_len = DRFS_TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \
5238 } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } DRFS_MZ_MACRO_END
5240 drfs_tinfl_status drfs_tinfl_decompress(drfs_tinfl_decompressor *r,
const drfs_mz_uint8 *pIn_buf_next,
size_t *pIn_buf_size, drfs_mz_uint8 *pOut_buf_start, drfs_mz_uint8 *pOut_buf_next,
size_t *pOut_buf_size,
const drfs_drfs_mz_uint32 decomp_flags)
5242 static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 };
5243 static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
5244 static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
5245 static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
5246 static const drfs_mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
5247 static const int s_min_table_sizes[3] = { 257, 1, 4 };
5249 drfs_tinfl_status status = DRFS_TINFL_STATUS_FAILED; drfs_drfs_mz_uint32 num_bits, dist, counter, num_extra; drfs_tinfl_bit_buf_t bit_buf;
5250 const drfs_mz_uint8 *pIn_buf_cur = pIn_buf_next, *
const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
5251 drfs_mz_uint8 *pOut_buf_cur = pOut_buf_next, *
const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
5252 size_t out_buf_size_mask = (decomp_flags & DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (
size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
5255 if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0;
return DRFS_TINFL_STATUS_BAD_PARAM; }
5257 num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start;
5260 bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1;
5261 if (decomp_flags & DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER)
5263 DRFS_TINFL_GET_BYTE(1, r->m_zhdr0); DRFS_TINFL_GET_BYTE(2, r->m_zhdr1);
5264 counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
5265 if (!(decomp_flags & DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
5266 if (counter) { DRFS_TINFL_CR_RETURN_FOREVER(36, DRFS_TINFL_STATUS_FAILED); }
5271 DRFS_TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1;
5274 DRFS_TINFL_SKIP_BITS(5, num_bits & 7);
5275 for (counter = 0; counter < 4; ++counter) {
if (num_bits) DRFS_TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
else DRFS_TINFL_GET_BYTE(7, r->m_raw_header[counter]); }
5276 if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (drfs_mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { DRFS_TINFL_CR_RETURN_FOREVER(39, DRFS_TINFL_STATUS_FAILED); }
5277 while ((counter) && (num_bits))
5279 DRFS_TINFL_GET_BITS(51, dist, 8);
5280 while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(52, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); }
5281 *pOut_buf_cur++ = (drfs_mz_uint8)dist;
5286 size_t n;
while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(9, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); }
5287 while (pIn_buf_cur >= pIn_buf_end)
5289 if (decomp_flags & DRFS_TINFL_FLAG_HAS_MORE_INPUT)
5291 DRFS_TINFL_CR_RETURN(38, DRFS_TINFL_STATUS_NEEDS_MORE_INPUT);
5295 DRFS_TINFL_CR_RETURN_FOREVER(40, DRFS_TINFL_STATUS_FAILED);
5298 n = DRFS_MZ_MIN(DRFS_MZ_MIN((
size_t)(pOut_buf_end - pOut_buf_cur), (
size_t)(pIn_buf_end - pIn_buf_cur)), counter);
5299 DRFS_TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (drfs_mz_uint)n;
5302 else if (r->m_type == 3)
5304 DRFS_TINFL_CR_RETURN_FOREVER(10, DRFS_TINFL_STATUS_FAILED);
5310 drfs_mz_uint8 *p = r->m_tables[0].m_code_size; drfs_mz_uint i;
5311 r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; DRFS_TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
5312 for ( i = 0; i <= 143; ++i) *p++ = 8;
for ( ; i <= 255; ++i) *p++ = 9;
for ( ; i <= 279; ++i) *p++ = 7;
for ( ; i <= 287; ++i) *p++ = 8;
5316 for (counter = 0; counter < 3; counter++) { DRFS_TINFL_GET_BITS(11, r->m_table_sizes[counter],
"\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; }
5317 DRFS_MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
for (counter = 0; counter < r->m_table_sizes[2]; counter++) { drfs_mz_uint
s; DRFS_TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (drfs_mz_uint8)s; }
5318 r->m_table_sizes[2] = 19;
5320 for ( ; (int)r->m_type >= 0; r->m_type--)
5322 int tree_next, tree_cur; drfs_tinfl_huff_table *pTable;
5323 drfs_mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; DRFS_MZ_CLEAR_OBJ(total_syms); DRFS_MZ_CLEAR_OBJ(pTable->m_look_up); DRFS_MZ_CLEAR_OBJ(pTable->m_tree);
5324 for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++;
5325 used_syms = 0, total = 0; next_code[0] = next_code[1] = 0;
5326 for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); }
5327 if ((65536 != total) && (used_syms > 1))
5329 DRFS_TINFL_CR_RETURN_FOREVER(35, DRFS_TINFL_STATUS_FAILED);
5331 for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
5333 drfs_mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index];
if (!code_size)
continue;
5334 cur_code = next_code[code_size]++;
for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1);
5335 if (code_size <= DRFS_TINFL_FAST_LOOKUP_BITS) { drfs_mz_int16 k = (drfs_mz_int16)((code_size << 9) | sym_index);
while (rev_code < DRFS_TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); }
continue; }
5336 if (0 == (tree_cur = pTable->m_look_up[rev_code & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)] = (drfs_mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
5337 rev_code >>= (DRFS_TINFL_FAST_LOOKUP_BITS - 1);
5338 for (j = code_size; j > (DRFS_TINFL_FAST_LOOKUP_BITS + 1); j--)
5340 tree_cur -= ((rev_code >>= 1) & 1);
5341 if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (drfs_mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; }
else tree_cur = pTable->m_tree[-tree_cur - 1];
5343 tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (drfs_mz_int16)sym_index;
5347 for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); )
5349 drfs_mz_uint
s; DRFS_TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
if (dist < 16) { r->m_len_codes[counter++] = (drfs_mz_uint8)dist;
continue; }
5350 if ((dist == 16) && (!counter))
5352 DRFS_TINFL_CR_RETURN_FOREVER(17, DRFS_TINFL_STATUS_FAILED);
5354 num_extra =
"\02\03\07"[dist - 16]; DRFS_TINFL_GET_BITS(18, s, num_extra);
s +=
"\03\03\013"[dist - 16];
5355 DRFS_TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter +=
s;
5357 if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
5359 DRFS_TINFL_CR_RETURN_FOREVER(21, DRFS_TINFL_STATUS_FAILED);
5361 DRFS_TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); DRFS_TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
5366 drfs_mz_uint8 *pSrc;
5369 if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
5371 DRFS_TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
5374 while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(24, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); }
5375 *pOut_buf_cur++ = (drfs_mz_uint8)counter;
5379 int sym2; drfs_mz_uint code_len;
5380 #if DRFS_TINFL_USE_64BIT_BITBUF
5381 if (num_bits < 30) { bit_buf |= (((drfs_tinfl_bit_buf_t)DRFS_MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; }
5383 if (num_bits < 15) { bit_buf |= (((drfs_tinfl_bit_buf_t)DRFS_MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
5385 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
5386 code_len = sym2 >> 9;
5389 code_len = DRFS_TINFL_FAST_LOOKUP_BITS;
do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; }
while (sym2 < 0);
5391 counter = sym2; bit_buf >>= code_len; num_bits -= code_len;
5395 #if !DRFS_TINFL_USE_64BIT_BITBUF
5396 if (num_bits < 15) { bit_buf |= (((drfs_tinfl_bit_buf_t)DRFS_MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; }
5398 if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (DRFS_TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
5399 code_len = sym2 >> 9;
5402 code_len = DRFS_TINFL_FAST_LOOKUP_BITS;
do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; }
while (sym2 < 0);
5404 bit_buf >>= code_len; num_bits -= code_len;
5406 pOut_buf_cur[0] = (drfs_mz_uint8)counter;
5413 pOut_buf_cur[1] = (drfs_mz_uint8)sym2;
5417 if ((counter &= 511) == 256)
break;
5419 num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257];
5420 if (num_extra) { drfs_mz_uint extra_bits; DRFS_TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; }
5422 DRFS_TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
5423 num_extra = s_dist_extra[dist]; dist = s_dist_base[dist];
5424 if (num_extra) { drfs_mz_uint extra_bits; DRFS_TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; }
5426 dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
5427 if ((dist > dist_from_out_buf_start) && (decomp_flags & DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
5429 DRFS_TINFL_CR_RETURN_FOREVER(37, DRFS_TINFL_STATUS_FAILED);
5432 pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
5434 if ((DRFS_MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
5438 while (pOut_buf_cur >= pOut_buf_end) { DRFS_TINFL_CR_RETURN(53, DRFS_TINFL_STATUS_HAS_MORE_OUTPUT); }
5439 *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
5443 #if DRFS_MINIZ_USE_UNALIGNED_LOADS_AND_STORES
5444 else if ((counter >= 9) && (counter <= dist))
5446 const drfs_mz_uint8 *pSrc_end = pSrc + (counter & ~7);
5449 ((drfs_drfs_mz_uint32 *)pOut_buf_cur)[0] = ((
const drfs_drfs_mz_uint32 *)pSrc)[0];
5450 ((drfs_drfs_mz_uint32 *)pOut_buf_cur)[1] = ((
const drfs_drfs_mz_uint32 *)pSrc)[1];
5452 }
while ((pSrc += 8) < pSrc_end);
5453 if ((counter &= 7) < 3)
5457 pOut_buf_cur[0] = pSrc[0];
5459 pOut_buf_cur[1] = pSrc[1];
5460 pOut_buf_cur += counter;
5468 pOut_buf_cur[0] = pSrc[0];
5469 pOut_buf_cur[1] = pSrc[1];
5470 pOut_buf_cur[2] = pSrc[2];
5471 pOut_buf_cur += 3; pSrc += 3;
5472 }
while ((
int)(counter -= 3) > 2);
5473 if ((
int)counter > 0)
5475 pOut_buf_cur[0] = pSrc[0];
5476 if ((
int)counter > 1)
5477 pOut_buf_cur[1] = pSrc[1];
5478 pOut_buf_cur += counter;
5482 }
while (!(r->m_final & 1));
5483 if (decomp_flags & DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER)
5485 DRFS_TINFL_SKIP_BITS(32, num_bits & 7);
for (counter = 0; counter < 4; ++counter) { drfs_mz_uint
s;
if (num_bits) DRFS_TINFL_GET_BITS(41, s, 8);
else DRFS_TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; }
5487 DRFS_TINFL_CR_RETURN_FOREVER(34, DRFS_TINFL_STATUS_DONE);
5488 DRFS_TINFL_CR_FINISH
5491 r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start;
5492 *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
5493 if ((decomp_flags & (DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER | DRFS_TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
5495 const drfs_mz_uint8 *ptr = pOut_buf_next;
size_t buf_len = *pOut_buf_size;
5496 drfs_drfs_mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16;
size_t block_len = buf_len % 5552;
5499 for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
5501 s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1;
5502 s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1;
5504 for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1;
5505 s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552;
5507 r->m_check_adler32 = (s2 << 16) + s1;
if ((status == DRFS_TINFL_STATUS_DONE) && (decomp_flags & DRFS_TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = DRFS_TINFL_STATUS_ADLER32_MISMATCH;
5513 void *drfs_tinfl_decompress_mem_to_heap(
const void *pSrc_buf,
size_t src_buf_len,
size_t *pOut_len,
int flags)
5515 drfs_tinfl_decompressor decomp;
void *pBuf =
NULL, *pNew_buf;
size_t src_buf_ofs = 0, out_buf_capacity = 0;
5517 drfs_tinfl_init(&decomp);
5520 size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
5521 drfs_tinfl_status status = drfs_tinfl_decompress(&decomp, (
const drfs_mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (drfs_mz_uint8*)pBuf, pBuf ? (drfs_mz_uint8*)pBuf + *pOut_len :
NULL, &dst_buf_size,
5522 (flags & ~DRFS_TINFL_FLAG_HAS_MORE_INPUT) | DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
5523 if ((status < 0) || (status == DRFS_TINFL_STATUS_NEEDS_MORE_INPUT))
5525 DRFS_MZ_FREE(pBuf); *pOut_len = 0;
return NULL;
5527 src_buf_ofs += src_buf_size;
5528 *pOut_len += dst_buf_size;
5529 if (status == DRFS_TINFL_STATUS_DONE)
break;
5530 new_out_buf_capacity = out_buf_capacity * 2;
if (new_out_buf_capacity < 128) new_out_buf_capacity = 128;
5531 pNew_buf = DRFS_MZ_REALLOC(pBuf, new_out_buf_capacity);
5534 DRFS_MZ_FREE(pBuf); *pOut_len = 0;
return NULL;
5536 pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity;
5541 size_t drfs_tinfl_decompress_mem_to_mem(
void *pOut_buf,
size_t out_buf_len,
const void *pSrc_buf,
size_t src_buf_len,
int flags)
5543 drfs_tinfl_decompressor decomp; drfs_tinfl_status status; drfs_tinfl_init(&decomp);
5544 status = drfs_tinfl_decompress(&decomp, (
const drfs_mz_uint8*)pSrc_buf, &src_buf_len, (drfs_mz_uint8*)pOut_buf, (drfs_mz_uint8*)pOut_buf, &out_buf_len, (flags & ~DRFS_TINFL_FLAG_HAS_MORE_INPUT) | DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
5545 return (status != DRFS_TINFL_STATUS_DONE) ? DRFS_TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
5548 int drfs_tinfl_decompress_mem_to_callback(
const void *pIn_buf,
size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func,
void *pPut_buf_user,
int flags)
5551 drfs_tinfl_decompressor decomp;
5552 drfs_mz_uint8 *pDict = (drfs_mz_uint8*)DRFS_MZ_MALLOC(DRFS_TINFL_LZ_DICT_SIZE);
size_t in_buf_ofs = 0, dict_ofs = 0;
5554 return DRFS_TINFL_STATUS_FAILED;
5555 drfs_tinfl_init(&decomp);
5558 size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = DRFS_TINFL_LZ_DICT_SIZE - dict_ofs;
5559 drfs_tinfl_status status = drfs_tinfl_decompress(&decomp, (
const drfs_mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
5560 (flags & ~(DRFS_TINFL_FLAG_HAS_MORE_INPUT | DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
5561 in_buf_ofs += in_buf_size;
5562 if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (
int)dst_buf_size, pPut_buf_user)))
5564 if (status != DRFS_TINFL_STATUS_HAS_MORE_OUTPUT)
5566 result = (status == DRFS_TINFL_STATUS_DONE);
5569 dict_ofs = (dict_ofs + dst_buf_size) & (DRFS_TINFL_LZ_DICT_SIZE - 1);
5571 DRFS_MZ_FREE(pDict);
5572 *pIn_buf_size = in_buf_ofs;
5579 #ifndef DRFS_MINIZ_NO_ARCHIVE_APIS
5581 #define DRFS_MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
5587 DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
5588 DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
5590 DRFS_MZ_ZIP_CDH_SIG_OFS = 0, DRFS_MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, DRFS_MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, DRFS_MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
5591 DRFS_MZ_ZIP_CDH_METHOD_OFS = 10, DRFS_MZ_ZIP_CDH_FILE_TIME_OFS = 12, DRFS_MZ_ZIP_CDH_FILE_DATE_OFS = 14, DRFS_MZ_ZIP_CDH_CRC32_OFS = 16,
5592 DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
5593 DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, DRFS_MZ_ZIP_CDH_DISK_START_OFS = 34, DRFS_MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, DRFS_MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, DRFS_MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
5595 DRFS_MZ_ZIP_LDH_SIG_OFS = 0, DRFS_MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, DRFS_MZ_ZIP_LDH_BIT_FLAG_OFS = 6, DRFS_MZ_ZIP_LDH_METHOD_OFS = 8, DRFS_MZ_ZIP_LDH_FILE_TIME_OFS = 10,
5596 DRFS_MZ_ZIP_LDH_FILE_DATE_OFS = 12, DRFS_MZ_ZIP_LDH_CRC32_OFS = 14, DRFS_MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, DRFS_MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
5597 DRFS_MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, DRFS_MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
5599 DRFS_MZ_ZIP_ECDH_SIG_OFS = 0, DRFS_MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, DRFS_MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, DRFS_MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
5600 DRFS_MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, DRFS_MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, DRFS_MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, DRFS_MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
5606 size_t m_size, m_capacity;
5607 drfs_mz_uint m_element_size;
5608 } drfs_mz_zip_array;
5610 struct drfs_mz_zip_internal_state_tag
5612 drfs_mz_zip_array m_central_dir;
5613 drfs_mz_zip_array m_central_dir_offsets;
5614 drfs_mz_zip_array m_sorted_central_dir_offsets;
5618 size_t m_mem_capacity;
5621 #define DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
5622 #define DRFS_MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
5624 static DRFS_MZ_FORCEINLINE
void drfs_mz_zip_array_clear(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray)
5626 pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
5627 memset(pArray, 0,
sizeof(drfs_mz_zip_array));
5630 static drfs_mz_bool drfs_mz_zip_array_ensure_capacity(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray,
size_t min_new_capacity, drfs_mz_uint growing)
5632 void *pNew_p;
size_t new_capacity = min_new_capacity; DRFS_MZ_ASSERT(pArray->m_element_size);
if (pArray->m_capacity >= min_new_capacity)
return DRFS_MZ_TRUE;
5633 if (growing) { new_capacity = DRFS_MZ_MAX(1, pArray->m_capacity);
while (new_capacity < min_new_capacity) new_capacity *= 2; }
5634 if (
NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity)))
return DRFS_MZ_FALSE;
5635 pArray->m_p = pNew_p; pArray->m_capacity = new_capacity;
5636 return DRFS_MZ_TRUE;
5639 static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_reserve(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray,
size_t new_capacity, drfs_mz_uint growing)
5641 if (new_capacity > pArray->m_capacity) {
if (!drfs_mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
return DRFS_MZ_FALSE; }
5642 return DRFS_MZ_TRUE;
5645 static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_resize(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray,
size_t new_size, drfs_mz_uint growing)
5647 if (new_size > pArray->m_capacity) {
if (!drfs_mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
return DRFS_MZ_FALSE; }
5648 pArray->m_size = new_size;
5649 return DRFS_MZ_TRUE;
5652 static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_ensure_room(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray,
size_t n)
5654 return drfs_mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, DRFS_MZ_TRUE);
5657 static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_array_push_back(drfs_mz_zip_archive *pZip, drfs_mz_zip_array *pArray,
const void *pElements,
size_t n)
5659 size_t orig_size = pArray->m_size;
if (!drfs_mz_zip_array_resize(pZip, pArray, orig_size + n, DRFS_MZ_TRUE))
return DRFS_MZ_FALSE;
5660 memcpy((drfs_mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
5661 return DRFS_MZ_TRUE;
5664 #ifndef DRFS_MINIZ_NO_TIME
5665 static time_t drfs_mz_zip_dos_to_time_t(
int dos_time,
int dos_date)
5668 memset(&tm, 0,
sizeof(tm)); tm.tm_isdst = -1;
5669 tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31;
5670 tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62;
5675 static drfs_mz_bool drfs_mz_zip_reader_init_internal(drfs_mz_zip_archive *pZip, drfs_drfs_mz_uint32 flags)
5678 if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_INVALID))
5679 return DRFS_MZ_FALSE;
5681 if (!pZip->m_pAlloc) pZip->m_pAlloc = drfs__def_alloc_func;
5682 if (!pZip->m_pFree) pZip->m_pFree = drfs__def_free_func;
5683 if (!pZip->m_pRealloc) pZip->m_pRealloc = drfs__def_realloc_func;
5685 pZip->m_zip_mode = DRFS_MZ_ZIP_MODE_READING;
5686 pZip->m_archive_size = 0;
5687 pZip->m_central_directory_file_ofs = 0;
5688 pZip->m_total_files = 0;
5690 if (
NULL == (pZip->m_pState = (drfs_mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1,
sizeof(drfs_mz_zip_internal_state))))
5691 return DRFS_MZ_FALSE;
5692 memset(pZip->m_pState, 0,
sizeof(drfs_mz_zip_internal_state));
5693 DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir,
sizeof(drfs_mz_uint8));
5694 DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets,
sizeof(drfs_drfs_mz_uint32));
5695 DRFS_MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets,
sizeof(drfs_drfs_mz_uint32));
5696 return DRFS_MZ_TRUE;
5699 static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_reader_filename_less(
const drfs_mz_zip_array *pCentral_dir_array,
const drfs_mz_zip_array *pCentral_dir_offsets, drfs_mz_uint l_index, drfs_mz_uint r_index)
5701 const drfs_mz_uint8 *pL = &DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, drfs_drfs_mz_uint32, l_index)), *pE;
5702 const drfs_mz_uint8 *pR = &DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, drfs_drfs_mz_uint32, r_index));
5703 drfs_mz_uint l_len = DRFS_MZ_READ_LE16(pL + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = DRFS_MZ_READ_LE16(pR + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS);
5704 drfs_mz_uint8 l = 0, r = 0;
5705 pL += DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5706 pE = pL + DRFS_MZ_MIN(l_len, r_len);
5709 if ((l = DRFS_MZ_TOLOWER(*pL)) != (r = DRFS_MZ_TOLOWER(*pR)))
5713 return (pL == pE) ? (l_len < r_len) : (l < r);
5716 #define DRFS_MZ_SWAP_UINT32(a, b) do { drfs_drfs_mz_uint32 t = a; a = b; b = t; } DRFS_MZ_MACRO_END
5719 static void drfs_mz_zip_reader_sort_central_dir_offsets_by_filename(drfs_mz_zip_archive *pZip)
5721 drfs_mz_zip_internal_state *pState = pZip->m_pState;
5722 const drfs_mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5723 const drfs_mz_zip_array *pCentral_dir = &pState->m_central_dir;
5724 drfs_drfs_mz_uint32 *pIndices = &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, drfs_drfs_mz_uint32, 0);
5725 const int size = pZip->m_total_files;
5726 int start = (size - 2) >> 1, end;
5729 int child, root =
start;
5732 if ((child = (root << 1) + 1) >= size)
5734 child += (((child + 1) < size) && (drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])));
5735 if (!drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
5737 DRFS_MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
5745 int child, root = 0;
5746 DRFS_MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
5749 if ((child = (root << 1) + 1) >= end)
5751 child += (((child + 1) < end) && drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]));
5752 if (!drfs_mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
5754 DRFS_MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child;
5760 static drfs_mz_bool drfs_mz_zip_reader_read_central_dir(drfs_mz_zip_archive *pZip, drfs_drfs_mz_uint32 flags)
5762 drfs_mz_uint cdir_size, num_this_disk, cdir_disk_index;
5763 drfs_mz_uint64 cdir_ofs;
5764 drfs_mz_int64 cur_file_ofs;
5765 const drfs_mz_uint8 *p;
5766 drfs_drfs_mz_uint32 buf_u32[4096 /
sizeof(drfs_drfs_mz_uint32)]; drfs_mz_uint8 *pBuf = (drfs_mz_uint8 *)buf_u32;
5767 drfs_mz_bool sort_central_dir = ((flags & DRFS_MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
5769 if (pZip->m_archive_size < DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5770 return DRFS_MZ_FALSE;
5772 cur_file_ofs = DRFS_MZ_MAX((drfs_mz_int64)pZip->m_archive_size - (drfs_mz_int64)
sizeof(buf_u32), 0);
5775 int i, n = (int)DRFS_MZ_MIN(
sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
5776 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (drfs_mz_uint)n)
5777 return DRFS_MZ_FALSE;
5778 for (i = n - 4; i >= 0; --i)
5779 if (DRFS_MZ_READ_LE32(pBuf + i) == DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
5786 if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
5787 return DRFS_MZ_FALSE;
5788 cur_file_ofs = DRFS_MZ_MAX(cur_file_ofs - (
sizeof(buf_u32) - 3), 0);
5791 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
5792 return DRFS_MZ_FALSE;
5793 if ((DRFS_MZ_READ_LE32(pBuf + DRFS_MZ_ZIP_ECDH_SIG_OFS) != DRFS_MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) ||
5794 ((pZip->m_total_files = DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS)))
5795 return DRFS_MZ_FALSE;
5797 num_this_disk = DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
5798 cdir_disk_index = DRFS_MZ_READ_LE16(pBuf + DRFS_MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
5799 if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
5800 return DRFS_MZ_FALSE;
5802 if ((cdir_size = DRFS_MZ_READ_LE32(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
5803 return DRFS_MZ_FALSE;
5805 cdir_ofs = DRFS_MZ_READ_LE32(pBuf + DRFS_MZ_ZIP_ECDH_CDIR_OFS_OFS);
5806 if ((cdir_ofs + (drfs_mz_uint64)cdir_size) > pZip->m_archive_size)
5807 return DRFS_MZ_FALSE;
5809 pZip->m_central_directory_file_ofs = cdir_ofs;
5811 if (pZip->m_total_files)
5816 if ((!drfs_mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, DRFS_MZ_FALSE)) ||
5817 (!drfs_mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, DRFS_MZ_FALSE)))
5818 return DRFS_MZ_FALSE;
5820 if (sort_central_dir)
5822 if (!drfs_mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, DRFS_MZ_FALSE))
5823 return DRFS_MZ_FALSE;
5826 if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
5827 return DRFS_MZ_FALSE;
5830 p = (
const drfs_mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
5831 for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
5833 drfs_mz_uint total_header_size, comp_size, decomp_size, disk_index;
5834 if ((n < DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (DRFS_MZ_READ_LE32(p) != DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
5835 return DRFS_MZ_FALSE;
5836 DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, i) = (drfs_drfs_mz_uint32)(p - (
const drfs_mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
5837 if (sort_central_dir)
5838 DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, drfs_drfs_mz_uint32, i) = i;
5839 comp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5840 decomp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5841 if (((!DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF))
5842 return DRFS_MZ_FALSE;
5843 disk_index = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_DISK_START_OFS);
5844 if ((disk_index != num_this_disk) && (disk_index != 1))
5845 return DRFS_MZ_FALSE;
5846 if (((drfs_mz_uint64)DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_LOCAL_HEADER_OFS) + DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
5847 return DRFS_MZ_FALSE;
5848 if ((total_header_size = DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS) + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS) + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n)
5849 return DRFS_MZ_FALSE;
5850 n -= total_header_size; p += total_header_size;
5854 if (sort_central_dir)
5855 drfs_mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
5857 return DRFS_MZ_TRUE;
5860 drfs_mz_bool drfs_mz_zip_reader_init(drfs_mz_zip_archive *pZip, drfs_mz_uint64 size, drfs_drfs_mz_uint32 flags)
5862 if ((!pZip) || (!pZip->m_pRead))
5863 return DRFS_MZ_FALSE;
5864 if (!drfs_mz_zip_reader_init_internal(pZip, flags))
5865 return DRFS_MZ_FALSE;
5866 pZip->m_archive_size = size;
5867 if (!drfs_mz_zip_reader_read_central_dir(pZip, flags))
5869 drfs_mz_zip_reader_end(pZip);
5870 return DRFS_MZ_FALSE;
5872 return DRFS_MZ_TRUE;
5875 drfs_mz_uint drfs_mz_zip_reader_get_num_files(drfs_mz_zip_archive *pZip)
5877 return pZip ? pZip->m_total_files : 0;
5880 static DRFS_MZ_FORCEINLINE
const drfs_mz_uint8 *drfs_mz_zip_reader_get_cdh(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index)
5882 if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_READING))
5884 return &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, file_index));
5887 drfs_mz_bool drfs_mz_zip_reader_is_file_a_directory(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index)
5889 drfs_mz_uint filename_len, external_attr;
5890 const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index);
5892 return DRFS_MZ_FALSE;
5895 filename_len = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS);
5898 if (*(p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) ==
'/')
5899 return DRFS_MZ_TRUE;
5905 external_attr = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5906 if ((external_attr & 0x10) != 0)
5907 return DRFS_MZ_TRUE;
5909 return DRFS_MZ_FALSE;
5912 drfs_mz_bool drfs_mz_zip_reader_file_stat(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index, drfs_drfs_mz_zip_archive_file_stat *pStat)
5915 const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index);
5916 if ((!p) || (!pStat))
5917 return DRFS_MZ_FALSE;
5920 pStat->m_file_index = file_index;
5921 pStat->m_central_dir_ofs = DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, file_index);
5922 pStat->m_version_made_by = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
5923 pStat->m_version_needed = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_VERSION_NEEDED_OFS);
5924 pStat->m_bit_flag = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_BIT_FLAG_OFS);
5925 pStat->m_method = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_METHOD_OFS);
5926 #ifndef DRFS_MINIZ_NO_TIME
5927 pStat->m_time = drfs_mz_zip_dos_to_time_t(DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILE_TIME_OFS), DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILE_DATE_OFS));
5929 pStat->m_crc32 = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_CRC32_OFS);
5930 pStat->m_comp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
5931 pStat->m_uncomp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
5932 pStat->m_internal_attr = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
5933 pStat->m_external_attr = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
5934 pStat->m_local_header_ofs = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_LOCAL_HEADER_OFS);
5937 n = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS); n = DRFS_MZ_MIN(n, DRFS_MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
5938 memcpy(pStat->m_filename, p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] =
'\0';
5940 n = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS); n = DRFS_MZ_MIN(n, DRFS_MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
5941 pStat->m_comment_size = n;
5942 memcpy(pStat->m_comment, p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS) + DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] =
'\0';
5944 return DRFS_MZ_TRUE;
5947 drfs_mz_uint drfs_mz_zip_reader_get_filename(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
char *pFilename, drfs_mz_uint filename_buf_size)
5950 const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index);
5951 if (!p) {
if (filename_buf_size) pFilename[0] =
'\0';
return 0; }
5952 n = DRFS_MZ_READ_LE16(p + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS);
5953 if (filename_buf_size)
5955 n = DRFS_MZ_MIN(n, filename_buf_size - 1);
5956 memcpy(pFilename, p + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
5957 pFilename[n] =
'\0';
5962 static DRFS_MZ_FORCEINLINE drfs_mz_bool drfs_mz_zip_reader_string_equal(
const char *pA,
const char *pB, drfs_mz_uint len, drfs_mz_uint flags)
5965 if (flags & DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE)
5966 return 0 == memcmp(pA, pB, len);
5967 for (i = 0; i < len; ++i)
5968 if (DRFS_MZ_TOLOWER(pA[i]) != DRFS_MZ_TOLOWER(pB[i]))
5969 return DRFS_MZ_FALSE;
5970 return DRFS_MZ_TRUE;
5973 static DRFS_MZ_FORCEINLINE
int drfs_mz_zip_reader_filename_compare(
const drfs_mz_zip_array *pCentral_dir_array,
const drfs_mz_zip_array *pCentral_dir_offsets, drfs_mz_uint l_index,
const char *pR, drfs_mz_uint r_len)
5975 const drfs_mz_uint8 *pL = &DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, drfs_drfs_mz_uint32, l_index)), *pE;
5976 drfs_mz_uint l_len = DRFS_MZ_READ_LE16(pL + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS);
5977 drfs_mz_uint8 l = 0, r = 0;
5978 pL += DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
5979 pE = pL + DRFS_MZ_MIN(l_len, r_len);
5982 if ((l = DRFS_MZ_TOLOWER(*pL)) != (r = DRFS_MZ_TOLOWER(*pR)))
5986 return (pL == pE) ? (int)(l_len - r_len) : (l - r);
5989 static int drfs_mz_zip_reader_locate_file_binary_search(drfs_mz_zip_archive *pZip,
const char *pFilename)
5991 drfs_mz_zip_internal_state *pState = pZip->m_pState;
5992 const drfs_mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
5993 const drfs_mz_zip_array *pCentral_dir = &pState->m_central_dir;
5994 drfs_drfs_mz_uint32 *pIndices = &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, drfs_drfs_mz_uint32, 0);
5995 const int size = pZip->m_total_files;
5996 const drfs_mz_uint filename_len = (drfs_mz_uint)strlen(pFilename);
5997 int l = 0, h = size - 1;
6000 int m = (l + h) >> 1, file_index = pIndices[m], comp = drfs_mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);
6011 int drfs_mz_zip_reader_locate_file(drfs_mz_zip_archive *pZip,
const char *pName,
const char *pComment, drfs_mz_uint flags)
6013 drfs_mz_uint file_index;
size_t name_len, comment_len;
6014 if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_READING))
6016 if (((flags & (DRFS_MZ_ZIP_FLAG_IGNORE_PATH | DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
6017 return drfs_mz_zip_reader_locate_file_binary_search(pZip, pName);
6018 name_len = strlen(pName);
if (name_len > 0xFFFF)
return -1;
6019 comment_len = pComment ? strlen(pComment) : 0;
if (comment_len > 0xFFFF)
return -1;
6020 for (file_index = 0; file_index < pZip->m_total_files; file_index++)
6022 const drfs_mz_uint8 *pHeader = &DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, drfs_mz_uint8, DRFS_MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, drfs_drfs_mz_uint32, file_index));
6023 drfs_mz_uint filename_len = DRFS_MZ_READ_LE16(pHeader + DRFS_MZ_ZIP_CDH_FILENAME_LEN_OFS);
6024 const char *pFilename = (
const char *)pHeader + DRFS_MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
6025 if (filename_len < name_len)
6029 drfs_mz_uint file_extra_len = DRFS_MZ_READ_LE16(pHeader + DRFS_MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = DRFS_MZ_READ_LE16(pHeader + DRFS_MZ_ZIP_CDH_COMMENT_LEN_OFS);
6030 const char *pFile_comment = pFilename + filename_len + file_extra_len;
6031 if ((file_comment_len != comment_len) || (!drfs_mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags)))
6034 if ((flags & DRFS_MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
6036 int ofs = filename_len - 1;
6039 if ((pFilename[ofs] ==
'/') || (pFilename[ofs] ==
'\\') || (pFilename[ofs] ==
':'))
6041 }
while (--ofs >= 0);
6043 pFilename += ofs; filename_len -= ofs;
6045 if ((filename_len == name_len) && (drfs_mz_zip_reader_string_equal(pName, pFilename, filename_len, flags)))
6051 drfs_mz_bool drfs_mz_zip_reader_extract_to_mem_no_alloc(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
void *pBuf,
size_t buf_size, drfs_mz_uint flags,
void *pUser_read_buf,
size_t user_read_buf_size)
6053 int status = DRFS_TINFL_STATUS_DONE;
6054 drfs_mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
6055 drfs_drfs_mz_zip_archive_file_stat file_stat;
6057 drfs_drfs_mz_uint32 local_header_u32[(DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE +
sizeof(drfs_drfs_mz_uint32) - 1) /
sizeof(drfs_drfs_mz_uint32)]; drfs_mz_uint8 *pLocal_header = (drfs_mz_uint8 *)local_header_u32;
6058 drfs_tinfl_decompressor inflator;
6060 if ((buf_size) && (!pBuf))
6061 return DRFS_MZ_FALSE;
6063 if (!drfs_mz_zip_reader_file_stat(pZip, file_index, &file_stat))
6064 return DRFS_MZ_FALSE;
6067 if (!file_stat.m_comp_size)
6068 return DRFS_MZ_TRUE;
6072 if (drfs_mz_zip_reader_is_file_a_directory(pZip, file_index))
6073 return DRFS_MZ_TRUE;
6076 if (file_stat.m_bit_flag & (1 | 32))
6077 return DRFS_MZ_FALSE;
6080 if ((!(flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != DRFS_MZ_DEFLATED))
6081 return DRFS_MZ_FALSE;
6084 needed_size = (flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
6085 if (buf_size < needed_size)
6086 return DRFS_MZ_FALSE;
6089 cur_file_ofs = file_stat.m_local_header_ofs;
6090 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
6091 return DRFS_MZ_FALSE;
6092 if (DRFS_MZ_READ_LE32(pLocal_header) != DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIG)
6093 return DRFS_MZ_FALSE;
6095 cur_file_ofs += DRFS_MZ_ZIP_LOCAL_DIR_HEADER_SIZE + DRFS_MZ_READ_LE16(pLocal_header + DRFS_MZ_ZIP_LDH_FILENAME_LEN_OFS) + DRFS_MZ_READ_LE16(pLocal_header + DRFS_MZ_ZIP_LDH_EXTRA_LEN_OFS);
6096 if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
6097 return DRFS_MZ_FALSE;
6099 if ((flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
6102 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (
size_t)needed_size) != needed_size)
6103 return DRFS_MZ_FALSE;
6104 return ((flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (drfs_mz_crc32(DRFS_MZ_CRC32_INIT, (
const drfs_mz_uint8 *)pBuf, (
size_t)file_stat.m_uncomp_size) == file_stat.m_crc32);
6108 drfs_tinfl_init(&inflator);
6110 if (pZip->m_pState->m_pMem)
6113 pRead_buf = (drfs_mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
6114 read_buf_size = read_buf_avail = file_stat.m_comp_size;
6117 else if (pUser_read_buf)
6120 if (!user_read_buf_size)
6121 return DRFS_MZ_FALSE;
6122 pRead_buf = (drfs_mz_uint8 *)pUser_read_buf;
6123 read_buf_size = user_read_buf_size;
6125 comp_remaining = file_stat.m_comp_size;
6130 read_buf_size = DRFS_MZ_MIN(file_stat.m_comp_size, DRFS_MZ_ZIP_MAX_IO_BUF_SIZE);
6132 if (((0,
sizeof(
size_t) ==
sizeof(drfs_drfs_mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
6134 if (((
sizeof(
size_t) ==
sizeof(drfs_drfs_mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
6136 return DRFS_MZ_FALSE;
6137 if (
NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (
size_t)read_buf_size)))
6138 return DRFS_MZ_FALSE;
6140 comp_remaining = file_stat.m_comp_size;
6145 size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
6146 if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
6148 read_buf_avail = DRFS_MZ_MIN(read_buf_size, comp_remaining);
6149 if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (
size_t)read_buf_avail) != read_buf_avail)
6151 status = DRFS_TINFL_STATUS_FAILED;
6154 cur_file_ofs += read_buf_avail;
6155 comp_remaining -= read_buf_avail;
6158 in_buf_size = (size_t)read_buf_avail;
6159 status = drfs_tinfl_decompress(&inflator, (drfs_mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (drfs_mz_uint8 *)pBuf, (drfs_mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, DRFS_TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? DRFS_TINFL_FLAG_HAS_MORE_INPUT : 0));
6160 read_buf_avail -= in_buf_size;
6161 read_buf_ofs += in_buf_size;
6162 out_buf_ofs += out_buf_size;
6163 }
while (status == DRFS_TINFL_STATUS_NEEDS_MORE_INPUT);
6165 if (status == DRFS_TINFL_STATUS_DONE)
6168 if ((out_buf_ofs != file_stat.m_uncomp_size) || (drfs_mz_crc32(DRFS_MZ_CRC32_INIT, (
const drfs_mz_uint8 *)pBuf, (
size_t)file_stat.m_uncomp_size) != file_stat.m_crc32))
6169 status = DRFS_TINFL_STATUS_FAILED;
6172 if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
6173 pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
6175 return status == DRFS_TINFL_STATUS_DONE;
6178 drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem_no_alloc(drfs_mz_zip_archive *pZip,
const char *pFilename,
void *pBuf,
size_t buf_size, drfs_mz_uint flags,
void *pUser_read_buf,
size_t user_read_buf_size)
6180 int file_index = drfs_mz_zip_reader_locate_file(pZip, pFilename,
NULL, flags);
6182 return DRFS_MZ_FALSE;
6183 return drfs_mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
6186 drfs_mz_bool drfs_mz_zip_reader_extract_to_mem(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
void *pBuf,
size_t buf_size, drfs_mz_uint flags)
6188 return drfs_mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags,
NULL, 0);
6191 drfs_mz_bool drfs_mz_zip_reader_extract_file_to_mem(drfs_mz_zip_archive *pZip,
const char *pFilename,
void *pBuf,
size_t buf_size, drfs_mz_uint flags)
6193 return drfs_mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags,
NULL, 0);
6196 void *drfs_mz_zip_reader_extract_to_heap(drfs_mz_zip_archive *pZip, drfs_mz_uint file_index,
size_t *pSize, drfs_mz_uint flags)
6198 drfs_mz_uint64 comp_size, uncomp_size, alloc_size;
6199 const drfs_mz_uint8 *p = drfs_mz_zip_reader_get_cdh(pZip, file_index);
6207 comp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
6208 uncomp_size = DRFS_MZ_READ_LE32(p + DRFS_MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
6210 alloc_size = (flags & DRFS_MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
6212 if (((0,
sizeof(
size_t) ==
sizeof(drfs_drfs_mz_uint32))) && (alloc_size > 0x7FFFFFFF))
6214 if (((
sizeof(
size_t) ==
sizeof(drfs_drfs_mz_uint32))) && (alloc_size > 0x7FFFFFFF))
6217 if (
NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (
size_t)alloc_size)))
6220 if (!drfs_mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (
size_t)alloc_size, flags))
6222 pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
6226 if (pSize) *pSize = (size_t)alloc_size;
6230 drfs_mz_bool drfs_mz_zip_reader_end(drfs_mz_zip_archive *pZip)
6232 if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != DRFS_MZ_ZIP_MODE_READING))
6233 return DRFS_MZ_FALSE;
6237 drfs_mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState =
NULL;
6238 drfs_mz_zip_array_clear(pZip, &pState->m_central_dir);
6239 drfs_mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
6240 drfs_mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
6242 pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
6244 pZip->m_zip_mode = DRFS_MZ_ZIP_MODE_INVALID;
6246 return DRFS_MZ_TRUE;
6249 #endif // #ifndef DRFS_MINIZ_NO_ARCHIVE_APIS
6255 #endif // DRFS_MINIZ_HEADER_FILE_ONLY
6257 #if defined(__GNUC__)
6258 #pragma GCC diagnostic pop
6260 #if defined(_MSC_VER)
6261 #pragma warning(pop)
6285 drfs_mz_uint8* pData;
6293 }drfs_openedfile_zip;
6295 static size_t drfs_drfs_mz_file_read_func(
void *pOpaque, drfs_mz_uint64 file_ofs,
void *pBuf,
size_t n)
6299 assert(pZipFile !=
NULL);
6315 return (
size_t)bytesRead;
6319 static dr_bool32 drfs_is_valid_extension__zip(
const char* extension)
6321 return drfs__stricmp(extension,
"zip") == 0;
6326 assert(pArchiveFile !=
NULL);
6327 assert(pHandleOut !=
NULL);
6338 drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)malloc(
sizeof(drfs_mz_zip_archive));
6343 memset(pZip, 0,
sizeof(drfs_mz_zip_archive));
6345 pZip->m_pRead = drfs_drfs_mz_file_read_func;
6346 pZip->m_pIO_opaque = pArchiveFile;
6347 if (!drfs_mz_zip_reader_init(pZip,
drfs_size(pArchiveFile), 0)) {
6356 static void drfs_close_archive__zip(
drfs_handle archive)
6358 assert(archive !=
NULL);
6360 drfs_mz_zip_reader_end((drfs_mz_zip_archive*)archive);
6366 assert(archive !=
NULL);
6368 drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive;
6369 int fileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath,
NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE);
6370 if (fileIndex == -1)
6377 drfs__strcpy_s(relativePathWithSlash,
sizeof(relativePathWithSlash), relativePath);
6378 drfs__strcat_s(relativePathWithSlash,
sizeof(relativePathWithSlash),
"/");
6379 fileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath,
NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE);
6380 if (fileIndex == -1)
6385 drfs_mz_uint numFiles = drfs_mz_zip_reader_get_num_files(pZip);
6386 for (drfs_mz_uint iFile = 0; iFile < numFiles; ++iFile)
6389 if (drfs_mz_zip_reader_get_filename(pZip, iFile, filePath,
DRFS_MAX_PATH) > 0)
6391 if (drfs_drpath_is_child(filePath, relativePath))
6409 assert(fileIndex != -1);
6413 drfs_drfs_mz_zip_archive_file_stat zipStat;
6414 if (drfs_mz_zip_reader_file_stat(pZip, (drfs_mz_uint)fileIndex, &zipStat))
6420 if (drfs_mz_zip_reader_is_file_a_directory(pZip, (drfs_mz_uint)fileIndex)) {
6433 assert(relativePath !=
NULL);
6435 drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive;
6436 assert(pZip !=
NULL);
6438 int directoryFileIndex = -1;
6439 if (relativePath[0] ==
'\0') {
6440 directoryFileIndex = 0;
6442 directoryFileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath,
NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE);
6445 if (directoryFileIndex == -1)
6449 drfs__strcpy_s(relativePathWithSlash,
sizeof(relativePathWithSlash), relativePath);
6450 drfs__strcat_s(relativePathWithSlash,
sizeof(relativePathWithSlash),
"/");
6451 directoryFileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath,
NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE);
6452 if (directoryFileIndex == -1)
6457 drfs_mz_uint numFiles = drfs_mz_zip_reader_get_num_files(pZip);
6458 for (drfs_mz_uint iFile = 0; iFile < numFiles; ++iFile)
6461 if (drfs_mz_zip_reader_get_filename(pZip, iFile, filePath,
DRFS_MAX_PATH) > 0)
6463 if (drfs_drpath_is_child(filePath, relativePath))
6479 drfs_iterator_zip* pZipIterator = (drfs_iterator_zip*)malloc(
sizeof(drfs_iterator_zip));
6480 if (pZipIterator !=
NULL)
6482 pZipIterator->index = 0;
6483 drfs__strcpy_s(pZipIterator->directoryPath,
sizeof(pZipIterator->directoryPath), relativePath);
6486 return pZipIterator;
6492 assert(archive !=
NULL);
6493 assert(iterator !=
NULL);
6501 assert(archive !=
NULL);
6502 assert(iterator !=
NULL);
6504 drfs_iterator_zip* pZipIterator = (drfs_iterator_zip*)iterator;
6505 if (pZipIterator ==
NULL) {
6509 drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive;
6510 while (pZipIterator->index < drfs_mz_zip_reader_get_num_files(pZip))
6512 unsigned int iFile = pZipIterator->index++;
6515 if (drfs_mz_zip_reader_get_filename(pZip, iFile, filePath,
DRFS_MAX_PATH) > 0)
6517 if (drfs_drpath_is_child(filePath, pZipIterator->directoryPath))
6521 drfs_drfs_mz_zip_archive_file_stat zipStat;
6522 if (drfs_mz_zip_reader_file_stat(pZip, iFile, &zipStat))
6528 if (drfs_mz_zip_reader_is_file_a_directory(pZip, iFile)) {
6535 if (absolutePathLen > 0 && (fi->
absolutePath[absolutePathLen - 1] ==
'/' || fi->
absolutePath[absolutePathLen - 1] ==
'\\')) {
6552 assert(archive !=
NULL);
6553 assert(pHandleOut !=
NULL);
6554 assert(relativePath !=
NULL);
6564 drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive;
6565 int fileIndex = drfs_mz_zip_reader_locate_file(pZip, relativePath,
NULL, DRFS_MZ_ZIP_FLAG_CASE_SENSITIVE);
6566 if (fileIndex == -1) {
6570 drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)malloc(
sizeof(*pOpenedFile));
6571 if (pOpenedFile ==
NULL) {
6575 pOpenedFile->pData = (drfs_mz_uint8*)drfs_mz_zip_reader_extract_to_heap(pZip, (drfs_mz_uint)fileIndex, &pOpenedFile->sizeInBytes, 0);
6576 if (pOpenedFile->pData ==
NULL) {
6581 pOpenedFile->index = (drfs_mz_uint)fileIndex;
6582 pOpenedFile->readPointer = 0;
6584 *pHandleOut = pOpenedFile;
6590 drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file;
6591 assert(pOpenedFile !=
NULL);
6593 drfs_mz_zip_archive* pZip = (drfs_mz_zip_archive*)archive;
6594 assert(pZip !=
NULL);
6596 pZip->m_pFree(pZip->m_pAlloc_opaque, pOpenedFile->pData);
6603 assert(archive !=
NULL);
6604 assert(file !=
NULL);
6605 assert(pDataOut !=
NULL);
6606 assert(bytesToRead > 0);
6608 drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file;
6609 if (pOpenedFile ==
NULL) {
6613 size_t bytesAvailable = pOpenedFile->sizeInBytes - pOpenedFile->readPointer;
6614 if (bytesAvailable < bytesToRead) {
6615 bytesToRead = bytesAvailable;
6618 if (bytesToRead == 0) {
6623 memcpy(pDataOut, pOpenedFile->pData + pOpenedFile->readPointer, bytesToRead);
6624 pOpenedFile->readPointer += bytesToRead;
6626 if (pBytesReadOut) {
6627 *pBytesReadOut = bytesToRead;
6640 assert(archive !=
NULL);
6641 assert(file !=
NULL);
6642 assert(pData !=
NULL);
6643 assert(bytesToWrite > 0);
6646 if (pBytesWrittenOut) {
6647 *pBytesWrittenOut = 0;
6657 assert(archive !=
NULL);
6658 assert(file !=
NULL);
6660 drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file;
6661 if (pOpenedFile ==
NULL) {
6665 dr_uint64 newPos = pOpenedFile->readPointer;
6668 if ((
dr_int64)newPos + bytesToSeek >= 0)
6680 assert(bytesToSeek >= 0);
6685 assert(bytesToSeek >= 0);
6686 if ((
dr_uint64)bytesToSeek <= pOpenedFile->sizeInBytes)
6688 newPos = pOpenedFile->sizeInBytes - (
dr_uint64)bytesToSeek;
6703 if (newPos > pOpenedFile->sizeInBytes) {
6707 pOpenedFile->readPointer = (size_t)newPos;
6715 drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file;
6716 assert(pOpenedFile !=
NULL);
6718 return pOpenedFile->readPointer;
6725 drfs_openedfile_zip* pOpenedFile = (drfs_openedfile_zip*)file;
6726 assert(pOpenedFile !=
NULL);
6728 return pOpenedFile->sizeInBytes;
6736 assert(archive !=
NULL);
6737 assert(file !=
NULL);
6743 static void drfs_register_zip_backend(
drfs_context* pContext)
6745 if (pContext ==
NULL) {
6761 callbacks.
open_file = drfs_open_file__zip;
6763 callbacks.
read_file = drfs_read_file__zip;
6765 callbacks.
seek_file = drfs_seek_file__zip;
6766 callbacks.
tell_file = drfs_tell_file__zip;
6767 callbacks.
file_size = drfs_file_size__zip;
6771 #endif //DR_FS_NO_ZIP
6780 #ifndef DR_FS_NO_PAK
6793 unsigned int offset;
6796 unsigned int sizeInBytes;
6810 unsigned int directoryOffset;
6813 unsigned int directoryLength;
6817 unsigned int accessMode;
6820 drfs_file_pak* pFiles;
6835 unsigned int processedDirCount;
6838 drfs_path_pak* pProcessedDirs;
6842 static dr_bool32 drfs_iterator_pak_append_processed_dir(drfs_iterator_pak* pIterator,
const char* path)
6844 if (pIterator !=
NULL && path !=
NULL)
6846 drfs_path_pak* pOldBuffer = pIterator->pProcessedDirs;
6847 drfs_path_pak* pNewBuffer = (drfs_path_pak*)malloc(
sizeof(drfs_path_pak) * (pIterator->processedDirCount + 1));
6849 if (pNewBuffer != 0)
6851 for (
unsigned int iDst = 0; iDst < pIterator->processedDirCount; ++iDst)
6853 pNewBuffer[iDst] = pOldBuffer[iDst];
6856 drfs__strcpy_s(pNewBuffer[pIterator->processedDirCount].path, 64, path);
6859 pIterator->pProcessedDirs = pNewBuffer;
6860 pIterator->processedDirCount += 1;
6871 static dr_bool32 drfs_iterator_pak_has_dir_been_processed(drfs_iterator_pak* pIterator,
const char* path)
6873 for (
unsigned int i = 0; i < pIterator->processedDirCount; ++i)
6875 if (strcmp(path, pIterator->pProcessedDirs[i].path) == 0)
6888 size_t offsetInArchive;
6896 }drfs_openedfile_pak;
6900 static drfs_archive_pak* drfs_pak_create(
drfs_file* pArchiveFile,
unsigned int accessMode)
6902 drfs_archive_pak* pak = (drfs_archive_pak*)malloc(
sizeof(*pak));
6905 pak->pArchiveFile = pArchiveFile;
6906 pak->directoryOffset = 0;
6907 pak->directoryLength = 0;
6908 pak->accessMode = accessMode;
6915 static void drfs_pak_delete(drfs_archive_pak* pArchive)
6917 free(pArchive->pFiles);
6924 static dr_bool32 drfs_is_valid_extension__pak(
const char* extension)
6926 return drfs__stricmp(extension,
"pak") == 0;
6932 assert(pArchiveFile !=
NULL);
6933 assert(pHandleOut !=
NULL);
6943 drfs_archive_pak* pak = drfs_pak_create(pArchiveFile, accessMode);
6949 if (pak->id[0] ==
'P' && pak->id[1] ==
'A' && pak->id[2] ==
'C' && pak->id[3] ==
'K')
6957 if (pak->directoryLength % 64 == 0)
6959 unsigned int fileCount = pak->directoryLength / 64;
6962 assert((
sizeof(drfs_file_pak) * fileCount) == pak->directoryLength);
6964 pak->pFiles = (drfs_file_pak*)malloc(pak->directoryLength);
6965 if (pak->pFiles !=
NULL)
6971 if (
drfs_read_nolock(pArchiveFile, pak->pFiles, pak->directoryLength, &bytesRead) ==
drfs_success && bytesRead == pak->directoryLength)
6978 drfs_pak_delete(pak);
6986 drfs_pak_delete(pak);
6994 drfs_pak_delete(pak);
7003 drfs_pak_delete(pak);
7011 drfs_pak_delete(pak);
7019 drfs_pak_delete(pak);
7027 drfs_pak_delete(pak);
7035 drfs_pak_delete(pak);
7046 static void drfs_close_archive__pak(
drfs_handle archive)
7048 drfs_archive_pak* pPak = (drfs_archive_pak*)archive;
7049 assert(pPak !=
NULL);
7051 drfs_pak_delete(pPak);
7058 drfs_archive_pak* pak = (drfs_archive_pak*)archive;
7059 assert(pak !=
NULL);
7061 unsigned int fileCount = pak->directoryLength / 64;
7062 for (
unsigned int i = 0; i < fileCount; ++i)
7064 drfs_file_pak* pFile = pak->pFiles + i;
7065 if (strcmp(pFile->name, relativePath) == 0)
7075 else if (drfs_drpath_is_descendant(pFile->name, relativePath))
7093 assert(relativePath !=
NULL);
7095 drfs_iterator_pak* pIterator = (drfs_iterator_pak*)malloc(
sizeof(drfs_iterator_pak));
7096 if (pIterator !=
NULL)
7098 pIterator->index = 0;
7099 drfs__strcpy_s(pIterator->directoryPath,
sizeof(pIterator->directoryPath), relativePath);
7100 pIterator->processedDirCount = 0;
7101 pIterator->pProcessedDirs =
NULL;
7111 drfs_iterator_pak* pIterator = (drfs_iterator_pak*)iterator;
7112 assert(pIterator !=
NULL);
7119 drfs_iterator_pak* pIterator = (drfs_iterator_pak*)iterator;
7120 assert(pIterator !=
NULL);
7122 drfs_archive_pak* pak = (drfs_archive_pak*)archive;
7123 assert(pak !=
NULL);
7125 unsigned int fileCount = pak->directoryLength / 64;
7126 while (pIterator->index < fileCount)
7128 unsigned int iFile = pIterator->index++;
7130 drfs_file_pak* pFile = pak->pFiles + iFile;
7131 if (drfs_drpath_is_child(pFile->name, pIterator->directoryPath))
7141 else if (drfs_drpath_is_descendant(pFile->name, pIterator->directoryPath))
7144 const char* childDirEnd = pFile->name + strlen(pIterator->directoryPath) + 1;
7145 while (childDirEnd[0] !=
'\0' && childDirEnd[0] !=
'/' && childDirEnd[0] !=
'\\')
7151 memcpy(childDir, pFile->name, childDirEnd - pFile->name);
7152 childDir[childDirEnd - pFile->name] =
'\0';
7154 if (!drfs_iterator_pak_has_dir_been_processed(pIterator, childDir))
7162 drfs_iterator_pak_append_processed_dir(pIterator, childDir);
7174 assert(relativePath !=
NULL);
7175 assert(pHandleOut !=
NULL);
7183 drfs_archive_pak* pak = (drfs_archive_pak*)archive;
7184 assert(pak !=
NULL);
7186 for (
unsigned int iFile = 0; iFile < (pak->directoryLength / 64); ++iFile)
7188 if (strcmp(relativePath, pak->pFiles[iFile].name) == 0)
7191 drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)malloc(
sizeof(*pOpenedFile));
7192 if (pOpenedFile !=
NULL)
7194 pOpenedFile->offsetInArchive = pak->pFiles[iFile].offset;
7195 pOpenedFile->sizeInBytes = pak->pFiles[iFile].sizeInBytes;
7196 pOpenedFile->readPointer = 0;
7198 *pHandleOut = pOpenedFile;
7212 drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file;
7213 assert(pOpenedFile !=
NULL);
7220 assert(pDataOut !=
NULL);
7221 assert(bytesToRead > 0);
7223 drfs_archive_pak* pak = (drfs_archive_pak*)archive;
7224 assert(pak !=
NULL);
7226 drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file;
7227 assert(pOpenedFile !=
NULL);
7230 assert(pOpenedFile->sizeInBytes >= pOpenedFile->readPointer);
7233 size_t bytesAvailable = pOpenedFile->sizeInBytes - pOpenedFile->readPointer;
7234 if (bytesAvailable < bytesToRead) {
7235 bytesToRead = bytesAvailable;
7245 pOpenedFile->readPointer += bytesToRead;
7259 assert(archive !=
NULL);
7260 assert(file !=
NULL);
7261 assert(pData !=
NULL);
7262 assert(bytesToWrite > 0);
7265 if (pBytesWrittenOut) {
7266 *pBytesWrittenOut = 0;
7276 drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file;
7277 assert(pOpenedFile !=
NULL);
7279 dr_uint64 newPos = pOpenedFile->readPointer;
7281 if ((
dr_int64)newPos + bytesToSeek >= 0) {
7287 assert(bytesToSeek >= 0);
7290 assert(bytesToSeek >= 0);
7291 if ((
dr_uint64)bytesToSeek <= pOpenedFile->sizeInBytes) {
7292 newPos = pOpenedFile->sizeInBytes - (
dr_uint64)bytesToSeek;
7301 if (newPos > pOpenedFile->sizeInBytes) {
7305 pOpenedFile->readPointer = (size_t)newPos;
7313 drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file;
7314 assert(pOpenedFile !=
NULL);
7316 return pOpenedFile->readPointer;
7323 drfs_openedfile_pak* pOpenedFile = (drfs_openedfile_pak*)file;
7324 assert(pOpenedFile !=
NULL);
7326 return pOpenedFile->sizeInBytes;
7334 assert(archive !=
NULL);
7335 assert(file !=
NULL);
7340 static void drfs_register_pak_backend(
drfs_context* pContext)
7342 if (pContext ==
NULL) {
7358 callbacks.
open_file = drfs_open_file__pak;
7360 callbacks.
read_file = drfs_read_file__pak;
7362 callbacks.
seek_file = drfs_seek_file__pak;
7363 callbacks.
tell_file = drfs_tell_file__pak;
7364 callbacks.
file_size = drfs_file_size__pak;
7368 #endif //DR_FS_NO_PAK
7377 #ifndef DR_FS_NO_MTL
7397 unsigned int accessMode;
7400 drfs_file_mtl* pFiles;
7403 unsigned int fileCount;
7425 }drfs_openedfile_mtl;
7428 static drfs_archive_mtl* drfs_mtl_create(
drfs_file* pArchiveFile,
unsigned int accessMode)
7430 drfs_archive_mtl* mtl = (drfs_archive_mtl*)malloc(
sizeof(drfs_archive_mtl));
7433 mtl->pArchiveFile = pArchiveFile;
7434 mtl->accessMode = accessMode;
7442 static void drfs_mtl_delete(drfs_archive_mtl* pArchive)
7444 free(pArchive->pFiles);
7448 static void drfs_mtl_addfile(drfs_archive_mtl* pArchive, drfs_file_mtl* pFile)
7450 if (pArchive !=
NULL && pFile !=
NULL)
7452 drfs_file_mtl* pOldBuffer = pArchive->pFiles;
7453 drfs_file_mtl* pNewBuffer = (drfs_file_mtl*)malloc(
sizeof(drfs_file_mtl) * (pArchive->fileCount + 1));
7455 if (pNewBuffer != 0)
7457 for (
unsigned int iDst = 0; iDst < pArchive->fileCount; ++iDst) {
7458 pNewBuffer[iDst] = pOldBuffer[iDst];
7461 pNewBuffer[pArchive->fileCount] = *pFile;
7463 pArchive->pFiles = pNewBuffer;
7464 pArchive->fileCount += 1;
7480 unsigned int chunkSize;
7482 }drfs_openarchive_mtl_state;
7484 static dr_bool32 drfs_mtl_loadnextchunk(drfs_openarchive_mtl_state* pState)
7486 assert(pState !=
NULL);
7488 if (pState->bytesRemaining > 0)
7490 pState->chunkSize = (pState->bytesRemaining > 4096) ? 4096 : (
unsigned int)pState->bytesRemaining;
7491 assert(pState->chunkSize);
7495 pState->bytesRemaining -= pState->chunkSize;
7496 pState->chunkPointer = pState->chunk;
7497 pState->chunkEnd = pState->chunk + pState->chunkSize;
7504 pState->bytesRemaining = 0;
7505 pState->chunkSize = 0;
7506 pState->chunkPointer = pState->chunk;
7507 pState->chunkEnd = pState->chunkPointer;
7514 static dr_bool32 drfs_mtl_loadnewmtl(drfs_openarchive_mtl_state* pState)
7516 assert(pState !=
NULL);
7518 const char newmtl[7] =
"newmtl";
7519 for (
unsigned int i = 0; i < 6; ++i)
7522 if (pState->chunkPointer >= pState->chunkEnd)
7524 if (!drfs_mtl_loadnextchunk(pState))
7531 if (pState->chunkPointer[0] != newmtl[i])
7536 pState->chunkPointer += 1;
7543 static dr_bool32 drfs_mtl_skipline(drfs_openarchive_mtl_state* pState)
7545 assert(pState !=
NULL);
7548 while (pState->chunkPointer < pState->chunkEnd)
7550 if (pState->chunkPointer[0] ==
'\n')
7553 pState->chunkPointer += 1;
7554 if (pState->chunkPointer >= pState->chunkEnd)
7556 return drfs_mtl_loadnextchunk(pState);
7562 pState->chunkPointer += 1;
7566 if (drfs_mtl_loadnextchunk(pState))
7568 return drfs_mtl_skipline(pState);
7574 static dr_bool32 drfs_mtl_skipwhitespace(drfs_openarchive_mtl_state* pState)
7576 assert(pState !=
NULL);
7578 while (pState->chunkPointer < pState->chunkEnd)
7580 const char c = pState->chunkPointer[0];
7581 if (c !=
' ' && c !=
'\t' && c !=
'\r' && c !=
'\n')
7586 pState->chunkPointer += 1;
7589 if (drfs_mtl_loadnextchunk(pState))
7591 return drfs_mtl_skipwhitespace(pState);
7597 static dr_bool32 drfs_mtl_loadmtlname(drfs_openarchive_mtl_state* pState,
void* dst,
unsigned int dstSizeInBytes)
7599 assert(pState !=
NULL);
7602 char* dst8 = (
char*)dst;
7603 while (dstSizeInBytes > 0 && pState->chunkPointer < pState->chunkEnd)
7605 const char c = pState->chunkPointer[0];
7606 if (c ==
' ' || c ==
'\t' || c ==
'\r' || c ==
'\n' || c ==
'#')
7615 dstSizeInBytes -= 1;
7616 pState->chunkPointer += 1;
7621 if (dstSizeInBytes > 0)
7624 assert(pState->chunkPointer == pState->chunkEnd);
7626 if (drfs_mtl_loadnextchunk(pState))
7628 return drfs_mtl_loadmtlname(pState, dst8, dstSizeInBytes);
7644 static dr_bool32 drfs_is_valid_extension__mtl(
const char* extension)
7646 return drfs__stricmp(extension,
"mtl") == 0;
7651 assert(pArchiveFile !=
NULL);
7652 assert(pHandleOut !=
NULL);
7661 drfs_archive_mtl* mtl = drfs_mtl_create(pArchiveFile, accessMode);
7669 drfs_openarchive_mtl_state state;
7670 state.pFile = pArchiveFile;
7672 state.bytesRemaining = state.archiveSizeInBytes;
7673 state.chunkSize = 0;
7674 state.chunkPointer = state.chunk;
7675 state.chunkEnd = state.chunk;
7676 if (drfs_mtl_loadnextchunk(&state))
7678 while (state.bytesRemaining > 0 || state.chunkPointer < state.chunkEnd)
7680 ptrdiff_t bytesRemainingInChunk = state.chunkEnd - state.chunkPointer;
7681 assert(bytesRemainingInChunk > 0);
7683 dr_uint64 newmtlOffset = state.archiveSizeInBytes - state.bytesRemaining - ((
dr_uint64)bytesRemainingInChunk);
7685 if (drfs_mtl_loadnewmtl(&state))
7687 if (state.chunkPointer[0] ==
' ' || state.chunkPointer[0] ==
'\t')
7690 if (drfs_mtl_skipwhitespace(&state))
7693 if (drfs_mtl_loadmtlname(&state, file.name, 256))
7697 file.offset = newmtlOffset;
7698 drfs_mtl_addfile(mtl, &file);
7705 drfs_mtl_skipline(&state);
7710 for (
unsigned int iFile = 0; iFile < mtl->fileCount; ++iFile)
7712 if (iFile < mtl->fileCount - 1)
7715 mtl->pFiles[iFile].sizeInBytes = mtl->pFiles[iFile + 1].offset - mtl->pFiles[iFile].offset;
7720 mtl->pFiles[iFile].sizeInBytes = state.archiveSizeInBytes - mtl->pFiles[iFile].offset;
7726 drfs_mtl_delete(mtl);
7736 static void drfs_close_archive__mtl(
drfs_handle archive)
7738 drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive;
7739 assert(mtl !=
NULL);
7741 drfs_mtl_delete(mtl);
7746 drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive;
7747 assert(mtl !=
NULL);
7749 for (
unsigned int iFile = 0; iFile < mtl->fileCount; ++iFile)
7751 if (strcmp(relativePath, mtl->pFiles[iFile].name) == 0)
7771 assert(relativePath !=
NULL);
7773 drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive;
7774 assert(mtl !=
NULL);
7776 if (mtl->fileCount > 0)
7778 if (relativePath[0] ==
'\0' || (relativePath[0] ==
'/' && relativePath[1] ==
'\0'))
7780 drfs_iterator_mtl* pIterator = (drfs_iterator_mtl*)malloc(
sizeof(*pIterator));
7781 if (pIterator !=
NULL)
7783 pIterator->index = 0;
7796 drfs_iterator_mtl* pIterator = (drfs_iterator_mtl*)iterator;
7802 drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive;
7803 assert(mtl !=
NULL);
7805 drfs_iterator_mtl* pIterator = (drfs_iterator_mtl*)iterator;
7806 assert(pIterator !=
NULL);
7808 if (pIterator->index < mtl->fileCount)
7813 fi->
sizeInBytes = mtl->pFiles[pIterator->index].sizeInBytes;
7818 pIterator->index += 1;
7827 assert(relativePath !=
NULL);
7828 assert(pHandleOut !=
NULL);
7837 drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive;
7838 assert(mtl !=
NULL);
7840 for (
unsigned int iFile = 0; iFile < mtl->fileCount; ++iFile)
7842 if (strcmp(relativePath, mtl->pFiles[iFile].name) == 0)
7845 drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)malloc(
sizeof(drfs_openedfile_mtl));
7846 if (pOpenedFile !=
NULL)
7848 pOpenedFile->offsetInArchive = mtl->pFiles[iFile].offset;
7849 pOpenedFile->sizeInBytes = mtl->pFiles[iFile].sizeInBytes;
7850 pOpenedFile->readPointer = 0;
7852 *pHandleOut = pOpenedFile;
7865 drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file;
7866 assert(pOpenedFile !=
NULL);
7873 assert(pDataOut !=
NULL);
7874 assert(bytesToRead > 0);
7876 drfs_archive_mtl* mtl = (drfs_archive_mtl*)archive;
7877 assert(mtl !=
NULL);
7879 drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file;
7880 assert(pOpenedFile !=
NULL);
7883 assert(pOpenedFile->sizeInBytes >= pOpenedFile->readPointer);
7885 dr_uint64 bytesAvailable = pOpenedFile->sizeInBytes - pOpenedFile->readPointer;
7886 if (bytesAvailable < bytesToRead) {
7887 bytesToRead = (size_t)bytesAvailable;
7897 pOpenedFile->readPointer += bytesToRead;
7910 assert(archive !=
NULL);
7911 assert(file !=
NULL);
7912 assert(pData !=
NULL);
7913 assert(bytesToWrite > 0);
7916 if (pBytesWrittenOut) {
7917 *pBytesWrittenOut = 0;
7927 drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file;
7928 assert(pOpenedFile !=
NULL);
7930 dr_uint64 newPos = pOpenedFile->readPointer;
7932 if ((
dr_int64)newPos + bytesToSeek >= 0) {
7938 assert(bytesToSeek >= 0);
7941 assert(bytesToSeek >= 0);
7942 if ((
dr_uint64)bytesToSeek <= pOpenedFile->sizeInBytes) {
7943 newPos = pOpenedFile->sizeInBytes - (
dr_uint64)bytesToSeek;
7952 if (newPos > pOpenedFile->sizeInBytes) {
7956 pOpenedFile->readPointer = newPos;
7964 drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file;
7965 assert(pOpenedFile !=
NULL);
7967 return pOpenedFile->readPointer;
7974 drfs_openedfile_mtl* pOpenedFile = (drfs_openedfile_mtl*)file;
7975 assert(pOpenedFile !=
NULL);
7977 return pOpenedFile->sizeInBytes;
7985 assert(archive !=
NULL);
7986 assert(file !=
NULL);
7992 static void drfs_register_mtl_backend(
drfs_context* pContext)
7994 if (pContext ==
NULL) {
8010 callbacks.
open_file = drfs_open_file__mtl;
8012 callbacks.
read_file = drfs_read_file__mtl;
8014 callbacks.
seek_file = drfs_seek_file__mtl;
8015 callbacks.
tell_file = drfs_tell_file__mtl;
8016 callbacks.
file_size = drfs_file_size__mtl;
8020 #endif //DR_FS_NO_MTL
8024 #endif //DR_FS_IMPLEMENTATION