Initial source commit

This commit is contained in:
Tony Bark 2025-10-03 02:19:59 -04:00
commit f1384c11ee
335 changed files with 52715 additions and 0 deletions

View file

@ -0,0 +1,73 @@
/*
* Modification History
*
* 2003-January-23 Jason Rohrer
* Created.
*
*
* 2003-November-10 Jason Rohrer
* Added makeDirectory function.
*/
#include "minorGems/common.h"
#include "minorGems/io/file/File.h"
#ifndef DIRECTORY_INCLUDED
#define DIRECTORY_INCLUDED
/**
* Class of static directory functions.
*
* This class exists because most directory operations are
* platform-dependent, and a large body of existing code
* depends on a platform-independent File.h.
*
* @author Jason Rohrer.
*/
class Directory {
public:
/**
* Removes a directory.
*
* The directory must be empty for this call to succeed.
*
* @param inFile the file representing the directory.
* Must be destroyed by caller.
*
* @return true if the directory is removed successfully, or
* false otherwise (for example, if the directory is not empy).
*/
static char removeDirectory( File *inFile );
/**
* Makes a directory.
*
* @param inFile the file representing the directory.
* Must be destroyed by caller.
*
* @return true if the directory is removed successfully, or
* false otherwise (for example, if the directory is not empy).
*/
static char makeDirectory( File *inFile );
};
#endif

994
minorGems/io/file/File.h Normal file
View file

