//---------------------------------------------------------------------
//
// Copyright (C) 2004 Yingle Jia
//
// Permission to copy, use, modify, sell and distribute this software is
// granted provided this copyright notice appears in all copies.
// This software is provided "as is" without express or implied warranty,
// and with no claim as to its suitability for any purpose.
//
#include "stdafx.h"
namespace Acf {
namespace IO {
inline void CheckInvalidPathChars(String* path)
{
#if PLATFORM_UNIX
if (path->StartsWith(L"\\\\"))
throw ArgumentException();
#endif // PLATFORM_UNIX
if (-1 != path->IndexOfAny(Path::InvalidPathChars))
throw ArgumentException();
}
inline bool IsDirectorySeparator(wchar_t c)
{
return (c == Path::DirectorySeparatorChar || c == Path::AltDirectorySeparatorChar);
}
//---------------------------------------------------------------------
// class Path
// Static Fields
#if !PLATFORM_UNIX
const wchar_t Path::VolumeSeparatorChar = L':';
const wchar_t Path::DirectorySeparatorChar = L'\\';
const wchar_t Path::AltDirectorySeparatorChar = L'/';
#else
const wchar_t Path::VolumeSeparatorChar = L'/';
const wchar_t Path::DirectorySeparatorChar = L'/';
const wchar_t Path::AltDirectorySeparatorChar = L'\\';
#endif // !PLATFORM_UNIX
const wchar_t Path::PathSeparator = L';';
const RefPtr<Array<wchar_t> > Path::InvalidPathChars = Array<wchar_t>::Build(
L'\"', L'<', L'>', L'|', L'\0', L'\b', (wchar_t)16, (wchar_t)17, (wchar_t)18,
(wchar_t)20, (wchar_t)21, (wchar_t)22, (wchar_t)23, (wchar_t)24, (wchar_t)25);
// Static Methods
/*static*/ StringPtr Path::Combine(String* path1, String* path2)
{
if (path1 == null || path2 == null)
throw ArgumentNullException();
CheckInvalidPathChars(path1);
CheckInvalidPathChars(path2);
if (path2->Length == 0)
return path1;
if (path1->Length == 0)
return path2;
if (IsPathRooted(path2))
return path2;
wchar_t ch = path1->Chars[path1->Length - 1];
if (ch != Path::DirectorySeparatorChar && ch != Path::AltDirectorySeparatorChar
&& ch != Path::VolumeSeparatorChar)
{
StringPtr sep = new String(Path::DirectorySeparatorChar, 1);
return String::Concat(path1, sep, path2);
}
else
{
return String::Concat(path1, path2);
}
}
/*static*/ StringPtr Path::GetFullPath(String* path)
{
if (path == null)
throw ArgumentNullException();
// TODO: fixup path
wchar_t buffer[Pal::MaxPath];
int result = Pal::GetFullPathNameW(path->GetCString(), Pal::MaxPath, buffer);
if (result == 0)
throw ArgumentException();
return new String(buffer);
}
/*static*/ bool Path::IsPathRooted(String* path)
{
if (path != null)
{
CheckInvalidPathChars(path);
int length = path->Length;
if (length >= 1)
{
// Check first character
wchar_t ch = path->Chars[0];
if (ch == DirectorySeparatorChar || ch == AltDirectorySeparatorChar)
return true;
// Check second character
if (length >= 2 && path->Chars[1] == VolumeSeparatorChar)
return true;
}
}
return false;
}
/*static*/ StringPtr Path::GetPathRoot(String* path)
{
if (path == null)
return null;
// TODO: fixup path
return path->Substring(0, GetRootLength(path));
}
/*static*/ StringPtr Path::GetDirectoryName(String* path)
{
if (path != null)
{
CheckInvalidPathChars(path);
// TODO: fixup path
int rootLen = GetRootLength(path);
int i = path->Length;
if (i > rootLen)
{
i = path->Length;
if (i == rootLen)
return null;
while (i > rootLen && !IsDirectorySeparator(path->Chars[i]))
i--;
return path->Substring(0, i);
}
}
return null;
}
/*static*/ StringPtr Path::GetFileName(String* path)
{
if (path != null)
{
CheckInvalidPathChars(path);
int length = path->Length;
for (int i = length; --i >= 0;)
{
wchar_t ch = path->Chars[i];
if (ch == DirectorySeparatorChar || ch == AltDirectorySeparatorChar
|| ch == VolumeSeparatorChar)
{
return path->Substring(i + 1, length - i - 1);
}
}
}
return path;
}
/*static*/ StringPtr Path::GetFileNameWithoutExtension(String* path)
{
path = GetFileName(path);
if (path != null)
{
int i;
if ((i = path->LastIndexOf(L'.')) == -1)
return path; // no path extension found
else
return path->Substring(0, i);
}
return null;
}
/*static*/ bool Path::HasExtension(String* path)
{
if (path != null)
{
CheckInvalidPathChars(path);
for (int i = path->Length; --i >= 0;)
{
wchar_t ch = path->Chars[i];
if (ch == L'.')
{
if (i != path->Length - 1)
return true;
else
return false;
}
if (ch == DirectorySeparatorChar || ch == AltDirectorySeparatorChar
|| ch == VolumeSeparatorChar)
break;
}
}
return false;
}
/*static*/ StringPtr Path::GetExtension(String* path)
{
if (path == null)
return null;
CheckInvalidPathChars(path);
int length = path->Length;
for (int i = length; --i >= 0;)
{
wchar_t ch = path->Chars[i];
if (ch == L'.')
{
if (i != length - 1)
return path->Substring(i, length - i);
else
return String::Empty;
}
if (ch == DirectorySeparatorChar || ch == AltDirectorySeparatorChar
|| ch == VolumeSeparatorChar)
break;
}
return String::Empty;
}
/*static*/ StringPtr Path::ChangeExtension(String* path, String* extension)
{
if (path != null)
{
CheckInvalidPathChars(path);
StringPtr s = path;
for (int i = path->Length; --i >= 0;)
{
wchar_t ch = path->Chars[i];
if (ch == L'.')
{
s = path->Substring(0, i);
break;
}
if (ch == DirectorySeparatorChar || ch == AltDirectorySeparatorChar
|| ch == VolumeSeparatorChar)
break;
}
if (extension != null && path->Length != 0)
{
if (extension->Length == 0 || extension->Chars[0] != L'.')
{
s = s + L".";
}
s = s + extension;
}
return s;
}
return null;
}
/*static*/ StringPtr Path::GetTempPath()
{
wchar_t buffer[Pal::MaxPath];
Pal::GetTempPathW(Pal::MaxPath, buffer);
return new String(buffer);
}
/*static*/ StringPtr Path::GetTempFileName()
{
wchar_t path[Pal::MaxPath];
Pal::GetTempPathW(Pal::MaxPath, path);
wchar_t name[Pal::MaxPath];
Pal::GetTempFileNameW(path, L"tmp", 0, name);
return new String(name);
}
/*static*/ int Path::GetRootLength(String* path)
{
CheckInvalidPathChars(path);
int i = 0;
int length = path->Length;
#if !PLATFORM_UNIX
if (length >= 1 && (IsDirectorySeparator(path->Chars[0])))
{
// handles UNC names and directories off current drive's rootLen.
i = 1;
if (length >= 2 && (IsDirectorySeparator(path->Chars[1])))
{
i = 2;
int n = 2;
while (i < length && (!IsDirectorySeparator(path->Chars[i]) || --n > 0))
i++;
}
}
else if (length >= 2 && path->Chars[1] == Path::VolumeSeparatorChar)
{
// handles A:\foo.
i = 2;
if (length >= 3 && (IsDirectorySeparator(path->Chars[2])))
i++;
}
#else // UNIX
if (length >= 1 && (IsDirectorySeparator(path->Chars[0])))
{
i = 1;
}
#endif // !PLATFORM_UNIX
return i;
}
} // namespace IO
} // namespace Acf