// // STATUS.CPP // // Source file for ArchiveLib 1.0 // // Copyright (c) 1994 Greenleaf Software, Inc. // All Rights Reserved // // CONTENTS // // ALStatus::operator new() // ALStatus::ALStatus() // ALStatus::~ALStatus() // ALStatus::SetError() // ALStatus::GetStatusString() // ALStatus::GetStatusDetail() // ALStatus::operator = () // // // DESCRIPTION // // This file contains LibMain() and the WEP() for ArchiveLib DLLs. // We don't really do anything exciting in the WEP, it is just // here for decoration. LibMain() has to set up memory allocation // for Borland. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // // #include "arclib.h" #pragma hdrstop #include #include // // void * ALStatus::operator new( size_t size ) // // ARGUMENTS: // // size : The number of bytes needed to create a new ALStatus object. // // RETURNS // // A pointer to the newly allocated storage area, or 0 if no storage // was available. // // DESCRIPTION // // When using a DLL, it is easy to get into a dangerous situation when // creating objects whose ctor and dtor are both in the DLL. The problem // arises because when you create an object using new, the memory for // the object will be allocated from the EXE. However, when you destroy // the object using delete, the memory is freed inside the DLL. Since // the DLL doesn't really own that memory, bad things can happen. // // But, you say, won't the space just go back to the Windows heap regardless // of who tries to free it? Maybe, but maybe not. If the DLL is using // a subsegment allocation scheme, it might do some sort of local free // before returning the space to the windows heap. That is the point where // you could conceivably cook your heap. // // By providing our own version of operator new inside this class, we // ensure that all memory allocation for the class will be done from // inside the DLL, not the EXE calling the DLL. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // #if defined( AL_BUILDING_DLL ) void AL_DLL_FAR * AL_PROTO ALStatus::operator new( size_t size ) { return ::new char[ size ]; } #endif // // ALStatus::ALStatus() // // ARGUMENTS: // // None. // // RETURNS // // Nothing, this is a constructor. // // DESCRIPTION // // This is the only constructor for objects of class ALStatus. It // initializes the detail length member to 129, which is a const and // won't change. The initial status is AL_SUCCESS, and there is no // detail string to start with. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // AL_PROTO ALStatus::ALStatus() : miStatusDetailLength( 129 ) { miStatus = AL_SUCCESS; mszStatusDetail = 0; } // // ALStatus::~ALStatus() // // ARGUMENTS: // // None, destructor. // // RETURNS // // None, destructor. // // DESCRIPTION // // The destructor has to free up any space allocated for the detailed // error status string. That's all. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // AL_PROTO ALStatus::~ALStatus() { if ( mszStatusDetail ) delete[] mszStatusDetail; } // // int ALStatus::SetError( int error, const char AL_DLL_FAR *fmt, ... ) // // ARGUMENTS: // // error : The new error code to set the miStatus member to. A value // less than 0 (AL_SUCCESS) will always be interpreted as // an error. // // fmt : A sprintf style formatting string. This is for the // message that is going to go into the status detail message. // // ... : Any additional arguments needed by the formatting string. // // // RETURNS // // error, the error code that just got passed in. // // DESCRIPTION // // I don't know why I did the status detail allocation the way it is // done here, it is really stupid. I should just allocate whatever space // is necessary after formatting the string. This will probably be // fixed in 1.x. // // This function is used to set the status of an object to an error state. // Normally this is done by sending an error code, along with a detailed // message explaining what went wrong and why. Note that to clear // and error state, you can pass AL_SUCCESS for the error code and // 0 for the format. The object will look like it is healthy and happy // after that. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // int AL_PROTO ALStatus::SetError( int error, const char AL_DLL_FAR *fmt, ... ) { char detail[ 256 ]; va_list argptr; miStatus = error; if ( fmt == 0 ) { if ( mszStatusDetail ) delete[] mszStatusDetail; mszStatusDetail = 0; } else { va_start( argptr, fmt ); vsprintf( detail, fmt, argptr ); va_end( argptr ); if ( mszStatusDetail == 0 ) mszStatusDetail = new char[ miStatusDetailLength ]; if ( mszStatusDetail ) { strncpy( mszStatusDetail, detail, miStatusDetailLength - 1 ); mszStatusDetail[ miStatusDetailLength - 1 ] = '\0'; } } return error; } // // const char * ALStatus::GetStatusString() // // ARGUMENTS: // // None. // // RETURNS // // A short ASCII translation of the current error code. // // DESCRIPTION // // Rather than just printing an error code number, it is usually more // helpful to translate that number into ASCII text, so a user or // programmer can read the description. This function is used to // do just that. It translates the current error code into a short // ASCII text string. Note that this is not the same as the detail // string, which is tailored for each specific occurrence of an error code. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // const char AL_DLL_FAR * AL_PROTO ALStatus::GetStatusString() { switch ( miStatus ) { case AL_SUCCESS : return "Success"; case AL_END_OF_FILE : return "End of file"; case AL_CANT_OPEN_BUFFER : return "Can't allocate buffer"; case AL_CANT_CREATE_ENGINE : return "Can't create compression engine"; case AL_CANT_CREATE_STORAGE_OBJECT: return "Can't create storage object"; case AL_CANT_ALLOCATE_MEMORY : return "Memory allocation failure"; case AL_RENAME_ERROR : return "Error renaming file"; case AL_CANT_OPEN_FILE : return "Can't open file"; case AL_SEEK_ERROR : return "Seek error"; case AL_READ_ERROR : return "Read error"; case AL_WRITE_ERROR : return "Write error"; case AL_DELETE_ERROR : return "File deletion error"; case AL_ILLEGAL_PARAMETER : return "Illegal parameter"; case AL_INTERNAL_ERROR : return "Internal error"; case AL_USER_ABORT : return "User abort"; case AL_SERVER_NOT_PRESENT : return "Server not present"; case AL_COMPRESSION_TYPE_MISMATCH : return "Mismatch in compression type"; case AL_NEED_LENGTH : return "Missing length parameter"; case AL_CRC_ERROR : return "CRC Error"; case AL_COMPARE_ERROR : return "Comparison error"; case AL_UNKNOWN_COMPRESSION_TYPE : return "Unknown compression type"; case AL_UNKNOWN_STORAGE_OBJECT : return "Unknown type of storage object"; case AL_INVALID_ARCHIVE : return "Invalid archive"; case AL_LOGIC_ERROR : return "Logic error"; case AL_BACKUP_FAILURE : return "Could not create backup"; case AL_GETSEL_ERROR : return "Error getting selections from list box"; case AL_DUPLICATE_ENTRY : return "Duplicate entry"; default : return "Unknown error"; } } // // const char * ALStatus::GetStatusDetail() const // // ARGUMENTS: // // None. // // RETURNS // // Guaranteed to return a valid character string. // // DESCRIPTION // // Whenever we set the error code for an object in ArchiveLib, we // call ALStatus::SetError(). At the same time that we set the // error code of the object to a non-zero value, we supply a formatted // string providing some detail about when and where the error // took place, maybe even including some other information provided by the // O/S. That information is stored in the detail string, which is a // private data member. This function provides the ability to get at // that detail string. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // const char AL_DLL_FAR * AL_PROTO ALStatus::GetStatusDetail() const { if ( mszStatusDetail ) return mszStatusDetail; else if ( miStatus == AL_SUCCESS ) return "No errors"; else return "Unable to allocate memory for error detail message"; } // // ALStatus & ALStatus::operator = ( ALStatus &rhs ) // // ARGUMENTS: // // rhs : Another ALStatus object that I want to copy into this object. // // RETURNS // // A reference to this. // // DESCRIPTION // // Somewhere in ArchiveLib I want to be able to copy one status // into another. This function does just that. It has to allocate // new space to make a copy of the detail string, and be sure to // free up any old space, and all that. // // REVISION HISTORY // // May 26, 1994 1.0A : First release // ALStatus AL_DLL_FAR & AL_PROTO ALStatus::operator = ( ALStatus AL_DLL_FAR &rhs ) { if ( rhs.mszStatusDetail == 0 ) { if ( mszStatusDetail ) { delete[] mszStatusDetail; mszStatusDetail = 0; } } else { if ( mszStatusDetail == 0 ) mszStatusDetail = new char[ miStatusDetailLength ]; if ( mszStatusDetail ) strcpy( mszStatusDetail, rhs.mszStatusDetail ); } miStatus = rhs.miStatus; return *this; }