@ -0,0 +1,994 @@
/*
* Modification History
*
* 2001-February-11 Jason Rohrer
* Created.
*
* 2001-February-25 Jason Rohrer
* Fixed file name bugs in length and existence functions.
*
* 2001-May-11 Jason Rohrer
* Added a missing include.
*
* 2001-November-3 Jason Rohrer
* Added a function for checking if a file is a directory.
* Added a function for getting the child files of a directory.
* Added a function for getting a pathless file name.
*
* 2001-November-13 Jason Rohrer
* Made name length parameter optional in constructor.
* Made return length parameter optional in name getting functions.
*
* 2001-November-17 Jason Rohrer
* Added a functions for removing a file and for copying a file.
*
* 2002-March-11 Jason Rohrer
* Added destruction comment to getFullFileName().
*
* 2002-March-13 Jason Rohrer
* Changed mName to be \0-terminated to fix interaction bugs with Path.
* Fixed a missing delete.
* Added a function for creating a directory.
*
* 2002-March-31 Jason Rohrer
* Fixed some bad syntax.
*
* 2002-April-6 Jason Rohrer
* Replaced use of strdup.
*
* 2002-April-8 Jason Rohrer
* Fixed fopen bug.
*
* 2002-April-11 Jason Rohrer
* Fixed a memory leak.
* Fixed a casting error.
*
* 2002-June-28 Jason Rohrer
* Added a function for copying a file class.
*
* 2002-August-3 Jason Rohrer
* Added a function for getting the parent file.
*
* 2002-August-5 Jason Rohrer
* Used an unused error variable.
*
* 2002-September-11 Jason Rohrer
* Added return value to remove.
*
* 2003-January-27 Jason Rohrer
* Added a function for reading file contents.
*
* 2003-February-3 Jason Rohrer
* Added a function for writing a string to a file.
*
* 2003-March-13 Jason Rohrer
* Added a function for getting a child file from a directory.
*
* 2003-June-2 Jason Rohrer
* Fixed parent directory behavior when current file is root directory.
* Fixed a bug in getting child files of root directory.
*
* 2003-November-6 Jason Rohrer
* Added function for getting last modification time.
*
* 2003-November-10 Jason Rohrer
* Changed to use platform-dependent makeDirectory function.
*
* 2004-January-4 Jason Rohrer
* Added recursive child file functions.
*
* 2005-August-29 Jason Rohrer
* Fixed an uninitialized variable warning.
*
* 2010-March-6 Jason Rohrer
* Added versions of writeToFile readFileContents for binary data.
*
* 2010-April-23 Jason Rohrer
* Fixed a string length bug when line ends are Windows.
*
* 2010-May-14 Jason Rohrer
* String parameters as const to fix warnings.
*/
#include "minorGems/common.h"
#ifndef FILE_CLASS_INCLUDED
#define FILE_CLASS_INCLUDED
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <dirent.h>
#include "Path.h"
#include "minorGems/util/SimpleVector.h"
#include "minorGems/util/stringUtils.h"
/**
* File interface. Provides access to information about a
* file.
*
* @author Jason Rohrer
*/
class File {
public:
/**
* Constructs a file.
*
* @param inPath the path for this file.
* Is destroyed when this class is destroyed.
* Pass in NULL to specify
* no path (the current working directory).
* @param inName the name of the file to open.
* Must be destroyed by caller if not const.
* Copied internally.
* @param inNameLength length of the name in chars,
* or -1 to use the c-string length of inName
* (assuming that inName is \0-terminated).
* Defaults to -1.
*/
File( Path *inPath, const char *inName, int inNameLength = -1 );
~File();
/**
* Gets whether this file is a directory.
*
* @return true iff this file is a directory.
*/
char isDirectory();
/**
* Makes a directory in the location of this file.
*
* Can only succeed if exists() is false.
*
* @return true iff directory creation succeeded.
*/
char makeDirectory();
/**
* Gets the files contained in this file if it is a directory.
*
* @param outNumFiles pointer to where the number of
* files will be returned.
*
* @return an array of files, or NULL if this
* file is not a directory, is an empty directory, or doesn't exist.
* Must be destroyed by caller if non-NULL.
*/
File **getChildFiles( int *outNumFiles );
/**
* Gets the files contained in this file if it is a directory and
* recursively in subdirectories of this file.
*
* @param inDepthLimit the maximum subdirectory depth to recurse into.
* If inDepthLimit is 0, then only child files in this directory
* will be returned.
* @param outNumFiles pointer to where the number of
* files will be returned.
*
* @return an array of files, or NULL if this
* file is not a directory, is an empty directory (or a directory
* containing empty subdirectories), or doesn't exist.
* Must be destroyed by caller if non-NULL.
*/
File **getChildFilesRecursive( int inDepthLimit, int *outNumFiles );
/**
* Gets a child of this directory.
*
* @param inChildFileName the name of the child file.
* Must be destroyed by caller if non-const.
*
* @return the child file (even if it does not exist), or NULL if
* this file is not a directory.
* Must be destroyed by caller if non-NULL.
*/
File *getChildFile( const char *inChildFileName );
/**
* Gets the parent directory of this file.
*
* @return the parent directory of this file.
* Must be destroyed by caller.
*/
File *getParentDirectory();
/**
* Gets the length of this file.
*
* @return the length of this file in bytes. Returns
* 0 if the file does not exist.
*/
long getLength();
/**
* Gets whether a file exists.
*
* @return true if the file exists.
*/
char exists();
/**
* Gets the last modification time of this file.
*
* @return the modification time in seconds based on the
* system clock. Returns 0 if the file does not exist.
*/
unsigned long getModificationTime();
/**
* Removes this file from the disk, if it exists.
*
* @return true iff the remove succeeded, false if the removal
* fails or the file does not exist.
*/
char remove();
/**
* Copies this file object (does not copy the file described by
* this object).
*
* @return a deep copy of this file object.
*/
File *copy();
/**
* Copies the contents of this file into another file.
*
* @param inDestination the file to copy this file into.
* If it exists, it will be overwritten.
* If it does not exist, it will be created.
* Must be destroyed by caller.
* @param inBlockSize the block size to use when copying.
* Defaults to blocks of 5000 bytes.
*/
void copy( File *inDestination, long inBlockSize = 5000 );
/**
* Gets the full-path file name sufficient
* to access this file from the current working
* directory.
*
* @param outLength pointer to where the name length, in
* characters, will be returned. Set to NULL to ignore
* the output length. Defaults to NULL.
*
* @return the full path file name for this file,
* in platform-specific form. Must be destroyed by caller.
* The returned string is '\0' terminated, but this
* extra character is not included in the length.
* Must be destroyed by caller.
*/
char *getFullFileName( int *outLength = NULL );
/**
* Gets the pathless name of this file.
*
* @param outLength pointer to where the name length, in
* characters, will be returned. Set to NULL to ignore
* the output length. Defaults to NULL.
*
* @return the name of this file. Must be destroyed by caller.
*/
char *getFileName( int *outLength = NULL );
/**
* Reads the contents of this file.
*
* @return a \0-terminated string containing the file contents,
* or NULL if reading the file into memory failed.
* Must be destroyed by caller.
*/
char *readFileContents();
/**
* Reads the contents of this file.
*
* @param outLength pointer to where the return array length should
* be returned.
* @param inTextMode true to open the file as text, false as binary.
* Defaults to false.
*
* @return an array containing the binary file contents,
* or NULL if reading the file into memory failed.
* Must be destroyed by caller.
*/
unsigned char *readFileContents( int *outLength,
char inTextMode = false );
/**
* Writes a string to this file.
*
* @param inString the \0-terminated string to write.
* Must be destroyed by caller if non-const.
*
* @return true if the file was written to successfully, or
* false otherwise.
*/
char writeToFile( const char *inString );
/**
* Writes a binary data to this file.
*
* @param inData the data to write.
* Must be destroyed by caller if non-const.
* @param inLength length of inData.
*
* @return true if the file was written to successfully, or
* false otherwise.
*/
char writeToFile( unsigned char *inData, int inLength );
private:
Path *mPath;
char *mName;
int mNameLength;
/**
* Gets the files contained in this file if it is a directory and
* recursively in subdirectories of this file.
*
* @param inDepthLimit the maximum subdirectory depth to recurse into.
* If inDepthLimit is 0, then only child files in this directory
* will be returned.
* @param inResultVector vector to add the discovered files to.
* Must be destroyed by caller.
*/
void getChildFilesRecursive( int inDepthLimit,
SimpleVector<File *> *inResultVector );
};
inline File::File( Path *inPath, const char *inName, int inNameLength )
: mPath( inPath ), mNameLength( inNameLength ) {
if( inNameLength == -1 ) {
inNameLength = strlen( inName );
mNameLength = inNameLength;
}
// copy name internally
mName = stringDuplicate( inName );
}
inline File::~File() {
delete [] mName;
if( mPath != NULL ) {
delete mPath;
}
}
inline long File::getLength() {
struct stat fileInfo;
// get full file name
int length;
char *stringName = getFullFileName( &length );
int statError = stat( stringName, &fileInfo );
delete [] stringName;
if( statError == 0 ) {
return fileInfo.st_size;
}
else {
// file does not exist
return 0;
}
}
inline char File::isDirectory() {
struct stat fileInfo;
// get full file name
int length;
char *stringName = getFullFileName( &length );
int statError = stat( stringName, &fileInfo );
delete [] stringName;
if( statError == -1 ) {
return false;
}
else {
return S_ISDIR( fileInfo.st_mode );
}
}
inline File **File::getChildFiles( int *outNumFiles ) {
int length;
char *stringName = getFullFileName( &length );
DIR *directory = opendir( stringName );
if( directory != NULL ) {
SimpleVector< File* > *fileVector = new SimpleVector< File* >();
struct dirent *entry = readdir( directory );
if( entry == NULL ) {
delete fileVector;
closedir( directory );
delete [] stringName;
*outNumFiles = 0;
return NULL;
}
while( entry != NULL ) {
// skip parentdir and thisdir files, if they occur
if( strcmp( entry->d_name, "." ) &&
strcmp( entry->d_name, ".." ) ) {
Path *newPath;
if( mPath != NULL ) {
newPath = mPath->append( mName );
}
else {
if( Path::isRoot( mName ) ) {
// use name as a string path
newPath = new Path( mName );
}
else {
char **folderPathArray = new char*[1];
folderPathArray[0] = mName;
// a non-absolute path to this directory's contents
int numSteps = 1;
char absolute = false;
newPath =
new Path( folderPathArray, numSteps,
absolute );
delete [] folderPathArray;
}
}
// safe to pass d_name in directly because it is copied
// internally by the constructor
fileVector->push_back(
new File( newPath,
entry->d_name,
strlen( entry->d_name ) ) );
}
entry = readdir( directory );
}
// now we have a vector full of this directory's files
int vectorSize = fileVector->size();
*outNumFiles = vectorSize;
if( vectorSize == 0 ) {
delete fileVector;
closedir( directory );
delete [] stringName;
return NULL;
}
else {
File **returnFiles = new File *[vectorSize];
for( int i=0; i<vectorSize; i++ ) {
returnFiles[i] = *( fileVector->getElement( i ) );
}
delete fileVector;
closedir( directory );
delete [] stringName;
return returnFiles;
}
}
else {
delete [] stringName;
*outNumFiles = 0;
return NULL;
}
}
inline File **File::getChildFilesRecursive( int inDepthLimit,
int *outNumFiles ) {
// create a vector for results
SimpleVector<File *> *resultVector = new SimpleVector<File *>();
// call the recursive function
getChildFilesRecursive( inDepthLimit, resultVector );
// extract results from vector
File **resultArray = NULL;
int numResults = resultVector->size();
if( numResults > 0 ) {
resultArray = resultVector->getElementArray();
}
delete resultVector;
*outNumFiles = numResults;
return resultArray;
}
inline void File::getChildFilesRecursive(
int inDepthLimit,
SimpleVector<File *> *inResultVector ) {
// get our child files
int numChildren;
File **childFiles = getChildFiles( &numChildren );
if( childFiles != NULL ) {
// for each child, add it to vector and
// recurse into it if it is a directory
for( int i=0; i<numChildren; i++ ) {
File *child = childFiles[i];
// add it to results vector
inResultVector->push_back( child );
if( child->isDirectory() ) {
// skip recursion if we have hit our depth limit
if( inDepthLimit > 0 ) {
// recurse into this subdirectory
child->getChildFilesRecursive( inDepthLimit - 1,
inResultVector );
}
}
}
delete [] childFiles;
}
}
inline File *File::getChildFile( const char *inChildFileName ) {
// make sure we are a directory
if( !isDirectory() ) {
return NULL;
}
// get a path to this directory
Path *newPath;
if( mPath != NULL ) {
newPath = mPath->append( mName );
}
else {
char **folderPathArray = new char*[1];
folderPathArray[0] = mName;
// a non-absolute path to this directory's contents
int numSteps = 1;
char absolute = false;
newPath =
new Path( folderPathArray, numSteps,
absolute );
delete [] folderPathArray;
}
return new File( newPath, inChildFileName );
}
inline File *File::getParentDirectory() {
if( mPath != NULL ) {
char *parentName;
Path *parentPath;
if( strcmp( mName, ".." ) == 0 ) {
// already a parent dir reference
// append one more parent dir reference with parentName below
parentPath = mPath->append( ".." );
parentName = stringDuplicate( ".." );
}
else {
// not a parent dir reference, so we can truncate
parentPath = mPath->truncate();
parentName = mPath->getLastStep();
}
File *parentFile = new File( parentPath, parentName );
delete [] parentName;
return parentFile;
}
else {
if( Path::isRoot( mName ) ) {
// we are already at the root
return new File( NULL, mName );
}
else {
// append parent dir symbol to path
char **parentPathSteps = new char*[1];
parentPathSteps[0] = mName;
Path *parentPath = new Path( parentPathSteps, 1, false );
const char *parentName = "..";
File *parentFile = new File( parentPath, parentName );
delete [] parentPathSteps;
return parentFile;
}
}
}
inline char File::exists() {
struct stat fileInfo;
// get full file name
int length;
char *stringName = getFullFileName( &length );
int statError = stat( stringName, &fileInfo );
delete [] stringName;
if( statError == 0 ) {
return true;
}
else {
// file does not exist
return false;
}
}
inline unsigned long File::getModificationTime() {
struct stat fileInfo;
// get full file name
int length;
char *stringName = getFullFileName( &length );
int statError = stat( stringName, &fileInfo );
delete [] stringName;
if( statError == 0 ) {
return fileInfo.st_mtime;
}
else {
// file does not exist
return 0;
}
}
inline char File::remove() {
char returnVal = false;
if( exists() ) {
char *stringName = getFullFileName();
int error = ::remove( stringName );
if( error == 0 ) {
returnVal = true;
}
delete [] stringName;
}
return returnVal;
}
inline File *File::copy() {
Path *pathCopy = NULL;
if( mPath != NULL ) {
pathCopy = mPath->copy();
}
return new File( pathCopy, mName );
}
inline void File::copy( File *inDestination, long inBlockSize ) {
char *thisFileName = getFullFileName();
char *destinationFileName = inDestination->getFullFileName();
FILE *thisFile = fopen( thisFileName, "rb" );
FILE *destinationFile = fopen( destinationFileName, "wb" );
long length = getLength();
long bytesCopied = 0;
char *buffer = new char[ inBlockSize ];
while( bytesCopied < length ) {
long bytesToCopy = inBlockSize;
// end of file case
if( length - bytesCopied < bytesToCopy ) {
bytesToCopy = length - bytesCopied;
}
fread( buffer, 1, bytesToCopy, thisFile );
fwrite( buffer, 1, bytesToCopy, destinationFile );
bytesCopied += bytesToCopy;
}
fclose( thisFile );
fclose( destinationFile );
delete [] buffer;
delete [] thisFileName;
delete [] destinationFileName;
}
inline char *File::getFileName( int *outLength ) {
char *returnName = stringDuplicate( mName );
if( outLength != NULL ) {
*outLength = mNameLength;
}
return returnName;
}
inline char *File::getFullFileName( int *outLength ) {
int length = mNameLength;
int pathLength = 0;
char *path = NULL;
if( mPath != NULL ) {
path = mPath->getPathString( &pathLength );
length += pathLength;
}
// extra character for '\0' termination
char *returnString = new char[ length + 1 ];
if( path != NULL ) {
memcpy( returnString, path, pathLength );
memcpy( &( returnString[pathLength] ), mName, mNameLength );
delete [] path;
}
else {
// no path, so copy the name directly in
memcpy( returnString, mName, mNameLength );
}
// terminate the string
returnString[ length ] = '\0';
if( outLength != NULL ) {
*outLength = length;
}
return returnString;
}
#include "minorGems/io/file/FileInputStream.h"
#include "minorGems/io/file/FileOutputStream.h"
inline char *File::readFileContents() {
int length;
// text mode!
unsigned char *data = readFileContents( &length, true );
if( data == NULL ) {
return NULL;
}
char *dataString = new char[ length + 1 ];
memcpy( dataString, data, length );
dataString[ length ] = '\0';
delete [] data;
return dataString;
}
inline unsigned char *File::readFileContents( int *outLength,
char inTextMode ) {
if( exists() ) {
int length = getLength();
unsigned char *returnData = new unsigned char[ length ];
if( returnData != NULL ) {
FileInputStream *input = new FileInputStream( this, inTextMode );
int numRead = input->read( returnData, length );
delete input;
// in text mode, read length might not equal binary file length,
// due to line end conversion
if( numRead == length ||
( inTextMode && numRead >= 0 ) ) {
*outLength = numRead;
return returnData;
}
else {
delete [] returnData;
return NULL;
}
}
else {
// failed to allocate this much memory
return NULL;
}
}
else {
return NULL;
}
}
inline char File::writeToFile( const char *inString ) {
return writeToFile( (unsigned char *)inString, strlen( inString ) );
}
inline char File::writeToFile( unsigned char *inData, int inLength ) {
FileOutputStream *output = new FileOutputStream( this );
long numWritten = output->write( inData, inLength );
delete output;
if( inLength == numWritten ) {
return true;
}
else {
return false;
}
}
#include "Directory.h"
inline char File::makeDirectory() {
if( exists() ) {
return false;
}
else {
return Directory::makeDirectory( this );
}
}
#endif

