gecko-dev/xpcom/io/nsFileSpec.cpp

580 lines
21 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "nsFileSpec.h"
#include "nsFileStream.h"
#include "nsDebug.h"
#include "prtypes.h"
#include <string.h>
#include <stdio.h>
//========================================================================================
NS_NAMESPACE nsFileSpecHelpers
//========================================================================================
{
enum
{ kMaxFilenameLength = 31 // should work on Macintosh, Unix, and Win32.
, kMaxAltDigitLength = 5
, kMaxCoreLeafNameLength = (kMaxFilenameLength - (kMaxAltDigitLength + 1))
};
NS_NAMESPACE_PROTOTYPE void LeafReplace(
char*& ioPath,
char inSeparator,
const char* inLeafName);
#ifndef XP_MAC
NS_NAMESPACE_PROTOTYPE void Canonify(char*& ioPath, bool inMakeDirs);
NS_NAMESPACE_PROTOTYPE void MakeAllDirectories(const char* inPath, int mode);
#endif
NS_NAMESPACE_PROTOTYPE char* GetLeaf(const char* inPath, char inSeparator); // allocated
NS_NAMESPACE_PROTOTYPE char* StringDup(const char* inString, int allocLength = 0);
NS_NAMESPACE_PROTOTYPE char* AllocCat(const char* inString1, const char* inString2);
NS_NAMESPACE_PROTOTYPE char* StringAssign(char*& ioString, const char* inOther);
NS_NAMESPACE_PROTOTYPE char* ReallocCat(char*& ioString, const char* inString1);
#ifdef XP_PC
NS_NAMESPACE_PROTOTYPE void NativeToUnix(char*& ioPath);
NS_NAMESPACE_PROTOTYPE void UnixToNative(char*& ioPath);
#endif
} NS_NAMESPACE_END
//----------------------------------------------------------------------------------------
char* nsFileSpecHelpers::StringDup(
const char* inString,
int allocLength)
//----------------------------------------------------------------------------------------
{
if (!allocLength && inString)
allocLength = strlen(inString);
char* newPath = inString || allocLength ? new char[allocLength + 1] : nsnull;
if (!newPath)
return NULL;
strcpy(newPath, inString);
return newPath;
} // nsFileSpecHelpers::StringDup
//----------------------------------------------------------------------------------------
char* nsFileSpecHelpers::AllocCat(
const char* inString1,
const char* inString2)
//----------------------------------------------------------------------------------------
{
if (!inString1)
return inString2 ? StringDup(inString2) : (char*)NULL;
if (!inString2)
return StringDup(inString1);
char* outString = StringDup(inString1, strlen(inString1) + strlen(inString2));
if (outString)
strcat(outString, inString2);
return outString;
} // nsFileSpecHelpers::StringDup
//----------------------------------------------------------------------------------------
char* nsFileSpecHelpers::StringAssign(
char*& ioString,
const char* inString2)
//----------------------------------------------------------------------------------------
{
if (!inString2)
{
delete [] ioString;
ioString = (char*)NULL;
return ioString;
}
if (!ioString || (strlen(inString2) > strlen(ioString)))
{
delete [] ioString;
ioString = StringDup(inString2);
return ioString;
}
strcpy(ioString, inString2);
return ioString;
} // nsFileSpecHelpers::StringAssign
//----------------------------------------------------------------------------------------
void nsFileSpecHelpers::LeafReplace(
char*& ioPath,
char inSeparator,
const char* inLeafName)
//----------------------------------------------------------------------------------------
{
// Find the existing leaf name
if (!ioPath)
return;
if (!inLeafName)
{
*ioPath = '\0';
return;
}
char* lastSeparator = strrchr(ioPath, inSeparator);
int oldLength = strlen(ioPath);
*(++lastSeparator) = '\0'; // strip the current leaf name
int newLength = lastSeparator - ioPath + strlen(inLeafName);
if (newLength > oldLength)
{
char* newPath = StringDup(ioPath, newLength + 1);
delete [] ioPath;
ioPath = newPath;
}
strcat(ioPath, inLeafName);
} // nsNativeFileSpec::LeafReplace
//----------------------------------------------------------------------------------------
char* nsFileSpecHelpers::GetLeaf(const char* inPath, char inSeparator)
// Returns a pointer to an allocated string representing the leaf.
//----------------------------------------------------------------------------------------
{
if (!inPath)
return NULL;
char* lastSeparator = strrchr(inPath, inSeparator);
if (lastSeparator)
return StringDup(++lastSeparator);
return StringDup(inPath);
} // nsNativeFileSpec::GetLeaf
#if defined(XP_UNIX) || defined(XP_PC)
//----------------------------------------------------------------------------------------
void nsFileSpecHelpers::MakeAllDirectories(const char* inPath, int mode)
// Make the path a valid one by creating all the intermediate directories. Does NOT
// make the leaf into a directory. This should be a unix path.
//----------------------------------------------------------------------------------------
{
if (!inPath)
return;
char* pathCopy = nsFileSpecHelpers::StringDup( inPath );
if (!pathCopy)
return;
const char kSeparator = '/'; // I repeat: this should be a unix-style path.
const int kSkipFirst = 1;
#ifdef XP_PC
// Either this is a relative path, or we ensure that it has
// a drive letter specifier.
NS_ASSERTION( pathCopy[0] != '/' || pathCopy[2] == '|', "No drive letter!" );
#endif
char* currentStart = pathCopy;
char* currentEnd = strchr(currentStart + kSkipFirst, kSeparator);
if (currentEnd)
{
*currentEnd = '\0';
nsNativeFileSpec spec(nsFilePath(pathCopy, false));
do
{
// If the node doesn't exist, and it is not the initial node in a full path,
// then make a directory (We cannot make the initial (volume) node).
if (!spec.Exists() && *currentStart != kSeparator)
spec.CreateDirectory(mode);
if (!spec.Exists())
{
NS_ASSERTION(spec.Exists(), "Could not create the directory?");
break;
}
currentStart = ++currentEnd;
currentEnd = strchr(currentStart, kSeparator);
if (!currentEnd)
break;
spec += currentStart; // "lengthen" the path, adding the next node.
} while (currentEnd);
}
delete [] pathCopy;
} // nsFileSpecHelpers::MakeAllDirectories
#endif // XP_PC || XP_UNIX
//----------------------------------------------------------------------------------------
char* nsFileSpecHelpers::ReallocCat(char*& ioString, const char* inString1)
//----------------------------------------------------------------------------------------
{
char* newString = AllocCat(ioString, inString1);
delete [] ioString;
ioString = newString;
return ioString;
} // nsNativeFileSpec::ReallocCat
#if defined(XP_PC)
#include "windows/nsFileSpecWin.cpp" // Windows-specific implementations
#elif defined(XP_MAC)
#include "nsFileSpecMac.cpp" // Macintosh-specific implementations
#elif defined(XP_UNIX)
#include "unix/nsFileSpecUnix.cpp" // Unix-specific implementations
#endif
//========================================================================================
// nsFileURL implementation
//========================================================================================
#ifndef XP_MAC
//----------------------------------------------------------------------------------------
nsFileURL::nsFileURL(const char* inString, bool inCreateDirs)
//----------------------------------------------------------------------------------------
: mURL(nsnull)
{
if (!inString)
return;
NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
// Make canonical and absolute.
nsFilePath path(inString + kFileURLPrefixLength, inCreateDirs);
*this = path;
} // nsFileURL::nsFileURL
#endif
//----------------------------------------------------------------------------------------
nsFileURL::nsFileURL(const nsFileURL& inOther)
//----------------------------------------------------------------------------------------
: mURL(nsFileSpecHelpers::StringDup(inOther.mURL))
#ifdef XP_MAC
, mNativeFileSpec(inOther.GetNativeSpec())
#endif
{
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
nsFileURL::nsFileURL(const nsFilePath& inOther)
//----------------------------------------------------------------------------------------
: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther))
#ifdef XP_MAC
, mNativeFileSpec(inOther.GetNativeSpec())
#endif
{
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
nsFileURL::nsFileURL(const nsNativeFileSpec& inOther)
: mURL(nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther)))
#ifdef XP_MAC
, mNativeFileSpec(inOther)
#endif
//----------------------------------------------------------------------------------------
{
} // nsFileURL::nsFileURL
//----------------------------------------------------------------------------------------
nsFileURL::~nsFileURL()
//----------------------------------------------------------------------------------------
{
delete [] mURL;
}
//----------------------------------------------------------------------------------------
void nsFileURL::operator = (const char* inString)
//----------------------------------------------------------------------------------------
{
nsFileSpecHelpers::StringAssign(mURL, inString);
NS_ASSERTION(strstr(inString, kFileURLPrefix) == inString, "Not a URL!");
#ifdef XP_MAC
mNativeFileSpec = inString + kFileURLPrefixLength;
#endif
} // nsFileURL::operator =
//----------------------------------------------------------------------------------------
void nsFileURL::operator = (const nsFileURL& inOther)
//----------------------------------------------------------------------------------------
{
mURL = nsFileSpecHelpers::StringAssign(mURL, inOther.mURL);
#ifdef XP_MAC
mNativeFileSpec = inOther.GetNativeSpec();
#endif
} // nsFileURL::operator =
//----------------------------------------------------------------------------------------
void nsFileURL::operator = (const nsFilePath& inOther)
//----------------------------------------------------------------------------------------
{
delete [] mURL;
mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)inOther);
#ifdef XP_MAC
mNativeFileSpec = inOther.GetNativeSpec();
#endif
} // nsFileURL::operator =
//----------------------------------------------------------------------------------------
void nsFileURL::operator = (const nsNativeFileSpec& inOther)
//----------------------------------------------------------------------------------------
{
delete [] mURL;
mURL = nsFileSpecHelpers::AllocCat(kFileURLPrefix, (const char*)nsFilePath(inOther));
#ifdef XP_MAC
mNativeFileSpec = inOther;
#endif
} // nsFileURL::operator =
//----------------------------------------------------------------------------------------
nsBasicOutStream& operator << (nsBasicOutStream& s, const nsFileURL& url)
//----------------------------------------------------------------------------------------
{
return (s << url.mURL);
}
//========================================================================================
// nsFilePath implementation
//========================================================================================
#ifndef XP_MAC
//----------------------------------------------------------------------------------------
nsFilePath::nsFilePath(const char* inString, bool inCreateDirs)
//----------------------------------------------------------------------------------------
: mPath(nsFileSpecHelpers::StringDup(inString))
{
NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path");
#ifdef XP_PC
nsFileSpecHelpers::UnixToNative(mPath);
#endif
// Make canonical and absolute.
nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
#ifdef XP_PC
NS_ASSERTION( mPath[1] == ':', "unexpected canonical path" );
nsFileSpecHelpers::NativeToUnix(mPath);
#endif
}
#endif
//----------------------------------------------------------------------------------------
nsFilePath::nsFilePath(const nsFileURL& inOther)
//----------------------------------------------------------------------------------------
: mPath(nsFileSpecHelpers::StringDup(inOther.mURL + kFileURLPrefixLength))
#ifdef XP_MAC
, mNativeFileSpec(inOther.GetNativeSpec())
#endif
{
}
#ifdef XP_UNIX
//----------------------------------------------------------------------------------------
nsFilePath::nsFilePath(const nsNativeFileSpec& inOther)
//----------------------------------------------------------------------------------------
: mPath(nsFileSpecHelpers::StringDup(inOther.mPath))
{
}
#endif // XP_UNIX
//----------------------------------------------------------------------------------------
nsFilePath::~nsFilePath()
//----------------------------------------------------------------------------------------
{
delete [] mPath;
}
#ifdef XP_UNIX
//----------------------------------------------------------------------------------------
void nsFilePath::operator = (const nsNativeFileSpec& inOther)
//----------------------------------------------------------------------------------------
{
mPath = nsFileSpecHelpers::StringAssign(mPath, inOther.mPath);
}
#endif // XP_UNIX
//----------------------------------------------------------------------------------------
void nsFilePath::operator = (const char* inString)
//----------------------------------------------------------------------------------------
{
NS_ASSERTION(strstr(inString, kFileURLPrefix) != inString, "URL passed as path");
#ifdef XP_MAC
mNativeFileSpec = inString;
nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(mNativeFileSpec));
#else
#ifdef XP_PC
nsFileSpecHelpers::UnixToNative(mPath);
#endif
// Make canonical and absolute.
nsFileSpecHelpers::Canonify(mPath, false /* XXX? */);
#ifdef XP_PC
nsFileSpecHelpers::NativeToUnix(mPath);
#endif
#endif // XP_MAC
}
//----------------------------------------------------------------------------------------
void nsFilePath::operator = (const nsFileURL& inOther)
//----------------------------------------------------------------------------------------
{
nsFileSpecHelpers::StringAssign(mPath, (const char*)nsFilePath(inOther));
#ifdef XP_MAC
mNativeFileSpec = inOther.GetNativeSpec();
#endif
}
//========================================================================================
// nsNativeFileSpec implementation
//========================================================================================
#ifndef XP_MAC
//----------------------------------------------------------------------------------------
nsNativeFileSpec::nsNativeFileSpec()
//----------------------------------------------------------------------------------------
: mPath(NULL)
{
}
#endif
//----------------------------------------------------------------------------------------
nsNativeFileSpec::nsNativeFileSpec(const nsFileURL& inURL)
//----------------------------------------------------------------------------------------
#ifndef XP_MAC
: mPath(NULL)
#endif
{
*this = nsFilePath(inURL); // convert to unix path first
}
//----------------------------------------------------------------------------------------
void nsNativeFileSpec::MakeUnique(const char* inSuggestedLeafName)
//----------------------------------------------------------------------------------------
{
if (inSuggestedLeafName && *inSuggestedLeafName)
SetLeafName(inSuggestedLeafName);
MakeUnique();
} // nsNativeFileSpec::MakeUnique
//----------------------------------------------------------------------------------------
void nsNativeFileSpec::MakeUnique()
//----------------------------------------------------------------------------------------
{
if (!Exists())
return;
char* leafName = GetLeafName();
if (!leafName)
return;
char* lastDot = strrchr(leafName, '.');
char* suffix = "";
if (lastDot)
{
suffix = nsFileSpecHelpers::StringDup(lastDot); // include '.'
*lastDot = '\0'; // strip suffix and dot.
}
const int kMaxRootLength
= nsFileSpecHelpers::kMaxCoreLeafNameLength - strlen(suffix) - 1;
if (strlen(leafName) > kMaxRootLength)
leafName[kMaxRootLength] = '\0';
for (short index = 1; index < 1000 && Exists(); index++)
{
// start with "Picture-1.jpg" after "Picture.jpg" exists
char newName[nsFileSpecHelpers::kMaxFilenameLength + 1];
sprintf(newName, "%s-%d%s", leafName, index, suffix);
SetLeafName(newName);
}
if (*suffix)
delete [] suffix;
delete [] leafName;
} // nsNativeFileSpec::MakeUnique
//----------------------------------------------------------------------------------------
void nsNativeFileSpec::operator = (const nsFileURL& inURL)
//----------------------------------------------------------------------------------------
{
*this = nsFilePath(inURL); // convert to unix path first
}
//========================================================================================
// UNIX & WIN nsNativeFileSpec implementation
//========================================================================================
#ifdef XP_UNIX
//----------------------------------------------------------------------------------------
nsNativeFileSpec::nsNativeFileSpec(const nsFilePath& inPath)
//----------------------------------------------------------------------------------------
: mPath(nsFileSpecHelpers::StringDup((const char*)inPath))
{
}
#endif // XP_UNIX
#ifdef XP_UNIX
//----------------------------------------------------------------------------------------
void nsNativeFileSpec::operator = (const nsFilePath& inPath)
//----------------------------------------------------------------------------------------
{
nsFileSpecHelpers::StringAssign(mPath, (const char*)inPath);
}
#endif //XP_UNIX
#if defined(XP_UNIX) || defined(XP_PC)
//----------------------------------------------------------------------------------------
nsNativeFileSpec::nsNativeFileSpec(const nsNativeFileSpec& inSpec)
//----------------------------------------------------------------------------------------
: mPath(nsFileSpecHelpers::StringDup(inSpec.mPath))
{
}
#endif //XP_UNIX
#if defined(XP_UNIX) || defined(XP_PC)
//----------------------------------------------------------------------------------------
nsNativeFileSpec::nsNativeFileSpec(const char* inString, bool inCreateDirs)
//----------------------------------------------------------------------------------------
: mPath(nsFileSpecHelpers::StringDup(inString))
{
// Make canonical and absolute.
nsFileSpecHelpers::Canonify(mPath, inCreateDirs);
}
#endif //XP_UNIX,PC
//----------------------------------------------------------------------------------------
nsNativeFileSpec::~nsNativeFileSpec()
//----------------------------------------------------------------------------------------
{
#ifndef XP_MAC
delete [] mPath;
#endif
}
#if defined(XP_UNIX) || defined(XP_PC)
//----------------------------------------------------------------------------------------
void nsNativeFileSpec::operator = (const nsNativeFileSpec& inSpec)
//----------------------------------------------------------------------------------------
{
mPath = nsFileSpecHelpers::StringAssign(mPath, inSpec.mPath);
}
#endif //XP_UNIX
#if defined(XP_UNIX) || defined(XP_PC)
//----------------------------------------------------------------------------------------
void nsNativeFileSpec::operator = (const char* inString)
//----------------------------------------------------------------------------------------
{
mPath = nsFileSpecHelpers::StringAssign(mPath, inString);
// Make canonical and absolute.
nsFileSpecHelpers::Canonify(mPath, true /* XXX? */);
}
#endif //XP_UNIX
#if (defined(XP_UNIX) || defined(XP_PC))
//----------------------------------------------------------------------------------------
nsBasicOutStream& operator << (nsBasicOutStream& s, const nsNativeFileSpec& spec)
//----------------------------------------------------------------------------------------
{
return (s << (const char*)spec.mPath);
}
#endif // DEBUG && XP_UNIX
//----------------------------------------------------------------------------------------
nsNativeFileSpec nsNativeFileSpec::operator + (const char* inRelativePath) const
//----------------------------------------------------------------------------------------
{
nsNativeFileSpec result = *this;
result += inRelativePath;
return result;
} // nsNativeFileSpec::operator +