home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / system / source / filesys.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  19.2 KB  |  664 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #include "stdafx.h"
  27. #include <ctype.h>
  28. #include <string.h>
  29.  
  30. #include <vd2/system/VDString.h>
  31. #include <vd2/system/filesys.h>
  32. #include <vd2/system/Error.h>
  33. #include <vd2/system/vdstl.h>
  34. #include <vd2/system/w32assist.h>
  35.  
  36. ///////////////////////////////////////////////////////////////////////////
  37.  
  38. template<class T, class U>
  39. static inline T splitimpL(const T& string, const U *s) {
  40.     const U *p = string.c_str();
  41.     return T(p, s - p);
  42. }
  43.  
  44. template<class T, class U>
  45. static inline T splitimpR(const T& string, const U *s) {
  46.     const U *p = string.c_str();
  47.     return T(s);
  48. }
  49.  
  50. ///////////////////////////////////////////////////////////////////////////
  51.  
  52. const char *VDFileSplitFirstDir(const char *s) {
  53.     const char *start = s;
  54.  
  55.     while(*s++)
  56.         if (s[-1] == ':' || s[-1] == '\\' || s[-1] == '/')
  57.             return s;
  58.  
  59.     return start;
  60. }
  61.  
  62. const wchar_t *VDFileSplitFirstDir(const wchar_t *s) {
  63.     const wchar_t *start = s;
  64.  
  65.     while(*s++)
  66.         if (s[-1] == L':' || s[-1] == L'\\' || s[-1] == L'/')
  67.             return s;
  68.  
  69.     return start;
  70. }
  71.  
  72. const char *VDFileSplitPath(const char *s) {
  73.     const char *lastsep = s;
  74.  
  75.     while(*s++)
  76.         if (s[-1] == ':' || s[-1] == '\\' || s[-1] == '/')
  77.             lastsep = s;
  78.  
  79.     return lastsep;
  80. }
  81.  
  82. const wchar_t *VDFileSplitPath(const wchar_t *s) {
  83.     const wchar_t *lastsep = s;
  84.  
  85.     while(*s++)
  86.         if (s[-1] == L':' || s[-1] == L'\\' || s[-1] == L'/')
  87.             lastsep = s;
  88.  
  89.     return lastsep;
  90. }
  91.  
  92. VDString  VDFileSplitPathLeft (const VDString&  s) { return splitimpL(s, VDFileSplitPath(s.c_str())); }
  93. VDStringW VDFileSplitPathLeft (const VDStringW& s) { return splitimpL(s, VDFileSplitPath(s.c_str())); }
  94. VDString  VDFileSplitPathRight(const VDString&  s) { return splitimpR(s, VDFileSplitPath(s.c_str())); }
  95. VDStringW VDFileSplitPathRight(const VDStringW& s) { return splitimpR(s, VDFileSplitPath(s.c_str())); }
  96.  
  97. const char *VDFileSplitRoot(const char *s) {
  98.     // Test for a UNC path.
  99.     if (s[0] == '\\' && s[1] == '\\') {
  100.         // For these, we scan for the fourth backslash.
  101.         s += 2;
  102.         for(int i=0; i<2; ++i) {
  103.             while(*s && *s != '\\')
  104.                 ++s;
  105.             if (*s == '\\')
  106.                 ++s;
  107.         }
  108.         return s;
  109.     }
  110.  
  111.     const char *const t = s;
  112.  
  113.     while(*s && *s != ':' && *s != '/' && *s != '\\')
  114.         ++s;
  115.  
  116.     return *s ? *s == ':' && (s[1]=='/' || s[1]=='\\') ? s+2 : s+1 : t;
  117. }
  118.  
  119. const wchar_t *VDFileSplitRoot(const wchar_t *s) {
  120.     // Test for a UNC path.
  121.     if (s[0] == '\\' && s[1] == '\\') {
  122.         // For these, we scan for the fourth backslash.
  123.         s += 2;
  124.         for(int i=0; i<2; ++i) {
  125.             while(*s && *s != '\\')
  126.                 ++s;
  127.             if (*s == '\\')
  128.                 ++s;
  129.         }
  130.         return s;
  131.     }
  132.  
  133.     const wchar_t *const t = s;
  134.  
  135.     while(*s && *s != L':' && *s != L'/' && *s != L'\\')
  136.         ++s;
  137.  
  138.     return *s ? *s == L':' && (s[1]==L'/' || s[1]==L'\\') ? s+2 : s+1 : t;
  139. }
  140.  
  141. VDString  VDFileSplitRoot(const VDString&  s) { return splitimpL(s, VDFileSplitRoot(s.c_str())); }
  142. VDStringW VDFileSplitRoot(const VDStringW& s) { return splitimpL(s, VDFileSplitRoot(s.c_str())); }
  143.  
  144. const char *VDFileSplitExt(const char *s) {
  145.     const char *t = s;
  146.  
  147.     while(*t)
  148.         ++t;
  149.  
  150.     const char *const end = t;
  151.  
  152.     while(t>s) {
  153.         --t;
  154.  
  155.         if (*t == '.')
  156.             return t;
  157.  
  158.         if (*t == ':' || *t == '\\' || *t == '/')
  159.             break;
  160.     }
  161.  
  162.     return NULL;
  163. }
  164.  
  165. const wchar_t *VDFileSplitExt(const wchar_t *s) {
  166.     const wchar_t *t = s;
  167.  
  168.     while(*t)
  169.         ++t;
  170.  
  171.     const wchar_t *const end = t;
  172.  
  173.     while(t>s) {
  174.         --t;
  175.  
  176.         if (*t == L'.')
  177.             return t;
  178.  
  179.         if (*t == L':' || *t == L'\\' || *t == L'/')
  180.             break;
  181.     }
  182.  
  183.     return end;
  184. }
  185.  
  186. VDString  VDFileSplitExtLeft (const VDString&  s) { return splitimpL(s, VDFileSplitExt(s.c_str())); }
  187. VDStringW VDFileSplitExtLeft (const VDStringW& s) { return splitimpL(s, VDFileSplitExt(s.c_str())); }
  188. VDString  VDFileSplitExtRight(const VDString&  s) { return splitimpR(s, VDFileSplitExt(s.c_str())); }
  189. VDStringW VDFileSplitExtRight(const VDStringW& s) { return splitimpR(s, VDFileSplitExt(s.c_str())); }
  190.  
  191. /////////////////////////////////////////////////////////////////////////////
  192.  
  193. bool VDFileWildMatch(const char *pattern, const char *path) {
  194.     // What we do here is split the string into segments that are bracketed
  195.     // by sequences of asterisks. The trick is that the first match for a
  196.     // segment as the best possible match, so we can continue. So we just
  197.     // take each segment at a time and walk it forward until we find the
  198.     // first match or we fail.
  199.     //
  200.     // Time complexity is O(NM), where N=length of string and M=length of
  201.     // the pattern. In practice, it's rather fast.
  202.  
  203.     bool star = false;
  204.     int i = 0;
  205.     for(;;) {
  206.         char c = (char)tolower((unsigned char)pattern[i]);
  207.         if (c == '*') {
  208.             star = true;
  209.             pattern += i+1;
  210.             if (!*pattern)
  211.                 return true;
  212.             path += i;
  213.             i = 0;
  214.             continue;
  215.         }
  216.  
  217.         char d = (char)tolower((unsigned char)path[i]);
  218.         ++i;
  219.  
  220.         if (c == '?') {        // ? matches any character but null.
  221.             if (!d)
  222.                 return false;
  223.         } else if (c != d) {    // Literal character must match itself.
  224.             // If we're at the end of the string or there is no
  225.             // previous asterisk (anchored search), there's no other
  226.             // match to find.
  227.             if (!star || !d || !i)
  228.                 return false;
  229.  
  230.             // Restart segment search at next position in path.
  231.             ++path;
  232.             i = 0;
  233.             continue;
  234.         }
  235.  
  236.         if (!c)
  237.             return true;
  238.     }
  239. }
  240.  
  241. bool VDFileWildMatch(const wchar_t *pattern, const wchar_t *path) {
  242.     // What we do here is split the string into segments that are bracketed
  243.     // by sequences of asterisks. The trick is that the first match for a
  244.     // segment as the best possible match, so we can continue. So we just
  245.     // take each segment at a time and walk it forward until we find the
  246.     // first match or we fail.
  247.     //
  248.     // Time complexity is O(NM), where N=length of string and M=length of
  249.     // the pattern. In practice, it's rather fast.
  250.  
  251.     bool star = false;
  252.     int i = 0;
  253.     for(;;) {
  254.         wchar_t c = towlower(pattern[i]);
  255.         if (c == L'*') {
  256.             star = true;
  257.             pattern += i+1;
  258.             if (!*pattern)
  259.                 return true;
  260.             path += i;
  261.             i = 0;
  262.             continue;
  263.         }
  264.  
  265.         wchar_t d = towlower(path[i]);
  266.         ++i;
  267.  
  268.         if (c == L'?') {        // ? matches any character but null.
  269.             if (!d)
  270.                 return false;
  271.         } else if (c != d) {    // Literal character must match itself.
  272.             // If we're at the end of the string or there is no
  273.             // previous asterisk (anchored search), there's no other
  274.             // match to find.
  275.             if (!star || !d || !i)
  276.                 return false;
  277.  
  278.             // Restart segment search at next position in path.
  279.             ++path;
  280.             i = 0;
  281.             continue;
  282.         }
  283.  
  284.         if (!c)
  285.             return true;
  286.     }
  287. }
  288.  
  289. /////////////////////////////////////////////////////////////////////////////
  290.  
  291. #include <windows.h>
  292. #include <vd2/system/w32assist.h>
  293.  
  294. sint64 VDGetDiskFreeSpace(const wchar_t *path) {
  295.     typedef BOOL (WINAPI *tpGetDiskFreeSpaceExA)(LPCSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailable, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes);
  296.     typedef BOOL (WINAPI *tpGetDiskFreeSpaceExW)(LPCWSTR lpDirectoryName, PULARGE_INTEGER lpFreeBytesAvailable, PULARGE_INTEGER lpTotalNumberOfBytes, PULARGE_INTEGER lpTotalNumberOfFreeBytes);
  297.  
  298.     static bool sbChecked = false;
  299.     static tpGetDiskFreeSpaceExA spGetDiskFreeSpaceExA;
  300.     static tpGetDiskFreeSpaceExW spGetDiskFreeSpaceExW;
  301.  
  302.     if (!sbChecked) {
  303.         HMODULE hmodKernel = GetModuleHandle("kernel32.dll");
  304.         spGetDiskFreeSpaceExA = (tpGetDiskFreeSpaceExA)GetProcAddress(hmodKernel, "GetDiskFreeSpaceExA");
  305.         spGetDiskFreeSpaceExW = (tpGetDiskFreeSpaceExW)GetProcAddress(hmodKernel, "GetDiskFreeSpaceExW");
  306.  
  307.         sbChecked = true;
  308.     }
  309.  
  310.     if (spGetDiskFreeSpaceExA) {
  311.         BOOL success;
  312.         uint64 freeClient, totalBytes, totalFreeBytes;
  313.         VDStringW directoryName(path);
  314.  
  315.         if (!directoryName.empty()) {
  316.             wchar_t c = directoryName[directoryName.length()-1];
  317.  
  318.             if (c != L'/' && c != L'\\')
  319.                 directoryName += L'\\';
  320.         }
  321.  
  322.         if ((LONG)GetVersion() < 0)
  323.             success = spGetDiskFreeSpaceExA(VDTextWToA(directoryName).c_str(), (PULARGE_INTEGER)&freeClient, (PULARGE_INTEGER)&totalBytes, (PULARGE_INTEGER)&totalFreeBytes);
  324.         else
  325.             success = spGetDiskFreeSpaceExW(directoryName.c_str(), (PULARGE_INTEGER)&freeClient, (PULARGE_INTEGER)&totalBytes, (PULARGE_INTEGER)&totalFreeBytes);
  326.  
  327.         return success ? (sint64)freeClient : -1;
  328.     } else {
  329.         DWORD sectorsPerCluster, bytesPerSector, freeClusters, totalClusters;
  330.         BOOL success;
  331.  
  332.         VDStringW rootPath(VDFileGetRootPath(path));
  333.  
  334.         if ((LONG)GetVersion() < 0)
  335.             success = GetDiskFreeSpaceA(rootPath.empty() ? NULL : VDTextWToA(rootPath).c_str(), §orsPerCluster, &bytesPerSector, &freeClusters, &totalClusters);
  336.         else
  337.             success = GetDiskFreeSpaceW(rootPath.empty() ? NULL : rootPath.c_str(), §orsPerCluster, &bytesPerSector, &freeClusters, &totalClusters);
  338.  
  339.         return success ? (sint64)((uint64)sectorsPerCluster * bytesPerSector * freeClusters) : -1;
  340.     }
  341. }
  342.  
  343. bool VDDoesPathExist(const wchar_t *fileName) {
  344.     bool bExists;
  345.  
  346.     if (!(GetVersion() & 0x80000000)) {
  347.         bExists = ((DWORD)-1 != GetFileAttributesW(fileName));
  348.     } else {
  349.         bExists = ((DWORD)-1 != GetFileAttributesA(VDTextWToA(fileName).c_str()));
  350.     }
  351.  
  352.     return bExists;
  353. }
  354.  
  355. void VDCreateDirectory(const wchar_t *path) {
  356.     // can't create dir with trailing slash
  357.     VDStringW::size_type l(wcslen(path));
  358.  
  359.     if (l) {
  360.         const wchar_t c = path[l-1];
  361.  
  362.         if (c == L'/' || c == L'\\') {
  363.             VDCreateDirectory(VDStringW(path, l-1).c_str());
  364.             return;
  365.         }
  366.     }
  367.  
  368.     BOOL succeeded;
  369.  
  370.     if (!(GetVersion() & 0x80000000)) {
  371.         succeeded = CreateDirectoryW(path, NULL);
  372.     } else {
  373.         succeeded = CreateDirectoryA(VDTextWToA(path).c_str(), NULL);
  374.     }
  375.  
  376.     if (!succeeded)
  377.         throw MyWin32Error("Cannot create directory: %%s", GetLastError());
  378. }
  379.  
  380. ///////////////////////////////////////////////////////////////////////////
  381.  
  382. bool VDDeletePathAutodetect(const wchar_t *path);
  383. bool (*VDRemoveFile)(const wchar_t *path) = VDDeletePathAutodetect;
  384.  
  385. namespace {
  386.     typedef BOOL (APIENTRY *tpDeleteFileW)(LPCWSTR path);
  387.     tpDeleteFileW spDeleteFileW;
  388. }
  389.  
  390. bool VDDeleteFile9x(const wchar_t *path) {
  391.     return !!DeleteFileA(VDTextWToA(path).c_str());
  392. }
  393.  
  394. bool VDDeleteFileNT(const wchar_t *path) {
  395.     return !!spDeleteFileW(path);
  396. }
  397.  
  398. bool VDDeletePathAutodetect(const wchar_t *path) {
  399.     if (VDIsWindowsNT()) {
  400.         spDeleteFileW = (tpDeleteFileW)GetProcAddress(GetModuleHandle("kernel32"), "DeleteFileW");
  401.         VDRemoveFile = VDDeleteFileNT;
  402.     } else
  403.         VDRemoveFile = VDDeleteFile9x;
  404.  
  405.     return VDRemoveFile(path);
  406. }
  407.  
  408. ///////////////////////////////////////////////////////////////////////////
  409.  
  410. namespace {
  411.     typedef BOOL (WINAPI *tpGetVolumePathNameW)(LPCWSTR lpszPathName, LPWSTR lpszVolumePathName, DWORD cchBufferLength);
  412.     typedef BOOL (WINAPI *tpGetFullPathNameW)(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart);
  413. }
  414.  
  415. uint64 VDFileGetLastWriteTime(const wchar_t *path) {
  416.     if (VDIsWindowsNT()) {
  417.         WIN32_FIND_DATAW fdw;
  418.         HANDLE h = FindFirstFileW(path, &fdw);
  419.         if (h == INVALID_HANDLE_VALUE)
  420.             return 0;
  421.  
  422.         FindClose(h);
  423.  
  424.         return ((uint64)fdw.ftLastWriteTime.dwHighDateTime << 32) + fdw.ftLastWriteTime.dwLowDateTime;
  425.     } else {
  426.         WIN32_FIND_DATAA fda;
  427.         HANDLE h = FindFirstFileA(VDTextWToA(path).c_str(), &fda);
  428.         if (h == INVALID_HANDLE_VALUE)
  429.             return 0;
  430.  
  431.         FindClose(h);
  432.  
  433.         return ((uint64)fda.ftLastWriteTime.dwHighDateTime << 32) + fda.ftLastWriteTime.dwLowDateTime;
  434.     }
  435. }
  436.  
  437. VDStringW VDFileGetRootPath(const wchar_t *path) {
  438.     static tpGetVolumePathNameW spGetVolumePathNameW = (tpGetVolumePathNameW)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetVolumePathNameW");
  439.     static tpGetFullPathNameW spGetFullPathNameW = (tpGetFullPathNameW)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFullPathNameW");
  440.  
  441.     VDStringW fullPath(VDGetFullPath(path));
  442.  
  443.     // Windows 2000/XP path
  444.     if (spGetVolumePathNameW) {
  445.         vdblock<wchar_t> buf(std::max<size_t>(fullPath.size() + 1, MAX_PATH));
  446.  
  447.         if (spGetVolumePathNameW(path, buf.data(), buf.size()))
  448.             return VDStringW(buf.data());
  449.     }
  450.  
  451.     // Windows 95/98/ME/NT4 path
  452.     const wchar_t *s = fullPath.c_str();
  453.     VDStringW root(s, VDFileSplitRoot(s) - s);
  454.     VDFileFixDirPath(root);
  455.     return root;
  456. }
  457.  
  458. VDStringW VDGetFullPath(const wchar_t *partialPath) {
  459.     static tpGetFullPathNameW spGetFullPathNameW = (tpGetFullPathNameW)GetProcAddress(GetModuleHandle("kernel32.dll"), "GetFullPathNameW");
  460.  
  461.     union {
  462.         char        a[MAX_PATH];
  463.         wchar_t        w[MAX_PATH];
  464.     } tmpBuf;
  465.  
  466.     if (spGetFullPathNameW && !(GetVersion() & 0x80000000)) {
  467.         LPWSTR p;
  468.  
  469.         tmpBuf.w[0] = 0;
  470.         DWORD count = spGetFullPathNameW(partialPath, MAX_PATH, tmpBuf.w, &p);
  471.  
  472.         if (count < MAX_PATH)
  473.             return VDStringW(tmpBuf.w);
  474.  
  475.         VDStringW tmp(count);
  476.  
  477.         DWORD newCount = spGetFullPathNameW(partialPath, count, (wchar_t *)tmp.data(), &p);
  478.         if (newCount < count)
  479.             return tmp;
  480.  
  481.         return VDStringW(partialPath);
  482.     } else {
  483.         LPSTR p;
  484.         VDStringA pathA(VDTextWToA(partialPath));
  485.  
  486.         tmpBuf.a[0] = 0;
  487.         DWORD count = GetFullPathNameA(pathA.c_str(), MAX_PATH, tmpBuf.a, &p);
  488.  
  489.         if (count < MAX_PATH)
  490.             return VDStringW(VDTextAToW(tmpBuf.a));
  491.  
  492.         VDStringA tmpA(count);
  493.  
  494.         DWORD newCount = GetFullPathNameA(pathA.c_str(), count, (char *)tmpA.data(), &p);
  495.         if (newCount < count)
  496.             return VDTextAToW(tmpA);
  497.  
  498.         return VDStringW(partialPath);
  499.     }
  500. }
  501.  
  502. VDStringW VDMakePath(const wchar_t *base, const wchar_t *file) {
  503.     if (!*base)
  504.         return VDStringW(file);
  505.  
  506.     VDStringW result(base);
  507.  
  508.     const wchar_t c = result[result.size() - 1];
  509.  
  510.     if (c != L'/' && c != L'\\' && c != L':')
  511.         result += L'\\';
  512.  
  513.     result.append(file);
  514.  
  515.     return result;
  516. }
  517.  
  518. void VDFileFixDirPath(VDStringW& path) {
  519.     if (!path.empty()) {
  520.         wchar_t c = path[path.size()-1];
  521.  
  522.         if (c != L'/' && c != L'\\' && c != L':')
  523.             path += L'\\';
  524.     }
  525. }
  526.  
  527. namespace {
  528.     VDStringW VDGetModulePathW32(HINSTANCE hInst) {
  529.         union {
  530.             wchar_t w[MAX_PATH];
  531.             char a[MAX_PATH];
  532.         } buf;
  533.  
  534.         VDStringW wstr;
  535.  
  536.         if (VDIsWindowsNT()) {
  537.             wcscpy(buf.w, L".");
  538.             if (GetModuleFileNameW(hInst, buf.w, MAX_PATH))
  539.                 *VDFileSplitPath(buf.w) = 0;
  540.             wstr = buf.w;
  541.         } else {
  542.             strcpy(buf.a, ".");
  543.             if (GetModuleFileNameA(hInst, buf.a, MAX_PATH))
  544.                 *VDFileSplitPath(buf.a) = 0;
  545.             wstr = VDTextAToW(buf.a, -1);
  546.         }
  547.  
  548.         VDStringW wstr2(VDGetFullPath(wstr.c_str()));
  549.  
  550.         return wstr2;
  551.     }
  552. }
  553.  
  554. VDStringW VDGetLocalModulePath() {
  555.     return VDGetModulePathW32(VDGetLocalModuleHandleW32());
  556. }
  557.  
  558. VDStringW VDGetProgramPath() {
  559.     return VDGetModulePathW32(NULL);
  560. }
  561.  
  562. ///////////////////////////////////////////////////////////////////////////
  563.  
  564. VDDirectoryIterator::VDDirectoryIterator(const wchar_t *path)
  565.     : mSearchPath(path)
  566.     , mpHandle(NULL)
  567.     , mbSearchComplete(false)
  568. {
  569.     mBasePath = VDFileSplitPathLeft(mSearchPath);
  570.     VDFileFixDirPath(mBasePath);
  571. }
  572.  
  573. VDDirectoryIterator::~VDDirectoryIterator() {
  574.     if (mpHandle)
  575.         FindClose((HANDLE)mpHandle);
  576. }
  577.  
  578. bool VDDirectoryIterator::Next() {
  579.     if (mbSearchComplete)
  580.         return false;
  581.  
  582.     union {
  583.         WIN32_FIND_DATAA a;
  584.         WIN32_FIND_DATAW w;
  585.     } wfd;
  586.  
  587.     if (GetVersion() & 0x80000000) {
  588.         if (mpHandle)
  589.             mbSearchComplete = !FindNextFileA((HANDLE)mpHandle, &wfd.a);
  590.         else {
  591.             mpHandle = FindFirstFileA(VDTextWToA(mSearchPath).c_str(), &wfd.a);
  592.             mbSearchComplete = (INVALID_HANDLE_VALUE == mpHandle);
  593.         }
  594.         if (mbSearchComplete)
  595.             return false;
  596.  
  597.         mbDirectory = (wfd.a.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  598.         mFilename = VDTextAToW(wfd.a.cFileName);
  599.         mFileSize = wfd.a.nFileSizeLow + ((sint64)wfd.w.nFileSizeHigh << 32);
  600.     } else {
  601.         if (mpHandle)
  602.             mbSearchComplete = !FindNextFileW((HANDLE)mpHandle, &wfd.w);
  603.         else {
  604.             mpHandle = FindFirstFileW(mSearchPath.c_str(), &wfd.w);
  605.             mbSearchComplete = (INVALID_HANDLE_VALUE == mpHandle);
  606.         }
  607.         if (mbSearchComplete)
  608.             return false;
  609.  
  610.         mbDirectory = (wfd.w.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
  611.         mFilename = wfd.w.cFileName;
  612.         mFileSize = wfd.w.nFileSizeLow + ((sint64)wfd.w.nFileSizeHigh << 32);
  613.     }
  614.  
  615.     return true;
  616. }
  617.  
  618. ///////////////////////////////////////////////////////////////////////////
  619.  
  620. #ifdef _DEBUG
  621.  
  622. struct VDSystemFilesysTestObject {
  623.     VDSystemFilesysTestObject() {
  624. #define TEST(fn, x, y1, y2) VDASSERT(!strcmp(fn(x), y2)); VDASSERT(!wcscmp(fn(L##x), L##y2)); VDASSERT(fn##Left(VDStringA(x))==y1); VDASSERT(fn##Right(VDStringA(x))==y2); VDASSERT(fn##Left(VDStringW(L##x))==L##y1); VDASSERT(fn##Right(VDStringW(L##x))==L##y2)
  625.         TEST(VDFileSplitPath, "", "", "");
  626.         TEST(VDFileSplitPath, "x", "", "x");
  627.         TEST(VDFileSplitPath, "x\\y", "x\\", "y");
  628.         TEST(VDFileSplitPath, "x\\y\\z", "x\\y\\", "z");
  629.         TEST(VDFileSplitPath, "x\\", "x\\", "");
  630.         TEST(VDFileSplitPath, "x\\y\\z\\", "x\\y\\z\\", "");
  631.         TEST(VDFileSplitPath, "c:", "c:", "");
  632.         TEST(VDFileSplitPath, "c:x", "c:", "x");
  633.         TEST(VDFileSplitPath, "c:\\", "c:\\", "");
  634.         TEST(VDFileSplitPath, "c:\\x", "c:\\", "x");
  635.         TEST(VDFileSplitPath, "c:\\x\\", "c:\\x\\", "");
  636.         TEST(VDFileSplitPath, "c:\\x\\", "c:\\x\\", "");
  637.         TEST(VDFileSplitPath, "c:x\\y", "c:x\\", "y");
  638.         TEST(VDFileSplitPath, "\\\\server\\share\\", "\\\\server\\share\\", "");
  639.         TEST(VDFileSplitPath, "\\\\server\\share\\x", "\\\\server\\share\\", "x");
  640. #undef TEST
  641. #define TEST(fn, x, y1, y2) VDASSERT(!strcmp(fn(x), y2)); VDASSERT(!wcscmp(fn(L##x), L##y2)); VDASSERT(fn(VDStringA(x))==y1); VDASSERT(fn(VDStringW(L##x))==L##y1)
  642.         TEST(VDFileSplitRoot, "", "", "");
  643.         TEST(VDFileSplitRoot, "c:", "c:", "");
  644.         TEST(VDFileSplitRoot, "c:x", "c:", "x");
  645.         TEST(VDFileSplitRoot, "c:x\\", "c:", "x\\");
  646.         TEST(VDFileSplitRoot, "c:x\\y", "c:", "x\\y");
  647.         TEST(VDFileSplitRoot, "c:\\", "c:\\", "");
  648.         TEST(VDFileSplitRoot, "c:\\x", "c:\\", "x");
  649.         TEST(VDFileSplitRoot, "c:\\x\\", "c:\\", "x\\");
  650.         TEST(VDFileSplitRoot, "\\", "\\", "");
  651.         TEST(VDFileSplitRoot, "\\x", "\\", "x");
  652.         TEST(VDFileSplitRoot, "\\x\\", "\\", "x\\");
  653.         TEST(VDFileSplitRoot, "\\x\\y", "\\", "x\\y");
  654.         TEST(VDFileSplitRoot, "\\\\server\\share", "\\\\server\\share", "");
  655.         TEST(VDFileSplitRoot, "\\\\server\\share\\", "\\\\server\\share\\", "");
  656.         TEST(VDFileSplitRoot, "\\\\server\\share\\x", "\\\\server\\share\\", "x");
  657.         TEST(VDFileSplitRoot, "\\\\server\\share\\x\\", "\\\\server\\share\\", "x\\");
  658.         TEST(VDFileSplitRoot, "\\\\server\\share\\x\\y", "\\\\server\\share\\", "x\\y");
  659. #undef TEST
  660.     }
  661. } g_VDSystemFilesysTestObject;
  662.  
  663. #endif
  664.