View file

@ -0,0 +1,183 @@
/*
* Modification History
*
* 2001-February-11 Jason Rohrer
* Created.
*
* 2001-April-12 Jason Rohrer
* Changed so that File is not destroyed when this stream is destroyed.
*
* 2001-April-29 Jason Rohrer
* Fixed a bug in the use of fread
* (num elements and element size swapped).
* Fixed a memory leak in the error message handling.
*
* 2006-November-23 Jason Rohrer
* Fixed a memory leak in error message handling.
*
* 2010-April-22 Jason Rohrer
* Added support for text mode.
*/
#include "minorGems/common.h"
#ifndef FILE_INPUT_STREAM_CLASS_INCLUDED
#define FILE_INPUT_STREAM_CLASS_INCLUDED
#include "minorGems/io/InputStream.h"
#include "File.h"
#include <stdio.h>
/**
* File implementation of an InputStream.
*
* @author Jason Rohrer
*/
class FileInputStream : public InputStream {
public:
/**
* Constructs an input stream.
*
* @param inFile the file to open for reading.
* If the file does not exist, all calls to read will fail.
* inFile is NOT destroyed when this class is destroyed.
* @param inTextMode true to open the file as text, false as binary.
* Defaults to false.
*/
FileInputStream( File *inFile, char inTextMode = false );
/**
* Destroys this stream and closes the file.
*/
~FileInputStream();
/**
* Gets the file attached to this stream.
*
* @return the file used by this stream.
* Should not be modified or destroyed by caller until after
* this class is destroyed.
*/
File *getFile();
// implementst InputStream interface
virtual long read( unsigned char *inBuffer, long inNumBytes );
private:
File *mFile;
FILE *mUnderlyingFile;
};
inline FileInputStream::FileInputStream( File *inFile, char inTextMode )
: mFile( inFile ) {
int fileNameLength;
char *fileName = mFile->getFullFileName( &fileNameLength );
if( inTextMode ) {
mUnderlyingFile = fopen( fileName, "r" );
}
else {
mUnderlyingFile = fopen( fileName, "rb" );
}
if( mUnderlyingFile == NULL ) {
// file open failed.
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer, "Opening file %s failed.", fileName );
setNewLastError( stringBuffer );
}
delete [] fileName;
}
inline FileInputStream::~FileInputStream() {
if( mUnderlyingFile != NULL ) {
fclose( mUnderlyingFile );
}
}
inline File *FileInputStream::getFile() {
return mFile;
}
inline long FileInputStream::read(
unsigned char *inBuffer, long inNumBytes ) {
if( mUnderlyingFile != NULL ) {
long numRead = fread( inBuffer, 1, inNumBytes, mUnderlyingFile );
if( numRead < inNumBytes ) {
int fileNameLength;
char *fileName = mFile->getFullFileName( &fileNameLength );
if( feof( mUnderlyingFile ) ) {
// we reached the end of the file.
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer, "Reached end of file %s on read.",
fileName );
setNewLastError( stringBuffer );
delete [] fileName;
}
else {
// some other kind of error occured
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer, "Reading from file %s failed.",
fileName );
setNewLastError( stringBuffer );
delete [] fileName;
if( numRead == 0 ) {
// a complete read failure
return -1;
}
}
}
return numRead;
}
else {
// file was not opened properly
int fileNameLength;
char *fileName = mFile->getFullFileName( &fileNameLength );
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer,
"File %s was not opened properly before reading.",
fileName );
delete [] fileName;
setNewLastError( stringBuffer );
return -1;
}
}
#endif

