/*
Copyright (C) 2010 Arnaud Champenois arthelion92@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KERNEL_H
#define KERNEL_H
#include <string>
#include <sstream>
#include <iomanip>
#include <QString>
#define SIZEOF_ARRAY(a) (sizeof(a)/sizeof(a[0]))
namespace kernel {
template <class T> inline void swap(T& a,T& b)
{ T c = b; b = a; a = c; }
// Class to manage filename components.
// Manages / and windows \ in directory
class FileNameString
{
public:
inline FileNameString();
inline FileNameString(const QString&aPathName);
inline FileNameString(const FileNameString&aPathName);
inline ~FileNameString();
inline FileNameString& operator =(const QString& aPathName);
inline FileNameString& operator =(const FileNameString& aPathName);
// Full patch, with an optional prefix number on the filename
inline QString GetPath(int aFileNumber=0) const;
// Drive letter with ':'
inline void SetDrive(const QString& aDrive);
inline const char* GetDrive() const;
// Directory path, no trailing slash
inline void SetDirectory(const QString& aPath);
inline void AppendDirectory(const QString& aPath);
inline QString GetDirectory() const;
// Full directory with drive, no trailing slash
inline QString GetFullDirectory() const;
// FileName with extension
inline void SetFileName(const QString &aFileName);
inline QString GetFileName() const;
// BaseFileName without extension
inline void SetBaseFileName(const QString &aFileName);
inline QString GetBaseFileName() const;
inline void AppendBaseFileName(const QString &aString);
inline void PrependBaseFileName(const QString &aString);
// Extension
inline void SetExtension(const QString &anExtension);
inline const char*GetExtension() const;
inline bool TestExtension(QString) const;
inline bool HasExtension() const;
// Is there somethin missing to define the path ?
inline bool IsEmpty() const;
inline int GetNumber() const;
protected:
inline void Split();
inline void SplitFileName();
inline void Merge(int aFileNumber) const;
inline void TransfoToSlash(std::string& aString);
private:
std::string mDrive;
std::string mPath;
std::string mFileName;
std::string mExtension;
mutable std::string mFullName;
};
//====================================
// implementation
FileNameString:: FileNameString() {}
FileNameString::FileNameString(const FileNameString&aFileName)
{
mFullName = aFileName.mFullName; Split();
}
FileNameString::FileNameString(const QString&aFileName) {
mFullName = aFileName.toLocal8Bit(); Split();
}
FileNameString::~FileNameString() {}
FileNameString& FileNameString::operator =(const FileNameString& aFileName)
{ mFullName = aFileName.mFullName; Split(); return *this; }
FileNameString& FileNameString::operator =(const QString& aFileName)
{ mFullName = aFileName.toLocal8Bit(); Split(); return *this; }
QString FileNameString::GetPath(int aFileNumber) const
{ if(IsEmpty()) return NULL; Merge(aFileNumber); return QString::fromLocal8Bit(mFullName.c_str());}
// Drive
void FileNameString::SetDrive(const QString &aDrive)
{ mDrive = aDrive.toLocal8Bit(); if(!mDrive.empty() && mDrive[mDrive.length()-1] != ':') mDrive += ':'; }
const char*FileNameString::GetDrive() const { return mDrive.c_str(); }
void FileNameString::TransfoToSlash(std::string& aString)
{
#if defined(WIN32)
std::string::iterator anIter;
for(anIter = aString.begin(); anIter != aString.end();anIter++)
{ if(*anIter == '\\') *anIter = '/'; }
#endif
}
// Path
void FileNameString::SetDirectory(const QString &aPath)
{ mPath = aPath.toLocal8Bit();
TransfoToSlash(mPath);
std::string::size_type aDriveIndex;
aDriveIndex = mPath.find(':');
if(aDriveIndex != std::string::npos)
{
mDrive.assign(mPath,0,aDriveIndex);
aDriveIndex++;
std::string aNewPath;
aNewPath.assign(mPath,aDriveIndex,mPath.length());
mPath = aNewPath;
}
int aLength = mPath.length();
while(aLength && mPath[aLength-1] == '/') { mPath.erase(aLength-1); aLength--; }
}
void FileNameString::AppendDirectory(const QString &aPath)
{
if(aPath.isEmpty()) return;
std::string aNewPath = aPath.toLocal8Bit();
TransfoToSlash(aNewPath);
if(aNewPath[0] != '/')
mPath += '/';
mPath += aNewPath;
}
QString FileNameString::GetDirectory() const { return QString::fromLocal8Bit(mPath.c_str()); }
// Full directory
QString FileNameString::GetFullDirectory() const
{
std::string aString;
if(!mDrive.empty()) { aString = mDrive; aString += ':'; }
aString += mPath;
return QString::fromLocal8Bit(aString.c_str());
}
// FileName
void FileNameString::SetFileName(const QString&aFileName)
{ mFileName = aFileName.toLocal8Bit(); SplitFileName(); }
QString FileNameString::GetFileName() const
{ std::string aString = mFileName; aString += '.'; aString += mExtension; return QString::fromLocal8Bit(aString.c_str()); }
// BaseFileName
void FileNameString::SetBaseFileName(const QString&aFileName)
{ mFileName = aFileName.toLocal8Bit(); }
QString FileNameString::GetBaseFileName() const { return QString::fromLocal8Bit(mFileName.c_str()); }
void FileNameString::AppendBaseFileName(const QString&aString)
{ mFileName += aString.toLocal8Bit(); }
void FileNameString::PrependBaseFileName(const QString&aString)
{ mFileName = std::string(aString.toLocal8Bit())+mFileName; }
// Extension
void FileNameString::SetExtension(const QString&anExtension)
{ if(anExtension.isEmpty()) mExtension.clear();
else
{ if(anExtension.data()[0] == '.') mExtension = (const char*)(anExtension.toLocal8Bit())+1; else mExtension = anExtension.toLocal8Bit(); }
}
const char*FileNameString::GetExtension() const
{ return mExtension.c_str(); }
bool FileNameString::TestExtension(QString anExtension) const
{ return (_stricmp(mExtension.c_str(),anExtension.toLocal8Bit()) == 0); }
bool FileNameString::HasExtension() const
{ return (!mExtension.empty()); }
bool FileNameString::IsEmpty() const
{ return mFileName.empty(); }
void FileNameString::Split()
{
mDrive.clear(); mPath.clear(); mFileName.clear(); mExtension.clear();
std::string::size_type aDriveIndex,aSlashIndex;
TransfoToSlash(mFullName);
aDriveIndex = mFullName.find(':');
if(aDriveIndex != std::string::npos)
{
mDrive.assign(mFullName,0,aDriveIndex);
aDriveIndex++;
}
else aDriveIndex = 0;
aSlashIndex = mFullName.rfind('/');
if(aSlashIndex != std::string::npos)
{
if(aSlashIndex>aDriveIndex)
{
mPath.assign(mFullName,aDriveIndex,aSlashIndex-aDriveIndex);
size_t aLength = mPath.length();
while(aLength && mPath[aLength-1] == '/') { mPath.erase(aLength-1); aLength--; }
aSlashIndex++;
}
}
else
aSlashIndex = aDriveIndex;
if(aSlashIndex<mFullName.length())
{
mFileName = mFullName.c_str()+aSlashIndex;
SplitFileName();
}
}
void FileNameString::SplitFileName()
{
mExtension.clear();
std::string::size_type aDotIndex;
aDotIndex = mFileName.rfind('.');
if(aDotIndex != std::string::npos)
{
mExtension = mFileName.c_str()+aDotIndex+1;
mFileName.erase(aDotIndex,mFileName.length()-aDotIndex);
}
}
inline int FileNameString::GetNumber() const
{
if(mFileName.empty()) return 0;
std::string aPreNumber;
const char*aPtr = mFileName.c_str();
// WTF ? bool aHasSep = false;
while(*aPtr && isdigit(*aPtr)) // || *aPtr == '_' || *aPtr == '-' || *aPtr == ' '))
{
// aHasSep = (*aPtr == '_' || *aPtr == '-' || *aPtr == ' ');
aPreNumber += *aPtr;
aPtr++;
}
return atoi(aPreNumber.c_str());
}
void FileNameString::Merge(int aFileNumber) const
{
mFullName.clear();
if(!mDrive.empty())
{
mFullName = mDrive;
mFullName += ':';
}
mFullName += mPath;
if(!mFileName.empty())
{
if(!mPath.empty())
mFullName += '/';
if(aFileNumber>0)
{
std::string aPreNumber;
const char*aPtr = mFileName.c_str();
bool aHasSep = false;
char aSep = '-';
int aCount = 0;
while(*aPtr && (isdigit(*aPtr) || *aPtr == '_' || *aPtr == '-' || *aPtr == ' '))
{
aHasSep = (*aPtr == '_' || *aPtr == '-' || *aPtr == ' ');
if(aHasSep) aSep = *aPtr;
else aCount++;
aPreNumber += *aPtr;
aPtr++;
}
std::ostringstream os;
if(aCount == 0) aCount = 3;
os << std::setw(aCount) << std::setfill('0') << aFileNumber << std::setw(0) << aSep << aPtr;
mFullName += os.str();
}
else
mFullName += mFileName;
}
if(!mExtension.empty())
{
mFullName += '.';
mFullName += mExtension;
}
}
}
#endif