#ifndef ___VDir_H___
#define ___VDir_H___
const
int
driveCount = (
'Z'
-
'A'
)+1+1;
const
int
driveLetterCount = (
'Z'
-
'A'
)+1;
class
VDir
{
public
:
VDir(
int
bManageDir = 1);
~VDir() {};
void
Init(VDir* pDir, VMem *pMem);
void
SetDefaultA(
char
const
*pDefault);
void
SetDefaultW(
WCHAR
const
*pDefault);
char
* MapPathA(
const
char
*pInName);
WCHAR
* MapPathW(
const
WCHAR
*pInName);
int
SetCurrentDirectoryA(
char
*lpBuffer);
int
SetCurrentDirectoryW(
WCHAR
*lpBuffer);
inline
int
GetDefault(
void
) {
return
nDefault; };
inline
char
* GetCurrentDirectoryA(
int
dwBufSize,
char
*lpBuffer)
{
char
* ptr = dirTableA[nDefault];
while
(--dwBufSize)
{
if
((*lpBuffer++ = *ptr++) ==
'\0'
)
break
;
}
*lpBuffer =
'\0'
;
return
NULL;
};
inline
WCHAR
* GetCurrentDirectoryW(
int
dwBufSize,
WCHAR
*lpBuffer)
{
WCHAR
* ptr = dirTableW[nDefault];
while
(--dwBufSize)
{
if
((*lpBuffer++ = *ptr++) ==
'\0'
)
break
;
}
*lpBuffer =
'\0'
;
return
NULL;
};
DWORD
CalculateEnvironmentSpace(
void
);
LPSTR
BuildEnvironmentSpace(
LPSTR
lpStr);
protected
:
int
SetDirA(
char
const
*pPath,
int
index);
int
SetDirW(
WCHAR
const
*pPath,
int
index);
void
FromEnvA(
char
*pEnv,
int
index);
void
FromEnvW(
WCHAR
*pEnv,
int
index);
inline
const
char
*GetDefaultDirA(
void
)
{
return
dirTableA[nDefault];
};
inline
void
SetDefaultDirA(
char
const
*pPath,
int
index)
{
SetDirA(pPath, index);
nDefault = index;
};
inline
const
WCHAR
*GetDefaultDirW(
void
)
{
return
dirTableW[nDefault];
};
inline
void
SetDefaultDirW(
WCHAR
const
*pPath,
int
index)
{
SetDirW(pPath, index);
nDefault = index;
};
inline
const
char
*GetDirA(
int
index)
{
char
*ptr = dirTableA[index];
if
(!ptr) {
ptr = szLocalBufferA;
ptr[0] =
'A'
+ index;
ptr[1] =
':'
;
ptr[2] =
'\\'
;
ptr[3] = 0;
}
return
ptr;
};
inline
const
WCHAR
*GetDirW(
int
index)
{
WCHAR
*ptr = dirTableW[index];
if
(!ptr) {
ptr = szLocalBufferW;
ptr[0] =
'A'
+ index;
ptr[1] =
':'
;
ptr[2] =
'\\'
;
ptr[3] = 0;
}
return
ptr;
};
inline
int
DriveIndex(
char
chr)
{
if
(chr ==
'\\'
|| chr ==
'/'
)
return
(
'Z'
-
'A'
)+1;
return
(chr | 0x20)-
'a'
;
};
VMem *pMem;
int
nDefault, bManageDirectory;
char
*dirTableA[driveCount];
char
szLocalBufferA[MAX_PATH+1];
WCHAR
*dirTableW[driveCount];
WCHAR
szLocalBufferW[MAX_PATH+1];
};
VDir::VDir(
int
bManageDir
)
{
nDefault = 0;
bManageDirectory = bManageDir;
memset
(dirTableA, 0,
sizeof
(dirTableA));
memset
(dirTableW, 0,
sizeof
(dirTableW));
}
void
VDir::Init(VDir* pDir, VMem *p)
{
int
index;
pMem = p;
if
(pDir) {
for
(index = 0; index < driveCount; ++index) {
SetDirW(pDir->GetDirW(index), index);
}
nDefault = pDir->GetDefault();
}
else
{
int
bSave = bManageDirectory;
DWORD
driveBits = GetLogicalDrives();
bManageDirectory = 0;
WCHAR
szBuffer[MAX_PATH*driveCount];
if
(GetLogicalDriveStringsW(
sizeof
(szBuffer), szBuffer)) {
WCHAR
* pEnv = GetEnvironmentStringsW();
WCHAR
* ptr = szBuffer;
for
(index = 0; index < driveCount; ++index) {
if
(driveBits & (1<<index)) {
ptr += SetDirW(ptr, index) + 1;
FromEnvW(pEnv, index);
}
}
FreeEnvironmentStringsW(pEnv);
}
SetDefaultW(L
"."
);
bManageDirectory = bSave;
}
}
int
VDir::SetDirA(
char
const
*pPath,
int
index)
{
char
chr, *ptr;
int
length = 0;
WCHAR
wBuffer[MAX_PATH+1];
if
(index < driveCount && pPath != NULL) {
length =
strlen
(pPath);
pMem->Free(dirTableA[index]);
ptr = dirTableA[index] = (
char
*)pMem->Malloc(length+2);
if
(ptr != NULL) {
strcpy
(ptr, pPath);
ptr += length-1;
chr = *ptr++;
if
(chr !=
'\\'
&& chr !=
'/'
) {
*ptr++ =
'\\'
;
*ptr =
'\0'
;
}
MultiByteToWideChar(CP_ACP, 0, dirTableA[index], -1,
wBuffer, (
sizeof
(wBuffer)/
sizeof
(
WCHAR
)));
length = wcslen(wBuffer);
pMem->Free(dirTableW[index]);
dirTableW[index] = (
WCHAR
*)pMem->Malloc((length+1)*2);
if
(dirTableW[index] != NULL) {
wcscpy(dirTableW[index], wBuffer);
}
}
}
if
(bManageDirectory)
::SetCurrentDirectoryA(pPath);
return
length;
}
void
VDir::FromEnvA(
char
*pEnv,
int
index)
{
while
(*pEnv !=
'\0'
) {
if
((pEnv[0] ==
'='
) && (DriveIndex(pEnv[1]) == index)
&& pEnv[2] ==
':'
&& pEnv[3] ==
'='
) {
SetDirA(&pEnv[4], index);
break
;
}
else
pEnv +=
strlen
(pEnv)+1;
}
}
void
VDir::FromEnvW(
WCHAR
*pEnv,
int
index)
{
while
(*pEnv !=
'\0'
) {
if
((pEnv[0] ==
'='
) && (DriveIndex((
char
)pEnv[1]) == index)
&& pEnv[2] ==
':'
&& pEnv[3] ==
'='
) {
SetDirW(&pEnv[4], index);
break
;
}
else
pEnv += wcslen(pEnv)+1;
}
}
void
VDir::SetDefaultA(
char
const
*pDefault)
{
char
szBuffer[MAX_PATH+1];
char
*pPtr;
if
(GetFullPathNameA(pDefault,
sizeof
(szBuffer), szBuffer, &pPtr)) {
if
(*pDefault !=
'.'
&& pPtr != NULL)
*pPtr =
'\0'
;
SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
}
}
int
VDir::SetDirW(
WCHAR
const
*pPath,
int
index)
{
WCHAR
chr, *ptr;
int
length = 0;
if
(index < driveCount && pPath != NULL) {
length = wcslen(pPath);
pMem->Free(dirTableW[index]);
ptr = dirTableW[index] = (
WCHAR
*)pMem->Malloc((length+2)*2);
if
(ptr != NULL) {
char
*ansi;
wcscpy(ptr, pPath);
ptr += length-1;
chr = *ptr++;
if
(chr !=
'\\'
&& chr !=
'/'
) {
*ptr++ =
'\\'
;
*ptr =
'\0'
;
}
ansi = win32_ansipath(dirTableW[index]);
length =
strlen
(ansi);
pMem->Free(dirTableA[index]);
dirTableA[index] = (
char
*)pMem->Malloc(length+1);
if
(dirTableA[index] != NULL) {
strcpy
(dirTableA[index], ansi);
}
win32_free(ansi);
}
}
if
(bManageDirectory)
::SetCurrentDirectoryW(pPath);
return
length;
}
void
VDir::SetDefaultW(
WCHAR
const
*pDefault)
{
WCHAR
szBuffer[MAX_PATH+1];
WCHAR
*pPtr;
if
(GetFullPathNameW(pDefault, (
sizeof
(szBuffer)/
sizeof
(
WCHAR
)), szBuffer, &pPtr)) {
if
(*pDefault !=
'.'
&& pPtr != NULL)
*pPtr =
'\0'
;
SetDefaultDirW(szBuffer, DriveIndex((
char
)szBuffer[0]));
}
}
inline
BOOL
IsPathSep(
char
ch)
{
return
(ch ==
'\\'
|| ch ==
'/'
);
}
inline
void
DoGetFullPathNameA(
char
* lpBuffer,
DWORD
dwSize,
char
* Dest)
{
char
*pPtr;
*Dest =
'\0'
;
GetFullPathNameA(lpBuffer, dwSize, Dest, &pPtr);
}
inline
bool
IsSpecialFileName(
const
char
* pName)
{
char
ch = (pName[0] & ~0x20);
switch
(ch)
{
case
'A'
:
if
(((pName[1] & ~0x20) ==
'U'
)
&& ((pName[2] & ~0x20) ==
'X'
)
&& !pName[3])
return
true
;
break
;
case
'C'
:
ch = (pName[1] & ~0x20);
switch
(ch)
{
case
'L'
:
if
(((pName[2] & ~0x20) ==
'O'
)
&& ((pName[3] & ~0x20) ==
'C'
)
&& ((pName[4] & ~0x20) ==
'K'
)
&& (pName[5] ==
'$'
)
&& !pName[6])
return
true
;
break
;
case
'O'
:
if
((pName[2] & ~0x20) ==
'M'
) {
if
( inRANGE(pName[3],
'1'
,
'9'
)
&& !pName[4])
return
true
;
}
else
if
((pName[2] & ~0x20) ==
'N'
) {
if
(!pName[3])
return
true
;
else
if
((pName[3] & ~0x20) ==
'I'
) {
if
(((pName[4] & ~0x20) ==
'N'
)
&& (pName[5] ==
'$'
)
&& !pName[6])
return
true
;
}
else
if
((pName[3] & ~0x20) ==
'O'
) {
if
(((pName[4] & ~0x20) ==
'U'
)
&& ((pName[5] & ~0x20) ==
'T'
)
&& (pName[6] ==
'$'
)
&& !pName[7])
return
true
;
}
}
break
;
}
break
;
case
'L'
:
if
(((pName[1] & ~0x20) ==
'U'
)
&& ((pName[2] & ~0x20) ==
'X'
)
&& inRANGE(pName[3],
'1'
,
'9'
)
&& !pName[4])
return
true
;
break
;
case
'N'
:
if
(((pName[1] & ~0x20) ==
'U'
)
&& ((pName[2] & ~0x20) ==
'L'
)
&& !pName[3])
return
true
;
break
;
case
'P'
:
if
(((pName[1] & ~0x20) ==
'R'
)
&& ((pName[2] & ~0x20) ==
'N'
)
&& !pName[3])
return
true
;
break
;
}
return
false
;
}
char
*VDir::MapPathA(
const
char
*pInName)
{
int
driveIndex;
char
szBuffer[(MAX_PATH+1)*2];
char
szlBuf[MAX_PATH+1];
int
length =
strlen
(pInName);
if
(!length)
return
(
char
*)pInName;
if
(length > MAX_PATH) {
strncpy
(szlBuf, pInName, MAX_PATH);
if
(IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
szlBuf[MAX_PATH-2] =
'\0'
;
}
else
szlBuf[MAX_PATH] =
'\0'
;
pInName = szlBuf;
}
if
(length > 1 && pInName[1] ==
':'
) {
if
(length > 2 && IsPathSep(pInName[2])) {
DoGetFullPathNameA((
char
*)pInName,
sizeof
(szLocalBufferA), szLocalBufferA);
}
else
{
driveIndex = DriveIndex(*pInName);
if
(driveIndex < 0 || driveIndex >= driveLetterCount)
return
(
char
*)pInName;
strcpy
(szBuffer, GetDirA(driveIndex));
strcat
(szBuffer, &pInName[2]);
if
(
strlen
(szBuffer) > MAX_PATH)
szBuffer[MAX_PATH] =
'\0'
;
DoGetFullPathNameA(szBuffer,
sizeof
(szLocalBufferA), szLocalBufferA);
}
}
else
{
if
(length > 1 && IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
DoGetFullPathNameA((
char
*)pInName,
sizeof
(szLocalBufferA), szLocalBufferA);
}
else
{
strcpy
(szBuffer, GetDefaultDirA());
if
(IsPathSep(pInName[0])) {
strcpy
(&szBuffer[2], pInName);
DoGetFullPathNameA(szBuffer,
sizeof
(szLocalBufferA), szLocalBufferA);
}
else
{
if
(IsSpecialFileName(pInName)) {
return
(
char
*)pInName;
}
else
{
strcat
(szBuffer, pInName);
if
(
strlen
(szBuffer) > MAX_PATH)
szBuffer[MAX_PATH] =
'\0'
;
DoGetFullPathNameA(szBuffer,
sizeof
(szLocalBufferA), szLocalBufferA);
}
}
}
}
return
szLocalBufferA;
}
int
VDir::SetCurrentDirectoryA(
char
*lpBuffer)
{
char
*pPtr;
int
length, nRet = -1;
pPtr = MapPathA(lpBuffer);
length =
strlen
(pPtr);
if
(length > 3 && IsPathSep(pPtr[length-1])) {
pPtr[length-1] =
'\0'
;
}
DWORD
r = GetFileAttributesA(pPtr);
if
((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY))
{
char
szBuffer[(MAX_PATH+1)*2];
DoGetFullPathNameA(pPtr,
sizeof
(szBuffer), szBuffer);
SetDefaultDirA(szBuffer, DriveIndex(szBuffer[0]));
nRet = 0;
}
return
nRet;
}
DWORD
VDir::CalculateEnvironmentSpace(
void
)
{
int
index;
DWORD
dwSize = 0;
for
(index = 0; index < driveCount; ++index) {
if
(dirTableA[index] != NULL) {
dwSize +=
strlen
(dirTableA[index]) + 5;
}
}
return
dwSize;
}
LPSTR
VDir::BuildEnvironmentSpace(
LPSTR
lpStr)
{
int
index, length;
LPSTR
lpDirStr;
for
(index = 0; index < driveCount; ++index) {
lpDirStr = dirTableA[index];
if
(lpDirStr != NULL) {
lpStr[0] =
'='
;
lpStr[1] = lpDirStr[0];
lpStr[2] =
'\0'
;
CharUpper(&lpStr[1]);
lpStr[2] =
':'
;
lpStr[3] =
'='
;
strcpy
(&lpStr[4], lpDirStr);
length =
strlen
(lpDirStr);
lpStr += length + 5;
if
(length > 3 && IsPathSep(lpStr[-2])) {
lpStr[-2] =
'\0'
;
--lpStr;
}
}
}
return
lpStr;
}
inline
BOOL
IsPathSep(
WCHAR
ch)
{
return
(ch ==
'\\'
|| ch ==
'/'
);
}
inline
void
DoGetFullPathNameW(
WCHAR
* lpBuffer,
DWORD
dwSize,
WCHAR
* Dest)
{
WCHAR
*pPtr;
*Dest =
'\0'
;
GetFullPathNameW(lpBuffer, dwSize, Dest, &pPtr);
}
inline
bool
IsSpecialFileName(
const
WCHAR
* pName)
{
WCHAR
ch = (pName[0] & ~0x20);
switch
(ch)
{
case
'A'
:
if
(((pName[1] & ~0x20) ==
'U'
)
&& ((pName[2] & ~0x20) ==
'X'
)
&& !pName[3])
return
true
;
break
;
case
'C'
:
ch = (pName[1] & ~0x20);
switch
(ch)
{
case
'L'
:
if
(((pName[2] & ~0x20) ==
'O'
)
&& ((pName[3] & ~0x20) ==
'C'
)
&& ((pName[4] & ~0x20) ==
'K'
)
&& (pName[5] ==
'$'
)
&& !pName[6])
return
true
;
break
;
case
'O'
:
if
((pName[2] & ~0x20) ==
'M'
) {
if
( inRANGE(pName[3],
'1'
,
'9'
)
&& !pName[4])
return
true
;
}
else
if
((pName[2] & ~0x20) ==
'N'
) {
if
(!pName[3])
return
true
;
else
if
((pName[3] & ~0x20) ==
'I'
) {
if
(((pName[4] & ~0x20) ==
'N'
)
&& (pName[5] ==
'$'
)
&& !pName[6])
return
true
;
}
else
if
((pName[3] & ~0x20) ==
'O'
) {
if
(((pName[4] & ~0x20) ==
'U'
)
&& ((pName[5] & ~0x20) ==
'T'
)
&& (pName[6] ==
'$'
)
&& !pName[7])
return
true
;
}
}
break
;
}
break
;
case
'L'
:
if
(((pName[1] & ~0x20) ==
'U'
)
&& ((pName[2] & ~0x20) ==
'X'
)
&& inRANGE(pName[3],
'1'
,
'9'
)
&& !pName[4])
return
true
;
break
;
case
'N'
:
if
(((pName[1] & ~0x20) ==
'U'
)
&& ((pName[2] & ~0x20) ==
'L'
)
&& !pName[3])
return
true
;
break
;
case
'P'
:
if
(((pName[1] & ~0x20) ==
'R'
)
&& ((pName[2] & ~0x20) ==
'N'
)
&& !pName[3])
return
true
;
break
;
}
return
false
;
}
WCHAR
* VDir::MapPathW(
const
WCHAR
*pInName)
{
int
driveIndex;
WCHAR
szBuffer[(MAX_PATH+1)*2];
WCHAR
szlBuf[MAX_PATH+1];
int
length = wcslen(pInName);
if
(!length)
return
(
WCHAR
*)pInName;
if
(length > MAX_PATH) {
wcsncpy(szlBuf, pInName, MAX_PATH);
if
(IsPathSep(pInName[0]) && !IsPathSep(pInName[1])) {
szlBuf[MAX_PATH-2] =
'\0'
;
}
else
szlBuf[MAX_PATH] =
'\0'
;
pInName = szlBuf;
}
if
(length > 1 && pInName[1] ==
':'
) {
if
(IsPathSep(pInName[2])) {
DoGetFullPathNameW((
WCHAR
*)pInName, (
sizeof
(szLocalBufferW)/
sizeof
(
WCHAR
)), szLocalBufferW);
}
else
{
driveIndex = DriveIndex(*pInName);
if
(driveIndex < 0 || driveIndex >= driveLetterCount)
return
(
WCHAR
*)pInName;
wcscpy(szBuffer, GetDirW(driveIndex));
wcscat(szBuffer, &pInName[2]);
if
(wcslen(szBuffer) > MAX_PATH)
szBuffer[MAX_PATH] =
'\0'
;
DoGetFullPathNameW(szBuffer, (
sizeof
(szLocalBufferW)/
sizeof
(
WCHAR
)), szLocalBufferW);
}
}
else
{
if
(length > 1 && IsPathSep(pInName[1]) && IsPathSep(pInName[0])) {
DoGetFullPathNameW((
WCHAR
*)pInName, (
sizeof
(szLocalBufferW)/
sizeof
(
WCHAR
)), szLocalBufferW);
}
else
{
wcscpy(szBuffer, GetDefaultDirW());
if
(IsPathSep(pInName[0])) {
wcscpy(&szBuffer[2], pInName);
DoGetFullPathNameW(szBuffer, (
sizeof
(szLocalBufferW)/
sizeof
(
WCHAR
)), szLocalBufferW);
}
else
{
if
(IsSpecialFileName(pInName)) {
return
(
WCHAR
*)pInName;
}
else
{
wcscat(szBuffer, pInName);
if
(wcslen(szBuffer) > MAX_PATH)
szBuffer[MAX_PATH] =
'\0'
;
DoGetFullPathNameW(szBuffer, (
sizeof
(szLocalBufferW)/
sizeof
(
WCHAR
)), szLocalBufferW);
}
}
}
}
return
szLocalBufferW;
}
int
VDir::SetCurrentDirectoryW(
WCHAR
*lpBuffer)
{
WCHAR
*pPtr;
int
length, nRet = -1;
pPtr = MapPathW(lpBuffer);
length = wcslen(pPtr);
if
(length > 3 && IsPathSep(pPtr[length-1])) {
pPtr[length-1] =
'\0'
;
}
DWORD
r = GetFileAttributesW(pPtr);
if
((r != 0xffffffff) && (r & FILE_ATTRIBUTE_DIRECTORY))
{
WCHAR
wBuffer[(MAX_PATH+1)*2];
DoGetFullPathNameW(pPtr, (
sizeof
(wBuffer)/
sizeof
(
WCHAR
)), wBuffer);
SetDefaultDirW(wBuffer, DriveIndex((
char
)wBuffer[0]));
nRet = 0;
}
return
nRet;
}
#endif /* ___VDir_H___ */