View file

@ -0,0 +1,175 @@
/*
* Modification History
*
* 2001-February-11 Jason Rohrer
* Created.
*
* 2001-April-12 Jason Rohrer
* Changed so that File is not destroyed when this stream is destroyed.
*
* 2001-April-29 Jason Rohrer
* Fixed a bug in the use of fwrite
* (num elements and element size swapped).
* Fixed a memory leak in the error message handling.
*
* 2006-August-22 Jason Rohrer
* Fixed include order bug.
*
* 2010-April-6 Jason Rohrer
* Fixed memory leak.
*/
#include "minorGems/common.h"
#include "File.h"
#ifndef FILE_OUTPUT_STREAM_CLASS_INCLUDED
#define FILE_OUTPUT_STREAM_CLASS_INCLUDED
#include "minorGems/io/OutputStream.h"
#include <stdio.h>
/**
* File implementation of an OutputStream.
*
* @author Jason Rohrer
*/
class FileOutputStream : public OutputStream {
public:
/**
* Constructs an output stream.
*
* @param inFile the file to open for writing.
* If the file does not exist, it will be created.
* inFile is NOT destroyed when this class is destroyed.
* @param inAppend set to true to append to file. If
* file does not exist, file is still created. Defaults
* to false.
*/
FileOutputStream( File *inFile, char inAppend = false );
/**
* Destroys this stream and closes the file.
*/
~FileOutputStream();
/**
* Gets the file attached to this stream.
*
* @return the file used by this stream.
* Should not be modified or destroyed by caller until after
* this class is destroyed.
*/
File *getFile();
// implementst OutputStream interface
virtual long write( unsigned char *inBuffer, long inNumBytes );
private:
File *mFile;
FILE *mUnderlyingFile;
};
inline FileOutputStream::FileOutputStream( File *inFile,
char inAppend )
: mFile( inFile ) {
int fileNameLength;
char *fileName = mFile->getFullFileName( &fileNameLength );
if( inAppend ) {
mUnderlyingFile = fopen( fileName, "ab" );
}
else {
mUnderlyingFile = fopen( fileName, "wb" );
}
if( mUnderlyingFile == NULL ) {
// file open failed.
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer, "Opening file %s failed.", fileName );
setNewLastError( stringBuffer );
}
delete [] fileName;
}
inline FileOutputStream::~FileOutputStream() {
if( mUnderlyingFile != NULL ) {
fclose( mUnderlyingFile );
}
}
inline File *FileOutputStream::getFile() {
return mFile;
}
inline long FileOutputStream::write(
unsigned char *inBuffer, long inNumBytes ) {
if( mUnderlyingFile != NULL ) {
long numWritten =
fwrite( inBuffer, 1, inNumBytes, mUnderlyingFile );
if( numWritten < inNumBytes ) {
int fileNameLength;
char *fileName = mFile->getFullFileName( &fileNameLength );
// some other kind of error occured
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer, "Writing to file %s failed.",
fileName );
setNewLastError( stringBuffer );
delete [] fileName;
if( numWritten == 0 ) {
// a complete write failure
return -1;
}
}
return numWritten;
}
else {
// file was not opened properly
int fileNameLength;
char *fileName = mFile->getFullFileName( &fileNameLength );
char *stringBuffer = new char[ fileNameLength + 50 ];
sprintf( stringBuffer,
"File %s was not opened properly before writing.",
fileName );
delete [] fileName;
setNewLastError( stringBuffer );
return -1;
}
}
#endif

615
minorGems/io/file/Path.h Normal file
View file

@ -0,0 +1,615 @@
/*
* Modification History
*
* 2001-February-12 Jason Rohrer
* Created.
*
* 2001-May-11 Jason Rohrer
* Added a version of getPathString that
* returns a '\0' terminated string.
*
* 2001-September-21 Jason Rohrer
* Added a missing include.
*
* 2001-September-23 Jason Rohrer
* Added a copy function.
* Made some comments more explicit.
* Changed the constructor to allow for const path step strings.
*
* 2001-November-3 Jason Rohrer
* Added a function for appending a string to a path.
* Changed the interface to the main constructor.
*
* 2002-March-29 Jason Rohrer
* Added Fortify inclusion.
*
* 2002-April-11 Jason Rohrer
* Fixed a variable scoping bug.
*
* 2002-July-2 Jason Rohrer
* Fixed a major memory leak in copy().
*
* 2002-August-1 Jason Rohrer
* Added support for path truncation.
* Added support for parsing platform-dependent path strings.
*
* 2003-May-29 Jason Rohrer
* Fixed a bug when an extra delimeters are at the end of the path.
* Fixed a bug when string path consists only of root.
*
* 2003-June-2 Jason Rohrer
* Fixed a bug in absolute path detection.
* Added platform-specific functions for root and absolute path detection.
* Fixed a memory bug when string path contains root only.
* Fixed a path step bug when path is root.
* Fixed bugs in truncate and append when non-default root string is used.
*
* 2005-August-29 Jason Rohrer
* Fixed an uninitialized variable warning.
*
* 2010-May-14 Jason Rohrer
* String parameters as const to fix warnings.
*/
#include "minorGems/common.h"
#ifndef PATH_CLASS_INCLUDED
#define PATH_CLASS_INCLUDED
#include <string.h>
#include "minorGems/util/stringUtils.h"
#ifdef FORTIFY
#include "minorGems/util/development/fortify/fortify.h"
#endif
/**
* Platform-independent file path interface. Contains
* all of path except for file name. Thus, appending
* a file name to the path will produce a complete file path.
*
* E.g., on Linux, file path:
* temp/files/
* file name:
* test.txt
* full path:
* temp/files/test.txt
*
* @author Jason Rohrer
*/
class Path {
public:
/**
* Constructs a path.
*
* @param inPathSteps an array of c-strings representing
* each step in the path, with no delimeters.
* For example, { "temp", "files" } to represent
* the linux path temp/files.
* Must be destroyed by caller since copied internally.
* @param inNumSteps the number of strings in the path.
* @param inAbsolute set to true to make this an absolute
* path. For example, in Linux, an absolute path
* is one that starts with '/', as in /usr/include/.
* The effects of inAbsolute vary by platform.
* @param inRootString the root string for this path if it
* is absolute, or NULL to specify a default root.
* Defaults to NULL.
* Must be destroyed by caller if non-NULL.
*/
Path( char **inPathSteps, int inNumSteps, char inAbsolute,
char *inRootString = NULL );
/**
* Constructs a path by parsing a platform-dependent path string.
*
* @param inPathSteps a \0-terminated string representing the path.
* Must be destroyed by caller.
*/
Path( const char *inPathString );
~Path();
/**
* Returns a complete, platform-dependent string path.
*
* @param outLength pointer to where the path length, in
* characters, will be returned.
*
* @return a new char array containing the path. Note
* that the string is not terminated by '\0'. Must
* be destroyed by the caller.
*/
char *getPathString( int *outLength );
/**
* Returns a complete, platform-dependent string path, terminated
* bye '\0'.
*
* @return a new char array containing the path. Note
* that the string IS terminated by '\0'. Must
* be destroyed by the caller.
*/
char *getPathStringTerminated();
/**
* Gets the platform-specific path delimeter.
*
* Note that this function is implemented separately for
* each supported platform.
*
* @return the path delimeter.
*/
static char getDelimeter();
/**
* Gets start characters for an absolute path.
*
* Note that this function is implemented separately for
* each supported platform.
*
* @param outLength pointer to where the string length, in
* characters, will be returned.
*
* @return the absolute path start string characters. For
* example, on Linux, this would be the string "/".
* Must be destroyed by the caller.
*/
static char *getAbsoluteRoot( int *outLength );
/**
* Gets whether a path string is absolute.
*
* Note that this function is implemented separately for
* each supported platform.
*
* @param inPathString the string to check.
* Must be destroyed by caller if non-const.
*
* @return true if the string is absolute, or false otherwise.
*/
static char isAbsolute( const char *inPathString );
/**
* Extracts the root string from a path string.
*
*
* @param inPathString the string to check.
* Must be destroyed by caller if non-const.
*
* @return the root string, or NULL if inPathString is not
* absolute. Must be destroyed by caller if non-NULL.
*/
static char *extractRoot( const char *inPathString );
/**
* Gets whether a path string is a root path.
*
* Note that this function is implemented separately for
* each supported platform. For example, on Unix, only "/"
* is the root path, while on Windows, both "c:\" and "d:\" might
* be root paths.
*
* @param inPathString the string to check.
* Must be destroyed by caller if non-const.
*
* @return true if the string is a root string, or false otherwise.
*/
static char isRoot( const char *inPathString );
/**
* Gets start string for an absolute path.
*
* @return the absolute path start string in \0-terminated form.
* Must be destroyed by the caller.
*/
static char *getAbsoluteRootString();
/**
* Copies this path.
*
* @return a new path that is a deep copy of this path.
*/
Path *copy();
/**
* Constructs a new path by appending an additional
* step onto this path.
*
* @param inStepString the step to add to this path.
* Must be destroyed by caller if non-const.
*
* @return a new path with the extra step.
* Must be destroyed by caller.
*/
Path *append( const char *inStepString );
/**
* Constructs a new path by removing the last step from this path.
*
* @return a new path, or NULL if there is only one step in this path.
* Must be destroyed by caller.
*/
Path *truncate();
/**
* Gets the last step in this path.
*
* @return the last step. Must be destroyed by caller.
*/
char *getLastStep();
private:
char **mPathSteps;
int mNumSteps;
int *mStepLength;
char mAbsolute;
// the root string of this path, if it is absolute
char *mRootString;
};
inline Path::Path( char **inPathSteps, int inNumSteps,
char inAbsolute, char *inRootString )
: mNumSteps( inNumSteps ), mAbsolute( inAbsolute ),
mRootString( NULL ) {
if( inRootString != NULL ) {
mRootString = stringDuplicate( inRootString );
}
// copy the path steps
mPathSteps = new char*[ mNumSteps ];
mStepLength = new int[ mNumSteps ];
for( int i=0; i<mNumSteps; i++ ) {
int stepLength = strlen( inPathSteps[i] );
mPathSteps[i] = new char[ stepLength + 1 ];
memcpy( mPathSteps[i], inPathSteps[i], stepLength + 1 );
mStepLength[i] = stepLength;
}
}
inline Path::Path( const char *inPathString ) {
mAbsolute = isAbsolute( inPathString );
char *pathStringCopy = stringDuplicate( inPathString );
char delimeter = getDelimeter();
char *delimString = new char[ 2 ];
delimString[0] = delimeter;
delimString[1] = '\0';
char *pathRootSkipped;
if( !mAbsolute ) {
mRootString = NULL;
pathRootSkipped = pathStringCopy;
}
else {
// root occurs at start of path string
mRootString = extractRoot( inPathString );
pathRootSkipped = &( pathStringCopy[ strlen( mRootString ) ] );
}
// remove any trailing delimeters, if they exist
while( pathRootSkipped[ strlen( pathRootSkipped ) - 1 ] == delimeter ) {
pathRootSkipped[ strlen( pathRootSkipped ) - 1 ] = '\0';
}
char *currentDelimPointer = strstr( pathRootSkipped, delimString );
if( currentDelimPointer != NULL ) {
// first, count the delimeters
int delimCount = 0;
while( currentDelimPointer != NULL ) {
if( strlen( currentDelimPointer ) > 1 ) {
// don't count tail end delimeters
delimCount++;
}
currentDelimPointer = strstr( &( currentDelimPointer[1] ),
delimString );
}
// no delimeter at end of path
mNumSteps = delimCount + 1;
mPathSteps = new char*[ mNumSteps ];
mStepLength = new int[ mNumSteps ];
// now extract the chars between delimeters as path steps
currentDelimPointer = strstr( pathRootSkipped, delimString );
int stepIndex = 0;
currentDelimPointer[0] = '\0';
mPathSteps[ stepIndex ] = stringDuplicate( pathRootSkipped );
mStepLength[ stepIndex ] = strlen( mPathSteps[ stepIndex ] );
stepIndex++;
while( currentDelimPointer != NULL ) {
char *nextDelimPointer = strstr( &( currentDelimPointer[1] ),
delimString );
if( nextDelimPointer != NULL ) {
nextDelimPointer[0] = '\0';
}
mPathSteps[ stepIndex ] =
stringDuplicate( &( currentDelimPointer[1] ) );
mStepLength[ stepIndex ] = strlen( mPathSteps[ stepIndex ] );
stepIndex++;
currentDelimPointer = nextDelimPointer;
}
}
else {
// no delimeters
if( strlen( pathRootSkipped ) > 0 ) {
mNumSteps = 1;
mPathSteps = new char*[1];
mPathSteps[0] = stringDuplicate( pathRootSkipped );
mStepLength = new int[1];
mStepLength[0] = strlen( mPathSteps[0] );
}
else {
// path with root only
mNumSteps = 0;
mPathSteps = new char*[0];
mStepLength = new int[0];
}
}
delete [] delimString;
delete [] pathStringCopy;
}
inline Path::~Path() {
// delete each step
for( int i=0; i<mNumSteps; i++ ) {
delete [] mPathSteps[i];
}
delete [] mPathSteps;
delete [] mStepLength;
if( mRootString != NULL ) {
delete [] mRootString;
}
}
inline char *Path::getPathString( int *outLength ) {
int length = 0;
// length = sum( length each step string + 1 )
// ( + 1 is for the delimeter that occurs after each step string )
int i;
for( i=0; i<mNumSteps; i++ ) {
length += mStepLength[i] + 1;
}
// if absolute, we need to add in the length of the root
char *rootString = NULL;
int rootLength = 0;
if( mAbsolute ) {
if( mRootString != NULL ) {
rootString = stringDuplicate( mRootString );
rootLength = strlen( mRootString );
}
else {
rootString = getAbsoluteRoot( &rootLength );
}
length += rootLength;
}
char *returnString = new char[ length ];
int index = 0;
if( rootString != NULL ) {
// write root into string
memcpy( &( returnString[index] ), rootString, rootLength );
index += rootLength;
delete [] rootString;
}
char delimeter = getDelimeter();
// write each step into the string
for( i=0; i<mNumSteps; i++ ) {
memcpy( &( returnString[index] ), mPathSteps[i], mStepLength[i] );
index += mStepLength[i];
returnString[ index ] = delimeter;
index++;
}
*outLength = length;
return returnString;
}
inline char *Path::getPathStringTerminated() {
int length;
char *pathString = getPathString( &length );
char *delimitedPathString = new char[ length + 1 ];
memcpy( delimitedPathString, pathString, length );
delimitedPathString[ length ] = '\0';
delete [] pathString;
return delimitedPathString;
}
inline Path *Path::copy() {
// the steps will be copied internally
return new Path( mPathSteps, mNumSteps, mAbsolute, mRootString );
}
inline Path *Path::append( const char *inStepString ) {
char **newPathSteps = new char*[ mNumSteps + 1 ];
// shallow copy, since the strings themselves
// are copied in the Path constructor below
for( int i=0; i<mNumSteps; i++ ) {
newPathSteps[i] = mPathSteps[i];
}
// append final step
newPathSteps[ mNumSteps ] = (char*)inStepString;
Path *newPath = new Path( newPathSteps, mNumSteps + 1, mAbsolute,
mRootString );
// shallow delete, because of shallow copy above
delete [] newPathSteps;
return newPath;
}
inline Path *Path::truncate() {
if( mNumSteps < 2 && !mAbsolute ) {
return NULL;
}
else if( mNumSteps < 1 ) {
return NULL;
}
char **newPathSteps = new char*[ mNumSteps ];
// shallow copy, since the strings themselves
// are copied in the Path constructor below
for( int i=0; i<mNumSteps-1; i++ ) {
newPathSteps[i] = mPathSteps[i];
}
Path *newPath = new Path( newPathSteps, mNumSteps - 1, mAbsolute,
mRootString );
// shallow delete, because of shallow copy above
delete [] newPathSteps;
return newPath;
}
inline char *Path::getLastStep() {
if( mNumSteps >= 1 ) {
return stringDuplicate( mPathSteps[ mNumSteps - 1 ] );
}
else {
if( mAbsolute ) {
if( mRootString != NULL ) {
return stringDuplicate( mRootString );
}
else {
return getAbsoluteRootString();
}
}
else {
// no path steps and not absolute...
return stringDuplicate( "" );
}
}
}
inline char *Path::getAbsoluteRootString() {
int rootLength;
char *root = getAbsoluteRoot( &rootLength );
char *rootString = new char[ rootLength + 1 ];
strncpy( rootString, root, rootLength );
// strncopy won't add termination if length limit reached
rootString[ rootLength ] = '\0';
delete [] root;
return rootString;
}
#endif

View file

@ -0,0 +1,138 @@
// Jason Rohrer
// UniversalFileIO.h
/**
*
* Object that handles universal file reading and writing
* Writes files as big endian, even on little endian machines
*
* Assumes that longs and floats are 32-bits
*
* Created 1-12-99
* Mods:
* Jason Rohrer 1-30-2000 Fixed fwrite functions to work on little endian machines
*/
#ifndef UNIVERSAL_FILE_IO_INCLUDED
#define UNIVERSAL_FILE_IO_INCLUDED
#include <stdio.h>
class UniversalFileIO {
public:
UniversalFileIO();
long freadLong( FILE *f );
float freadFloat( FILE *f );
void fwriteLong( FILE *f, long x );
void fwriteFloat( FILE *f, float x );
private:
char machineBigEndian;
char bytesInLong;
char bytesInFloat;
};
inline UniversalFileIO::UniversalFileIO()
: machineBigEndian( true ),
bytesInLong( 4 ), bytesInFloat( 4 )
{
// test whether machine is big endian
long test = 1;
char testChopped = (*(char*)&test);
if( testChopped == 1 ) machineBigEndian = false;
}
inline long UniversalFileIO::freadLong( FILE *f ) {
if( machineBigEndian ) {
long returnVal;
fread((void *)&returnVal, sizeof(long), 1, f);
return returnVal;
}
else {
unsigned char *buffer = new unsigned char[bytesInLong];
fread((void *)buffer, sizeof(char), bytesInLong, f);
// now put the bytes into a long
long returnVal = (long)( buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3] );
delete [] buffer;
return returnVal;
}
}
inline float UniversalFileIO::freadFloat( FILE *f ) {
if( machineBigEndian ) {
float returnVal;
fread( (void *)&returnVal, sizeof(float), 1, f );
return returnVal;
}
else {
unsigned char *buffer = new unsigned char[bytesInFloat];
fread( (void *)buffer, sizeof(char), bytesInFloat, f );
// now put the bytes into a long
long temp = (long)(buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3]);
delete [] buffer;
return *((float *) &temp); // convert long into a float
}
}
inline void UniversalFileIO::fwriteLong( FILE *f, long x ) {
if( machineBigEndian ) {
fwrite( (void *)&x, sizeof(long), 1, f );
}
else {
unsigned char *buffer = new unsigned char[bytesInLong];
buffer[0] = (unsigned char)(x >> 24); // put bytes from long into char buffer
buffer[1] = (unsigned char)(x >> 16);
buffer[2] = (unsigned char)(x >> 8);
buffer[3] = (unsigned char)(x);
fwrite( (void *)buffer, sizeof(char), bytesInLong, f );
}
}
inline void UniversalFileIO::fwriteFloat( FILE *f, float x ) {
if( machineBigEndian ) {
fwrite( (void *)&x, sizeof(float), 1, f );
}
else {
unsigned char *buffer = new unsigned char[bytesInFloat];
long temp = *((long*)&x); // convert float into long so that bit-wise ops can be performed
buffer[0] = (unsigned char)(temp >> 24); // put bytes from float into char buffer
buffer[1] = (unsigned char)(temp >> 16);
buffer[2] = (unsigned char)(temp >> 8);
buffer[3] = (unsigned char)(temp);
fwrite( (void *)buffer, sizeof(char), bytesInFloat, f );
}
}
#endif

View file

@ -0,0 +1,77 @@
/*
* Modification History
*
* 2001-February-12 Jason Rohrer
* Created.
*
* 2001-August-1 Jason Rohrer
* Added missing length return value.
*
* 2003-June-2 Jason Rohrer
* Added support for new path checking functions.
*
* 2010-May-18 Jason Rohrer
* String parameters as const to fix warnings.
*/
#include "minorGems/io/file/Path.h"
#include "minorGems/util/stringUtils.h"
/*
* Linux-specific path implementation. May be compatible
* with other posix-complient systems.
*/
char Path::getDelimeter() {
return '/';
}
char *Path::getAbsoluteRoot( int *outLength ) {
char *returnString = new char[1];
returnString[0] = '/';
*outLength = 1;
return returnString;
}
char Path::isAbsolute( const char *inPathString ) {
if( inPathString[0] == '/' ) {
return true;
}
else {
return false;
}
}
char *Path::extractRoot( const char *inPathString ) {
if( isAbsolute( inPathString ) ){
return stringDuplicate( "/" );
}
else {
return NULL;
}
}
char Path::isRoot( const char *inPathString ) {
if( strcmp( inPathString, "/" ) == 0 ) {
return true;
}
else {
return false;
}
}

View file

@ -0,0 +1,73 @@
/*
* Modification History
*
* 2004-January-4 Jason Rohrer
* Created.
*/
/**
* A test program for the various child file functions in File.h
*
* @author Jason Rohrer.
*/
#include "minorGems/io/file/File.h"
int main( int inNumArgs, char **inArgs ) {
char *fileName = "linux";
if( inNumArgs > 1 ) {
fileName = inArgs[1];
}
File *testFile = new File( NULL, fileName );
int numChildren;
File **childFiles = testFile->getChildFiles( &numChildren );
printf( "child files:\n" );
for( int i=0; i<numChildren; i++ ) {
char *fullName = childFiles[i]->getFullFileName();
printf( " %s\n", fullName );
delete [] fullName;
delete childFiles[i];
}
delete [] childFiles;
childFiles = testFile->getChildFilesRecursive( 10, &numChildren );
printf( "recursive child files:\n" );
for( int i=0; i<numChildren; i++ ) {
char *fullName = childFiles[i]->getFullFileName();
printf( " %s\n", fullName );
delete [] fullName;
delete childFiles[i];
}
delete [] childFiles;
delete testFile;
return 0;
}

View file

@ -0,0 +1,39 @@
/*
* Modification History
*
* 2002-August-1 Jason Rohrer
* Created.
*/
#include "Path.h"
#include <stdio.h>
int main() {
char *pathString = "/test/this/thing";
printf( "using path string = %s\n", pathString );
printf( "Constructing path.\n" );
Path *path = new Path( pathString );
printf( "Extracting path string.\n" );
char *extractedPathString = path->getPathStringTerminated();
printf( "extracted path string = %s\n", extractedPathString );
delete [] extractedPathString;
delete path;
return 1;
}

View file

@ -0,0 +1,39 @@
/*
* Modification History
*
* 2002-August-1 Jason Rohrer
* Created.
*/
#include "Path.h"
#include <stdio.h>
int main() {
char *pathString = "/test/this/thing";
printf( "using path string = %s\n", pathString );
printf( "Constructing path.\n" );
Path *path = new Path( pathString );
printf( "Extracting path string.\n" );
char *extractedPathString = path->getPathStringTerminated();
printf( "extracted path string = %s\n", extractedPathString );
delete [] extractedPathString;
delete path;
return 1;
}

View file

@ -0,0 +1,51 @@
/*
* Modification History
*
* 2003-January-23 Jason Rohrer
* Created.
*
* 2003-November-10 Jason Rohrer
* Added makeDirectory function.
*/
#include "minorGems/io/file/Directory.h"
#include <unistd.h>
char Directory::removeDirectory( File *inFile ) {
char *fileName = inFile->getFullFileName();
int result = rmdir( fileName );
delete [] fileName;
if( result == 0 ) {
return true;
}
else {
return false;
}
}
char Directory::makeDirectory( File *inFile ) {
char *stringName = inFile->getFullFileName();
int result = mkdir( stringName, 0xFFFF );
delete [] stringName;
if( 0 == result ) {
return true;
}
else {
return false;
}
}

View file

@ -0,0 +1,53 @@
/*
* Modification History
*
* 2003-January-23 Jason Rohrer
* Created.
*
* 2003-November-10 Jason Rohrer
* Added makeDirectory function.
*/
#include "minorGems/io/file/Directory.h"
#include <direct.h>
char Directory::removeDirectory( File *inFile ) {
char *fileName = inFile->getFullFileName();
int result = _rmdir( fileName );
delete [] fileName;
if( result == 0 ) {
return true;
}
else {
return false;
}
}
char Directory::makeDirectory( File *inFile ) {
char *stringName = inFile->getFullFileName();
int result = mkdir( stringName );
delete [] stringName;
if( 0 == result ) {
return true;
}
else {
return false;
}
}

View file

@ -0,0 +1,95 @@
/*
* Modification History
*
* 2001-February-12 Jason Rohrer
* Created.
*
* 2001-March-4 Jason Rohrer
* Fixed delimeter constants.
*
* 2001-August-1 Jason Rohrer
* Added missing length return value.
*
* 2003-June-2 Jason Rohrer
* Added support for new path checking functions.
*
* 2010-May-14 Jason Rohrer
* String parameters as const to fix warnings.
*/
#include "minorGems/io/file/Path.h"
#include "minorGems/util/stringUtils.h"
/*
* Windows-specific path implementation.
*/
char Path::getDelimeter() {
return '\\';
}
char *Path::getAbsoluteRoot( int *outLength) {
// C:\ is the only root we can generically return
char *returnString = new char[3];
returnString[0] = 'C';
returnString[1] = ':';
returnString[2] = '\\';
*outLength = 3;
return returnString;
}
char Path::isAbsolute( const char *inPathString ) {
// ignore first character, which will be drive letter
if( inPathString[1] == ':' && inPathString[2] == '\\' ) {
return true;
}
else {
return false;
}
}
char *Path::extractRoot( const char *inPathString ) {
if( isAbsolute( inPathString ) ){
// copy path, then trim to only three characters
char *pathCopy = stringDuplicate( inPathString );
pathCopy[ 3 ] = '\0';
char *trimmedCopy = stringDuplicate( pathCopy );
delete [] pathCopy;
return trimmedCopy;
}
else {
return NULL;
}
}
char Path::isRoot( const char *inPathString ) {
// must be of form "c:\"
if( strlen( inPathString ) == 3 &&
inPathString[1] == ':' &&
inPathString[2] == '\\' ) {
return true;
}
else {
return false;
}
}

View file

@ -0,0 +1,159 @@
/*
* Modification History
*
* 2002-April-7 Jason Rohrer
* Added a mkdir wrapper for CodeWarrior.
*
* 2002-April-11 Jason Rohrer
* Changed type of mode parameter to work with Visual C++.
* Added missing include.
*
* 2002-July-22 Jason Rohrer
* Commented out mkdir replacement function to work with new MSL.
*
* 2002-October-13 Jason Rohrer
* Re-added mkdir wrapper function, since both CW4 and VC++ need it.
*/
/*
Implementation of POSIX directory browsing functions and types for Win32.
Kevlin Henney (mailto:kevlin@acm.org), March 1997.
Copyright Kevlin Henney, 1997. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that this copyright and permissions notice appear in all copies and
derivatives, and that no charge may be made for the software and its
documentation except to cover cost of distribution.
This software is supplied "as is" without express or implied warranty.
But that said, if there are any problems please get in touch.
*/
#include <dirent.h>
#include <errno.h>
#include <io.h>
#include <stdlib.h>
#include <string.h>
#include <direct.h>
struct DIR
{
long handle; /* -1 for failed rewind */
struct _finddata_t info;
struct dirent result; /* d_name null iff first time */
char *name; /* NTBS */
};
DIR *opendir(const char *name)
{
DIR *dir = 0;
if(name && name[0])
{
size_t base_length = strlen(name);
const char *all = /* the root directory is a special case... */
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
if((dir = (DIR *) malloc(sizeof *dir)) != 0 &&
(dir->name = (char *) malloc(base_length + strlen(all) + 1)) != 0)
{
strcat(strcpy(dir->name, name), all);
if((dir->handle = _findfirst(dir->name, &dir->info)) != -1)
{
dir->result.d_name = 0;
}
else /* rollback */
{
free(dir->name);
free(dir);
dir = 0;
}
}
else /* rollback */
{
free(dir);
dir = 0;
errno = ENOMEM;
}
}
else
{
errno = EINVAL;
}
return dir;
}
int closedir(DIR *dir)
{
int result = -1;
if(dir)
{
if(dir->handle != -1)
{
result = _findclose(dir->handle);
}
free(dir->name);
free(dir);
}
if(result == -1) /* map all errors to EBADF */
{
errno = EBADF;
}
return result;
}
struct dirent *readdir(DIR *dir)
{
struct dirent *result = 0;
if(dir && dir->handle != -1)
{
if(!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1)
{
result = &dir->result;
result->d_name = dir->info.name;
}
}
else
{
errno = EBADF;
}
return result;
}
void rewinddir(DIR *dir)
{
if(dir && dir->handle != -1)
{
_findclose(dir->handle);
dir->handle = _findfirst(dir->name, &dir->info);
dir->result.d_name = 0;
}
else
{
errno = EBADF;
}
}
int mkdir( const char *pathname, unsigned int mode ) {
return mkdir( pathname );
}

View file

@ -0,0 +1,77 @@
/*
* Modification History
*
* 2002-April-7 Jason Rohrer
* Added a mkdir wrapper for CodeWarrior.
*
* 2002-April-11 Jason Rohrer
* Changed type of mode parameter to work with Visual C++.
* Added missing macros.
*
* 2002-July-22 Jason Rohrer
* Commented out mkdir replacement function to work with new MSL.
*
* 2002-October-13 Jason Rohrer
* Re-added mkdir wrapper function, since both CW4 and VC++ need it.
*/
#include "minorGems/common.h"
/*
Declaration of POSIX directory browsing functions and types for Win32.
Kevlin Henney (mailto:kevlin@acm.org), March 1997.
Copyright Kevlin Henney, 1997. All rights reserved.
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose is hereby granted without fee, provided
that this copyright and permissions notice appear in all copies and
derivatives, and that no charge may be made for the software and its
documentation except to cover cost of distribution.
*/
#ifndef DIRENT_INCLUDED
#define DIRENT_INCLUDED
typedef struct DIR DIR;
struct dirent
{
char *d_name;
};
DIR *opendir(const char *);
int closedir(DIR *);
struct dirent *readdir(DIR *);
void rewinddir(DIR *);
#include <sys/stat.h>
/**
* The Metrowerks Standard Library seems
* to have only a 1-parameter mkdir command in sys/stat.h.
*/
int mkdir( const char *pathname, unsigned int mode );
// make sure our needed macros are defined
// S_IFMT and S_IFDIR seem to be defined everywhere
#ifndef __S_ISTYPE
#define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
#endif
#ifndef S_ISDIR
#define S_ISDIR(mode) __S_ISTYPE((mode), S_IFDIR)
#endif
#endif