// $Id: ccfile.cpp 1607 2006-07-29 20:24:58Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are 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 Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ /******************************************************************************************** CCFile.cpp - Contains the function declarations of the Kernel CCFile derived classes. These include: CCDiskFile, CCMemFile and CCMemTextFile. ********************************************************************************************/ #include "camtypes.h" //#include "costream.h" //#include "ccfile.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "zstream.h" // WEBSTER-Martin-29/12/96 no accusoft stuff #ifndef WEBSTER //#include "extfilts.h" #endif //WEBSTER #include //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "mario.h" //#include "nev.h" //#include "tim.h" DECLARE_SOURCE("$Revision: 1607 $"); CC_IMPLEMENT_DYNAMIC(CCFile, CCObject); CC_IMPLEMENT_DYNAMIC(CCLexFile, CCFile); CC_IMPLEMENT_DYNAMIC(CCStreamFile, CCLexFile); CC_IMPLEMENT_DYNAMIC(CCDiskFile, CCStreamFile); CC_IMPLEMENT_DYNAMIC(CCMemFile, CCLexFile); CC_IMPLEMENT_DYNAMIC(CCMemTextFile, CCMemFile); // Declare smart memory handling in Debug builds #define new CAM_DEBUG_NEW #define CHAR_EOF ((char)EOF) /******************************************************************************************** > CCFile::CCFile(BOOL ReportErrors, BOOL ThrowExceptions) Author: Neville_Humphrys (Xara Group Ltd) Created: 29/08/94 Inputs: Flags to specify whether reporting errors or throwing exceptions. Defaults specified to backward compatible. Set to report errors but not to throw exceptions. Outputs: None Returns: None Purpose: Default CCFile class constructor. Does nothing but set the reporting flags. Errors: None ********************************************************************************************/ CCFile::CCFile(BOOL ErrorReporting, BOOL ExceptionThrowing) { // Set our class variables from the passed in values ReportErrors = ErrorReporting; ThrowExceptions = ExceptionThrowing; // Default to no compression CompressData = FALSE; // Default to no GZipErrorID GZipErrorID = 0; } /******************************************************************************************** > BOOL CCFile::IsCompressionSet( ) Author: Neville_Humphrys (Xara Group Ltd) Created: 29/08/94 Inputs: None Outputs: None Returns: The state of the compression flag, TRUE if compression is on. Purpose: Allow the reading of the compression flag to see if all output data is compressed or not. ********************************************************************************************/ BOOL CCFile::IsCompressionSet( ) { return CompressData; } /******************************************************************************************** > BOOL CCFile::SetCompression( BOOL NewState) Author: Neville_Humphrys (Xara Group Ltd) Created: 29/08/94 Inputs: TRUE if want compression, false otherhwise. Outputs: None Returns: True, if it was successful, False otherwise. Purpose: Allow the setting of the compression flag so that all output data is compressed. ********************************************************************************************/ BOOL CCFile::SetCompression( BOOL NewState) { // BOOL OldState = CompressData; CompressData = NewState; BOOL ok = TRUE; // If turning compression On then start the compression up // else turn it off. if (NewState) { // Get the class itself to start the compression process up ok = StartCompression(); if (!ok) { CompressData = FALSE; } } else { // Get the class itself to start the compression process up ok = StopCompression(); } return ok; } /******************************************************************************************** > CCFile::GotError( UNIT errorID ) > CCFile::GotError( UNIT errorID , const TCHAR*) Author: Neville_Humphrys (Xara Group Ltd) Created: 29/08/94 Inputs: Unsigned interger which is the error id and possible error message string Outputs: None Returns: None Purpose: Error handler for the CCFile class. It uses flags set in the constructor to determine if the user requires errors to be reported or exceptions thrown. Errors: None SeeAlso: SetReportErrors; SetThrowExceptions ********************************************************************************************/ void CCFile::GotError( UINT32 errorID , const TCHAR* errorString) { ERROR3IF(errorString == 0, "errorString is null. Oh dear."); Error::SetError(errorID, errorString, 0); // Flag that no more reads/writes should happen by forcing bad() to return True/. // So that if the user continues to access the file then they should get an error. SetBadState(); #if !defined(EXCLUDE_FROM_XARLIB) // If the ReportErrors flag is set then report the error now. if (ReportErrors) InformError(); #endif // If the ThrowExceptions flag is set then throw an exception. // Use the CFileException with a generic or unknown error and make the ioserror // our error number. if (ThrowExceptions) { TRACE( _T("CCFile GotError call to throw exception\n") ); throw( CFileException( errorID ) ); // AfxThrowFileException(CFileException::generic, errorID); } } void CCFile::GotError( UINT32 errorID ) { // Expand certain types of error messages to make them more informative if ((errorID == _R(IDE_OPEN_ERROR)) || (errorID == _R(IDE_FILE_READ_ERROR)) || (errorID == _R(IDE_FILE_WRITE_ERROR)) ) // Make the error message contain handy information. SetFileErrorMessage(errorID); else if ((errorID == _R(IDE_ZOPEN_ERROR) ) || (errorID == _R(IDE_ZFILE_READ_ERROR)) || (errorID == _R(IDE_ZFILE_WRITE_ERROR)) ) // Make the error message contain handy information. SetZipFileErrorMessage(errorID); else Error::SetError(errorID, 0); // Flag that no more reads/writes should happen by forcing bad() to return True. // So that if the user continues to access the file then they should get an error. SetBadState(); #if !defined(EXCLUDE_FROM_XARLIB) // If the ReportErrors flag is set then report the error now. if (ReportErrors) InformError(); #endif // If the ThrowExceptions flag is set then throw an exception. // Use the CFileException with a generic or unknown error and make the ioserror // our error number. if (ThrowExceptions) { TRACE( _T("CCFile GotError call to throw exception\n") ); //TRACEUSER( "Chris", _T("EXCEPTION!!!!!")); //AfxDebugBreak(); throw( CFileException( errorID ) ); } } /******************************************************************************************** > BOOL CCFile::SetFileErrorMessage(UINT32 ErrorID) Author: Tim_Browse (Xara Group Ltd) Created: 02/11/94 Inputs: ErrorID - the ID of the string resource to use as the error message. Returns: TRUE if the error message was constructed ok; FALSE if not (e.g. string resource did not load). Purpose: Looks at the 'errno' variable to determine what kind of error occured, and uses the specified error resource string to make a helpful error message out of it. NB. The string must have two string fields, to be replaced as follows: #1%s = description of error #2%s = name of the file that went wrong. An example is _R(IDE_FILE_READ_ERROR): "A read error occured (#1%s) with the file: #2%s" SeeAlso: CCFile::GotError ********************************************************************************************/ BOOL CCFile::SetFileErrorMessage(UINT32 ErrorID) { UINT32 FileErrorID; // Work out which error description string to use... switch (errno) { case EACCES: // Permission denied FileErrorID = _R(IDE_FILE_PERM_DENIED); break; case EBADF: // Bad file number FileErrorID = _R(IDE_FILE_BAD_FILE); break; case EEXIST: // File already exists FileErrorID = _R(IDE_FILE_EXISTS); break; case EMFILE: // Too many open files FileErrorID = _R(IDE_FILE_TOO_MANY_OPEN); break; case ENOENT: // No such file or directory FileErrorID = _R(IDE_FILE_NO_EXIST); break; case ENOSPC: // No space left on device FileErrorID = _R(IDE_FILE_NO_SPACE); break; default: // Unknown error FileErrorID = _R(IDE_FILE_UNKNOWN); } // Load in this resource String_64 FileError; if (!FileError.Load(FileErrorID)) { // Error occured - just use the error number if( FileError._MakeMsg( _T("#1%d"), errno ) == 0 ) // Couldn't do this (we must be severely shafted by now!) - return error return FALSE; } // Get a shortened name for the file String_64 Filename; if (!GetName(&Filename)) { // Unable to get a name - substitute with "unknown" if (!Filename.Load(_R(IDE_FILE_UNKNOWN))) { // Error occured - just use the hard-coded literal "unknown" // (This was sanctioned by Phil) Filename = TEXT("unknown"); } } // Use this information to build an error string and pass it to the SetError() function. String_256 ErrorMsg; if (ErrorMsg.MakeMsg(ErrorID, (LPCTSTR) FileError, (LPCTSTR) Filename) == 0) // Error occured - maybe resource would not load...not much we can do now. return FALSE; Error::SetError(ErrorID, (TCHAR *) ErrorMsg, 0); // Error string was constructed ok return TRUE; } /******************************************************************************************** > BOOL CCFile::SetZipFileErrorMessage(UINT32 ErrorID) Author: Neville_Humphrys (Xara Group Ltd) Created: 1/6/94 Inputs: ErrorID - the ID of the string resource to use as the error message. Returns: TRUE if the error message was constructed ok; FALSE if not (e.g. string resource did not load). Purpose: Looks at the 'GZipErrorID' variable to determine what kind of error occured, and uses the specified error resource string to make a helpful error message out of it. NB. The string must have two string fields, to be replaced as follows: #1%s = description of error #2%s = name of the file that went wrong. An example is _R(IDE_FILE_READ_ERROR): "A read error occured (#1%s) with the file: #2%s" Exactly the same as above but is designed for zip file errors. SeeAlso: SetFileErrorMessage; CCFile::GotError ********************************************************************************************/ BOOL CCFile::SetZipFileErrorMessage(UINT32 ErrorID) { UINT32 ZipFileErrorID; // Work out which error description string to use... switch (GZipErrorID) { case Z_ERRNO: // Bad file number ZipFileErrorID = _R(IDE_ZFILE_ERRORNO); break; case Z_STREAM_ERROR: // Permission denied ZipFileErrorID = _R(IDE_ZFILE_STREAMERROR); break; case Z_DATA_ERROR: // Bad file number ZipFileErrorID = _R(IDE_ZFILE_DATAERROR); break; case Z_MEM_ERROR: // Bad file number ZipFileErrorID = _R(IDE_ZFILE_MEMORYERROR); break; case Z_BUF_ERROR: // Bad file number ZipFileErrorID = _R(IDE_ZFILE_BUFFERERROR); break; default: // Unknown error ZipFileErrorID = _R(IDE_ZFILE_BASEEERROR); } // Load in this resource String_64 FileError; if (!FileError.Load(ZipFileErrorID)) { // Error occured - just use the error number if( FileError._MakeMsg( _T("#1%d"), errno ) == 0 ) // Couldn't do this (we must be severely shafted by now!) - return error return FALSE; } // Get a shortened name for the file String_32 Filename; if (!GetName(&Filename)) { // Unable to get a name - substitute with "unknown" if (!Filename.Load(_R(IDE_FILE_UNKNOWN))) { // Error occured - just use the hard-coded literal "unknown" // (This was sanctioned by Phil) Filename = TEXT("unknown"); } } // Use this information to build an error string and pass it to the SetError() function. String_256 ErrorMsg; if (ErrorMsg.MakeMsg(ErrorID, (LPCTSTR) FileError, (LPCTSTR) Filename) == 0) // Error occured - maybe resource would not load...not much we can do now. return FALSE; Error::SetError(ErrorID, (TCHAR *) ErrorMsg, 0); // Error string was constructed ok return TRUE; } /******************************************************************************************** > BOOL CCFile::SetReportErrors( BOOL ) Author: Neville_Humphrys (Xara Group Ltd) Created: 29/08/94 Inputs: BOOL which is the TRUE/FALSE state required. Outputs: None Returns: Old state of the flag Purpose: Public way of setting the internal error handling flag to say whether errors are going to be reported or not. Errors: None SeeAlso: GotError; IsReportingSet; IsThrowingSet ********************************************************************************************/ BOOL CCFile::SetReportErrors( BOOL newState ) { BOOL OldState = ReportErrors; ReportErrors = newState; return OldState; } /******************************************************************************************** > BOOL CCFile::SetThrowExceptions( BOOL ) Author: Neville_Humphrys (Xara Group Ltd) Created: 29/08/94 Inputs: BOOL which is the TRUE/FALSE state required. Outputs: None Returns: Old state of the flag Purpose: Public way of setting the internal error handling flag to say whether errors are going to throw an exception or not. Errors: None SeeAlso: GotError; IsReportingSet; IsThrowingSet ********************************************************************************************/ BOOL CCFile::SetThrowExceptions( BOOL newState ) { BOOL OldState = ThrowExceptions; ThrowExceptions = newState; return OldState; } /******************************************************************************************** > BOOL CCFile::IsReportingSet() Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: None. Outputs: None Returns: True if error reporting flag is set. Purpose: Public way of checking the internal error reporting flag to say whether InformError is going to be called or not. Errors: None SeeAlso: GotError; SetReportErrors; SetThrowExceptions ********************************************************************************************/ BOOL CCFile::IsReportingSet() { return ReportErrors; } /******************************************************************************************** > BOOL CCFile::IsThrowingSet() Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: None. Outputs: None Returns: True if exception throwing flag is set. Purpose: Public way of checking the internal error throwing flag to say whether errors are going to throw an exception or not. Errors: None SeeAlso: GotError; SetReportErrors; SetThrowExceptions ********************************************************************************************/ BOOL CCFile::IsThrowingSet() { return ThrowExceptions; } /******************************************************************************************** > BOOL CCFile::GetName( StringBase* name) const Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: Pointer to a CCFile name Outputs: None Returns: True if a name has been set otherwise False. At present always returns False. Purpose: Given a CCFile*, you can ask for some sort of name which is associated with that file. For filenames it might be a filename, or a pathname, for resource files it might be "Default Bitmap" etc. These names could then be used for making error messages have some extra useful information in. Errors: None ********************************************************************************************/ BOOL CCFile::GetName( StringBase* name) const { return FALSE; } /******************************************************************************************** > virtual PathName CCFile::GetPathName() const Author: Justin_Flude (Xara Group Ltd) Created: 15/8/96 Returns: The path-name of this file. If the file doesn't support the notion of a file-path (as, for instance, CCMemFiles and CCStreamFiles), then returns an empty string. ********************************************************************************************/ PathName CCFile::GetPathName() const { PathName pn; return pn; } /******************************************************************************************** > CCFile& CCFile::operator>>(StringBase* buf) Author: Mario_Shamtani (Xara Group Ltd) Created: 1/9/93 Inputs: String buffer. Returns: Reference to the CCFile object. Purpose: Reads file until string buffer is full or end of line or end of file is met. SeeAlso: CCFile::read ********************************************************************************************/ CCFile& CCFile::operator>>(StringBase* buf) { return read(buf); } /******************************************************************************************** > CCFile& CCFile::operator<<(const StringBase& buf) Author: Mario_Shamtani (Xara Group Ltd) Created: 1/9/93 Inputs: buf - the string to write out to the file. Returns: Reference to the CCFile object. Purpose: Writes the charactors found in the String buffer. SeeAlso: CCFile::write ********************************************************************************************/ CCFile& CCFile::operator<<(const StringBase& buf) { return write(buf); } // These should be deleted soon..? CCFile &CCFile::get( char &buf ) { return read(buf); } CCFile &CCFile::put( const char &buf ) { return write((void *) &buf); } /******************************************************************************************** > virtual CCFile& CCFile::flush() Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Returns: Reference to the CCFile object. Purpose: Flushes a file's buffers. By default it does nothing - override it if you want it to do anything. (The CCDiskFile class overrides this function.) SeeAlso: CCDiskFile::flush ********************************************************************************************/ CCFile& CCFile::flush() { return (CCFile&) *this; } /******************************************************************************************** > BOOL CCFile::good() Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Returns: TRUE => file stream is ok. FALSE => an error has occured. Purpose: Simple base implentation of this function - just examines EOF status. It allows checking of the current file status to see if we should continue using the file or not. Override this function to provide more sophisticated error checking (the CCDiskFile class overrides this function). ********************************************************************************************/ BOOL CCFile::good() const { return !eof(); } /******************************************************************************************** > BOOL CCFile::bad() Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Returns: TRUE => An error has occured. FALSE => The file stream is ok. Purpose: Simple base implementation of this function - just examines EOF status. It allows checking of the current file status to see if we should continue using the file or not. Override this function to provide more sophisticated error checking (the CCDiskFile class overrides this function). ********************************************************************************************/ BOOL CCFile::bad() const { return eof(); } /******************************************************************************************** > BOOL CCFile::fail() Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Returns: TRUE => An error has occured. FALSE => The file stream is ok. Purpose: Simple base implementation of this function - just examines EOF status. It allows checking of the current file status to see if we should continue using the file or not. Override this function to provide more sophisticated error checking (the CCDiskFile class overrides this function). ********************************************************************************************/ BOOL CCFile::fail() const { return eof(); } //----------------------- /******************************************************************************************** CCLexFile ********************************************************************************************/ //----------------------- /******************************************************************************************** > CCLexFile::CCLexFile(BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Tim_Browse (Xara Group Ltd) (Altered by Neville 01/08/94) Created: 05/04/94 Purpose: Initialise a CCLexFile object. ********************************************************************************************/ CCLexFile::CCLexFile(BOOL ErrorReporting, BOOL ExceptionThrowing) : CCFile(ErrorReporting, ExceptionThrowing), CharsRead(0) { // Ensure that the buffers are NULL so that DeinitLexer() can be called // safely even if called after a failed InitLexer() call. LineBuf = NULL; Buf = NULL; TokenBuf = NULL; LexerInitialised = FALSE; TokenIsCached = FALSE; SeekingRequired = FALSE; IgnoreStringEscapeCodes = FALSE; DontFail = FALSE; //Graham's HTML parsing variables m_pcHTMLBuffer=NULL; } /******************************************************************************************** > CCLexFile::~CCLexFile() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Purpose: Deinitialises a CCLexFile object (calls DeinitLexer() for you). ********************************************************************************************/ CCLexFile::~CCLexFile() { DeinitLexer(); } // The size of the token buffer used for lexical analysis in the CCLexFile class. const INT32 TokenBufSize = 256; /******************************************************************************************** > BOOL CCLexFile::InitLexer(BOOL IsSeekingRequired = FALSE, BOOL DoIgnoreStringEscapeCodes = FALSE) Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Inputs: IsSeekingRequired - Set to TRUE and seekin and tellin will work, but all the lexfile stuff is slowed down a bit DoIgnoreStringEscapeCodes - Set to TRUE to force '\' chars in strings to be ignored (see below) Returns: TRUE if successful; FALSE otherwise. Purpose: Prepare the file object for performing lexical analysis on the input stream. This allocates the buffers and sets the various character sets to the default values: Whitespace: spaces and tabs Delimiters: none Comment: # String: Delimited by " and " (i.e. like C) Also resets the newline indent output used by PutNewLine() to 0; DoIgnoreStringEscapeCodes = Should escape codes in strings be ignored? e.g. Should "hello\r" turn into "hello" + CR, or should we ignore the \r code and hence leave the string unaltered? I.e. if DoIgnoreStringEscapeCodes is TRUE, then the '\' character in strings is left alone. Errors: Out of memory. SeeAlso: CCLexFile::SetWhitespace; CCLexFile::SetDelimiters; CCLexFile::SetCommentMarker; CCLexFile::SetStringDelimiters ********************************************************************************************/ BOOL CCLexFile::InitLexer(BOOL IsSeekingRequired, BOOL DoIgnoreStringEscapeCodes) { // If we've already been here before, get out of town. if (LexerInitialised) return TRUE; // Allocate buffer for reading in each line LineBuf = new String_256; if (LineBuf == NULL) return FALSE; // Allocate space for storing tokens while decoding a line TokenBuf = new TCHAR[TokenBufSize]; if (TokenBuf == NULL) { delete LineBuf; LineBuf = NULL; return FALSE; } // Get ready to parse tokens. TokenBuf[0] = 0; Ofs = 0; Ch = 0; Line = 0; // Make buffer pointer point to line buffer. Buf = (TCHAR *) (*LineBuf); CharsRead = 0; LastLinePos = (FilePos) 0; EOFFound = FALSE; // Set character classes to reasonable defaults. WhitespaceChars = " \t"; DelimiterChars = NULL; CommentMarker = '#'; StringDelimiters = "\"\""; // reset the current indent count and delta value IndentSpaces = 0; IndentDelta = 4; // If true then seeking and tellin lex files will work - slows things down a bit SeekingRequired = IsSeekingRequired; // Ignore '\' characters in string tokens? IgnoreStringEscapeCodes = DoIgnoreStringEscapeCodes; InitHTMLLexer(); LexerInitialised = TRUE; return TRUE; } /******************************************************************************************** > void CCLexFile::DeinitLexer() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Purpose: Frees up the dynamic objects allocated by CCLexFile::InitLexer. Can be called at any point, and should be called before the next call to InitLexer(), even if the last InitLexer() call has failed. SeeAlso: CCLexFile::InitLexer ********************************************************************************************/ void CCLexFile::DeinitLexer() { // Deallocate our buffers if (LineBuf != NULL) delete LineBuf; if (TokenBuf != NULL) delete [] TokenBuf; LineBuf = NULL; TokenBuf = NULL; Buf = NULL; DeleteHTMLBuffer(); LexerInitialised = FALSE; } /******************************************************************************************** > void CCLexFile::SetWhitespace(char *Str) Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Inputs: Str - the set of characters to treat as whitespace. Purpose: This function changes the set of characters that the lexical analyser treats as white space. Note that it defaults to tabs and spaces, but you can specify any set of characters you want - for example you could even pass in " tf" and it would treat spaces, lower case t's and lower case f's as whitespace characters. Tokens extracted by CCLexFile::GetToken never contain any whitespace characters. SeeAlso: CCLexFile::InitLexer; CCLexFile::GetToken ********************************************************************************************/ void CCLexFile::SetWhitespace(char *Str) { WhitespaceChars = Str; } /******************************************************************************************** > void CCLexFile::SetDelimiters(char *Str) Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Inputs: Str - the set of characters to be interpreted as token delimiters. Purpose: Change the set of characters that are treated as 'delimiters'. A delimiter character indicates that a token has finished. A delimiter character *will* be extracted by CCLexFile::GetToken, and returned on its own. For example, for the line "hello; there ();", processed with the set of delimiters ";()", you would get the following tokens out of CCLexFile::GetToken: MonoOn "hello" ";" "there" "(" ")" ";" MonoOff By default, the set of delimiter characters is empty. SeeAlso: CCLexFile::InitLexer; CCLexFile::GetToken ********************************************************************************************/ void CCLexFile::SetDelimiters(char *Str) { DelimiterChars = Str; } /******************************************************************************************** > void CCLexFile::SetCommentMarker(char ch) Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Inputs: ch - the character to use as the comment marker. Purpose: Change the character used to denote a comment token. Comments start from the comment character until the end of the line. So, for example, to set the lexer up for PostScript style comments, pass in '%' as the comment marker; for assembler style comments, pass in ';'. Multi-line comments are not supported. SeeAlso: CCLexFile::InitLexer; CCLexFile::GetToken ********************************************************************************************/ void CCLexFile::SetCommentMarker(char ch) { CommentMarker = ch; } /******************************************************************************************** > void CCLexFile::SetStringDelimiters(char *Str) Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Inputs: Str - the two-character string to indicate what characters to use to start and end strings. Purpose: Change the characters used to delimit a string. The lexer will handle strings as a special token type (see CCLexFile::GetToken). You can specify which characters delimit the strings - you pass in a two-character string; the first character is used to start the string,and the second is used to terminate it. The two characters can be the same. So, for example, for PostScript strings, use "()", or for C-style strings, use "\"\"". SeeAlso: CCLexFile::InitLexer; CCLexFile::GetToken ********************************************************************************************/ void CCLexFile::SetStringDelimiters(char *Str) { StringDelimiters = Str; } /******************************************************************************************** > BOOL CCLexFile::GetSimpleToken() Author: Mark_Neves (Xara Group Ltd) Created: 07/04/94 Inputs: - Purpose: A simplified interface onto GetToken(). The caller is not informed of token types TOKEN_COMMENT and TOKEN_EOL. The function returns TRUE if a TOKEN_NORMAL or TOKEN_STRING is read. FALSE is returned if TOKEN_EOF is read, or if FALSE is returned by GetToken(). SeeAlso: CCLexFile::GetToken ********************************************************************************************/ BOOL CCLexFile::GetSimpleToken() { BOOL ok; LexTokenType TokenType; do { do { ok = GetToken(); } while (DelimiterFound); TokenType = GetTokenType(); } while (ok && (TokenType != TOKEN_NORMAL) && (TokenType != TOKEN_STRING) && (TokenType != TOKEN_EOF)); return (ok && (TokenType != TOKEN_EOF)); } /******************************************************************************************** > BOOL CCLexFile::GetToken() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Returns: TRUE if all went well; FALSE otherwise. Purpose: Extract the next lexical token from the input stream of this file. Tokens are separated by whitespace, delimiters, line-breaks, or any combination of the three. Delimiters and line-breaks are returned as tokens (and may be ignored if desired); whitespace is never returned. Call CCLexFile::GetTokenType() to find out what kind of token was extracted. You can examine the token directly by looking at the buffer returned by CCLexFile::GetTokenBuf() (this is a const buffer so you may examine it, but not alter it). This buffer address will not change unless CCLexFile::InitLexer is called again, so it is safe to cache the return value of CCLexFile::GetTokenBuf. Errors: A 'string' token exceeded 256 characters in length. SeeAlso: CCLexFile::GetTokenType; CCLexFile::GetTokenBuf; CCLexFile::SetWhitespace; CCLexFile::SetDelimiters; CCLexFile::SetCommentMarker; CCLexFile::SetStringDelimiters; CCLexFile::InitLexer; CCLexFile ********************************************************************************************/ BOOL CCLexFile::GetToken() { // Check to see if the client has put a token back onto the input stream if (TokenIsCached) { // Yes - just return success to the caller and they will use the current token // again. TokenIsCached = FALSE; return TRUE; } DelimiterFound = FALSE; // No effect if at EOF if (EOFFound) { TokenType = TOKEN_EOF; TokenBuf[0] = 0; return TRUE; } // Ignore white space until we get something useful while (!EOFFound && IsWhitespace()) GetCh(); if (EOFFound) { TokenType = TOKEN_EOF; TokenBuf[0] = 0; return TRUE; } // Check for line breaks if (Ch == 0) { GetCh(); TokenType = TOKEN_EOL; return TRUE; } else if (Ch == StringDelimiters[0]) { // It's a string return GetStringToken(); } else if (Ch == CommentMarker) { // It's a comment - ignore the rest of this line camStrcpy( TokenBuf, Buf + Ofs - 1 ); TokenType = TOKEN_COMMENT; GetLine(); GetCh(); } // Extract the next token else { // Read until delimiter or white-space, and analyse result. // NB. 0-terminator ends a token => tokens cannot be split over a line. INT32 i = 0; if (IsDelim()) { // Found a delimiter token - just return it TokenBuf[i++] = Ch; GetCh(); DelimiterFound = TRUE; } else { do { TokenBuf[i++] = Ch; GetCh(); } while (!EOFFound && !IsDelim() && !IsWhitespace() && (Ch != 0)); } // Terminate the token TokenBuf[i] = 0; TokenType = TOKEN_NORMAL; } // Token extracted ok return TRUE; } /******************************************************************** Graham 15/5/97 CCLexFile: HTML parsing code The lexer above isn't suited to parsing HTML code. For example, it insists on breaking tokens at the end of lines, but HTML should be able to run over lines ignoring line break characters. And HTML tokens should be able to be any length...not just 256 characters. And so on. So it makes sense to do HTML parsing completely separately. This HTML lexer returns two sorts of tokens: TAGS Which start with < and end with > TEXT Which is anything in between tags. So for example, a file containing the characters Bold would produce three tokens: TAG TEXT Bold TAG Here's an example of how to use the lexer. This code reads all the HTML from a file pMyFile and prints out only the tags. (I haven't tested this code, of course, there might be the odd mistake). //First initialise the lexer. This function will call InitHTMLLexer(). InitLexer(); //And read HTML tokens from the file until we reach the end of the file while (!pMyFile->IsEndOfHTMLFile()) { //Tell the HTML lexer to get an HTML token into its buffer pMyFile->GetHTMLToken(); //Get the text buffer TCHAR* pcBuffer=pMyFile->GetHTMLTokenBuffer(); //Now, does the buffer contain a tag? if (pMyFile->IsHTMLTag()) { //Yes. So print it out. //Remember that pcBuffer may be NULL if it had nothing in it if (pcBuffer) TRACE(pcBuffer); } } //And deinitialise the lexer DeInitLexer(); Also see the function ImagemapFilter::WriteExistingDataHelper. ************************************************************************/ /******************************************************************************************** > void CCLexFile::InitHTMLLexer() Author: Graham_Walmsley (Xara Group Ltd) Created: 15/5/97 Inputs: - Returns: - Purpose: Initialises all the variables used in the HTML parsing code Errors: - SeeAlso: CCLexFile::InitLexer ********************************************************************************************/ void CCLexFile::InitHTMLLexer() { //Initialise the "character waiting" variables m_cWaitingCharacter=0; m_fIsCharacterWaiting=FALSE; //And delete the buffer DeleteHTMLBuffer(); //And say that we haven't reached the end of the file m_fEndOfHTMLFile=FALSE; //And say that the current token is not a tag m_fIsTag=FALSE; } /******************************************************************************************** > void CCLexFile::DeleteHTMLBuffer() Author: Graham_Walmsley (Xara Group Ltd) Created: 15/5/97 Inputs: - Returns: - Purpose: Deletes the HTML buffer and sets all the member variables that refer to it to appropriate defaults Errors: - SeeAlso: CCLexFile::InitHTMLLexer ********************************************************************************************/ void CCLexFile::DeleteHTMLBuffer() { if (m_pcHTMLBuffer) free( m_pcHTMLBuffer ); m_pcHTMLBuffer=NULL; m_iCharsInHTMLBuffer=0; m_iLengthOfHTMLBuffer=0; } /******************************************************************************************** > void CCLexFile::AddToHTMLBuffer(TCHAR &cToAdd) Author: Graham_Walmsley (Xara Group Ltd) Created: 15/5/97 Inputs: cToAdd - the character to add to the buffer Returns: - Purpose: Adds cToAdd to the buffer, extending the buffer if necessary. Errors: - SeeAlso: CCLexFile::GetHTMLToken ********************************************************************************************/ void CCLexFile::AddToHTMLBuffer( char cToAdd ) { //First, do we have an HTML buffer? if( NULL == m_pcHTMLBuffer ) { //No. So create one now m_iLengthOfHTMLBuffer = TokenBufSize; m_pcHTMLBuffer = (char *)malloc( m_iLengthOfHTMLBuffer ); m_iCharsInHTMLBuffer = 0; } //Now, is there enough room in our HTML buffer to store //our new character? if( m_iCharsInHTMLBuffer >= m_iLengthOfHTMLBuffer ) { //No. So double the size of the buffer m_iLengthOfHTMLBuffer *= 2; m_pcHTMLBuffer = (char *)realloc( m_pcHTMLBuffer, m_iLengthOfHTMLBuffer ); } ERROR3IF(m_pcHTMLBuffer==NULL, "AddToHTMLBUffer - realloc error"); //And finally add our character m_pcHTMLBuffer[m_iCharsInHTMLBuffer] = cToAdd; //And increase the number of characters in the buffer m_iCharsInHTMLBuffer++; } /******************************************************************************************** > BOOL CCLexFile::GetHTMLToken(BOOL fIgnoreEOL=TRUE, BOOL fCorrectCase=TRUE) Author: Graham_Walmsley (Xara Group Ltd) Created: 14/5/97 Inputs: fIgnoreReturns Whether all EOL characters should be removed from the text in the buffer. This is TRUE by default because HTML should normally ignore EOL characters fCorrectCase Whether the string should automatically be converted to upper case. This is TRUE by default because HTML should ignore case. Returns: TRUE if all went well; FALSE otherwise. Purpose: Get the next HTML token from the file. This works as follows: if the first character read in the token is a <, then the token will contain all the characters between that < and the following >. If the next character read is not a <, then the token will contain all the characters until the next <. So the token you get back from this function will either be an HTML tag: Alt text Or some text: This is some text Note that we read into a variable length buffer. This is because HTML tokens could be any length at all. So, as soon as you have called GetHTMLToken, you should call GetHTMLTokenBuffer to get a pointer to the string that has just been read. Errors: - SeeAlso: CCLexFile::GetToken; CCLexFile::GetHTMLTokenBuffer ********************************************************************************************/ BOOL CCLexFile::GetHTMLToken(BOOL fIgnoreEOL, BOOL fCorrectCase) { //First delete our buffer DeleteHTMLBuffer(); //Now, are we reading a tag or some text? //It depends on whether the first character we read is a < m_fIsTag=(PeekNextHTMLChar()=='<'); //Create a two-character buffer to read characters into //(Why is it a buffer, not a single character? Because the //function _tcsupr needs to be passed a null-terminated //string rather than a single character) TCHAR pcReadCharacter[2]; //But when does the HTML token end? If the token is a tag, it ends after the //next > is read. If the token is text, it ends just *before* the next < //is read. This condition is contained in the following while statement... while (!eof() && !(m_fIsTag && pcReadCharacter[0]=='>') && !(!m_fIsTag && PeekNextHTMLChar()=='<')) { //Read in a character pcReadCharacter[0]=ReadNextHTMLChar(); //And null terminate the string pcReadCharacter[1]='\0'; //Correct the string to uppercase if necessary if( fCorrectCase ) CharUpper( pcReadCharacter ); //If we just reached the end of the file, break if (eof()) break; //Now, are we ignoring end of line characters? //And is the character we've read an end of line character? if (!(fIgnoreEOL && (pcReadCharacter[0]=='\r' || pcReadCharacter[0]=='\n'))) { //No. So add the character to the buffer AddToHTMLBuffer(pcReadCharacter[0]); } } //If we reached the end of the file if (eof()) { //Then set our member flag m_fEndOfHTMLFile=TRUE; } //And NULL terminate the buffer AddToHTMLBuffer('\0'); //And return TRUE return TRUE; } /******************************************************************************************** > TCHAR CCLexFile::PeekNextHTMLChar() Author: Graham_Walmsley (Xara Group Ltd) Created: 14/5/97 Returns: The next character that will be read from the file Purpose: In theory, this function finds out what the next character that will be read from the file will be. But of course to find out what the next character in the file is, we have to read that character. So this is what we do. We read the character, but we put it into our member variable m_cWaitingCharacter. We also set our member flag m_fIsCharacterWaiting to TRUE. Then the function ReadNextHTMLCharacter will know there is a character waiting to be 'read' in m_cWaitingCharacter, and will return that character instead of actually reading one from the file. Not perfect but it works. Errors: - SeeAlso: CCLexFile::GetHTMLToken; CCLexFile::ReadNextHTMLChar ********************************************************************************************/ char CCLexFile::PeekNextHTMLChar() { //Is there a character waiting in m_cWaitingCharacter? if (!m_fIsCharacterWaiting) { //No. So read the next character into our "Waiting Character" buffer //We use "get" because "read" will throw an exception //if you try to read past the end of the file. get(m_cWaitingCharacter); //And remember there's a character waiting m_fIsCharacterWaiting=TRUE; } //Now return the waiting character return m_cWaitingCharacter; } /******************************************************************************************** > TCHAR CCLexFile::ReadNextHTMLChar() Author: Graham_Walmsley (Xara Group Ltd) Created: 14/5/97 Returns: The next character in the file Purpose: This function reads the next character from the file. Well, actually, the way it works is slightly more complicated. That's because the function PeekNextHTMLChar may have given us a character "waiting to be read" in m_cCharacterWaiting. If so, we should return that character first. See PeekNextHTMLChar for a better explanation. Errors: - SeeAlso: CCLexFile::GetHTMLToken; CCLexFile::PeekNextHTMLChar ********************************************************************************************/ char CCLexFile::ReadNextHTMLChar() { //Do we have a character waiting? if (m_fIsCharacterWaiting) { //Yes. So remember we no longer have a character waiting m_fIsCharacterWaiting=FALSE; //And return our waiting character return m_cWaitingCharacter; } else { //No. So simply read a new character from the file //We use "get" because "read" will throw an exception //if you try to read past the end of the file. char cToRead; get( cToRead ); return cToRead; } } /******************************************************************************************** > String_256 CCLexFile::GetHTMLTagName() Author: Graham_Walmsley (Xara Group Ltd) Created: 14/5/97 Returns: The name of the tag which is currently in the buffer Purpose: This function reads the name of the tag in the buffer. It does this by simply reading from the second character in the buffer to the first whitespace character (where whitespace is usually either a space or a tab). Also, if the token in the buffer is not a tag, this function returns FALSE. Errors: - SeeAlso: CCLexFile::GetHTMLToken ********************************************************************************************/ String_256 CCLexFile::GetHTMLTagName() { //Create an empty string to return String_256 strToReturn = ""; //If this isn't a tag, return that empty string if (!IsHTMLTag()) return strToReturn; //And, if there's less than two characters in the buffer, //return now if (m_iCharsInHTMLBuffer<2) return strToReturn; //Otherwise, start copying from the buffer to the string //Start with the second character (remember that the second //character is m_pcHTMLBuffer[1]) and finish //when either we find a whitespace character or we go //past the end of the string INT32 i; for( i = 1; ( i < 255 && i < ( m_iCharsInHTMLBuffer - 1 ) && !IsWhitespace( m_pcHTMLBuffer[i] ) && m_pcHTMLBuffer[i] != _T('>') ); i++ ) { strToReturn+=m_pcHTMLBuffer[i]; } // test for overflow if (i == 255) return ""; //Correct the string to upper case strToReturn.toUpper(); //And return our string return strToReturn; } /******************************************************************************************** > String_256 CCLexFile::GetHTMLParameterValue(String_256 strParameterName, BOOL fCorrectCase=TRUE) Author: Graham_Walmsley (Xara Group Ltd) Created: 14/5/97 Inputs: strParameterName The name of the parameter whose value we want to find. For example, in an image tag, we might want to find the value of 'SRC'. fCorrectCase TRUE if the value should be returned in uppercase FALSE if the value should be returned in its original case Returns: If the parameter is specified within the buffer (e.g. , then the value of that parameter will be returned without any enclosing quotes (e.g. www.xara.com will be returned, not "www.xara.com"). If the parameter is not specified within the buffer, an empty string will be returned. Purpose: Finds the value of the specified parameter. For example, if we search for the value of "ALT" and the buffer contains the text Alt Then the string returned will be Alt This is done as follows: first we make up a composite string consisting of the strParameterName with an equals sign on the end (e.g. "ALT="). Then we search for that string. If we find it: Then if the character after that string is a ", we return everything up until the next ". Otherwise, if the character after that string is not a ", we return everything up until the next > or whitespace character. Errors: - SeeAlso: CCLexFile::GetHTMLToken ********************************************************************************************/ String_256 CCLexFile::GetHTMLParameterValue( const String_256 &strParameterName, BOOL fCorrectCase ) { //Create an empty string to return String_256 strToReturn; //And, if there's less than two characters in the buffer, //return now if (m_iCharsInHTMLBuffer<2) return strToReturn; //So search for the string we have been told to search for PCSTR pcFound; #if 0 != wxUSE_UNICODE { size_t cchParam = camWcstombs( NULL, (const TCHAR *)strParameterName, 0 ) + 1; PSTR pszParam = PSTR( alloca( cchParam ) ); camWcstombs( pszParam, (const TCHAR *)strParameterName, cchParam ); pcFound = FindStringWithoutCase( m_pcHTMLBuffer, pszParam ); } #else pcFound = FindStringWithoutCase( m_pcHTMLBuffer, (const TCHAR *)strParameterName ); #endif //Have we found something? if (pcFound) { //Yes. So move our found pointer past the string we've found // pcFound = camStrninc( pcFound, strParameterName.Length() ); pcFound = pcFound + strParameterName.Length(); //We're now pointing to the character after the parameter name //If we're pointing to a whitespace character, move forward //to the first character that's not whitespace while (*pcFound!='\0' && IsWhitespace(*pcFound)) { // pcFound = camStrinc( pcFound ); pcFound++; } //If that character is not an equals, return an empty string if (*pcFound!='=') return strToReturn; //And, again, move our found pointer to the next character that's not a space do { // pcFound = camStrinc( pcFound ); pcFound++; } while (*pcFound!='\0' && IsWhitespace(*pcFound)); //Note that there is no way that pcFound can //have been advanced past the end of the buffer. //It may, possibly, have been advanced to the NULL //character at the end of the buffer, and I'll handle that... //Now, this variable will tell us whether the parameter value //is in quotes. Set to FALSE by default. BOOL fInQuotes=FALSE; //And is the parameter value in quotes? if (*pcFound=='\"') { //Yes. So make a note of that fInQuotes=TRUE; //And move on to the character after the quotes // pcFound=camStrinc(pcFound); pcFound++; } //Now, copy everything from the character we are pointing at //until... //IF the parameter value is in quotes, until the next " //OTHERWISE, until the next > or whitespace character while (*pcFound!='\0' && ((fInQuotes && *pcFound!='\"') || (!fInQuotes && (!IsWhitespace(*pcFound) && *pcFound!='>')))) { strToReturn+=*pcFound; // pcFound=camStrinc(pcFound); pcFound++; } } //And correct the case if necessary if (fCorrectCase) strToReturn.toUpper(); //And return the string //Note that if nothing was found, this string will be empty return strToReturn; } /******************************************************************************************** > TCHAR* CCLexFile::FindStringWithoutCase(TCHAR* strToSearch, TCHAR* strToFind) Author: Graham_Walmsley (Xara Group Ltd) Created: 20/5/97 Inputs: strToSearch The string in which to search strToFind The string to search for Returns: A pointer to the first occurrence of strToFind within strToSearch. Purpose: Finds strToFind within strToSearch. The find operation is done without regard to case - so, for example, the string "Map" would be found within the string "" Errors: - SeeAlso: CCLexFile::GetHTMLParameterValue ********************************************************************************************/ PCSTR CCLexFile::FindStringWithoutCase( PCSTR strToSearch, PCSTR strToFind ) { //We assume strToSearch and strToFind are valid //First set up a pointer to search strToSearch with PCSTR pcThisChar = strToSearch; //Now, while pcThisChar is valid while( pcThisChar != NULL && *pcThisChar != '\0' ) { //Is strToSearch from pcThisChar onwards the same //as strToFind, doing a case insensitive comparision? if( 0 == _strnicmp( pcThisChar, strToFind, strlen( strToFind ) ) ) { //Yes. So return TRUE return pcThisChar; } // pcThisChar = camStrinc(pcThisChar); pcThisChar++; } //Otherwise return NULL return NULL; } /******************************************************************************************** > BOOL CCLexFile::GetHexToken() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Returns: TRUE if all went well; FALSE otherwise. Purpose: Extract the next lexical token from the input stream of this file. The token is expected to be a string of hexadecimal digits, and its length should be an even number of characters. If whitespace or a delimiter is encountered then the token is returned ok. If any other character is found which is not a legal hex digit thenFALSE is returned. Errors: A 'string' token exceeded 256 characters in length. SeeAlso: CCLexFile::GetTokenType; CCLexFile::GetTokenBuf; CCLexFile::SetWhitespace; CCLexFile::SetDelimiters; CCLexFile::SetCommentMarker; CCLexFile::SetStringDelimiters; CCLexFile::InitLexer; CCLexFile ********************************************************************************************/ BOOL CCLexFile::GetHexToken() { // Check to see if the client has put a token back onto the input stream if (TokenIsCached) { // Yes - just return success to the caller and they will use the current token // again. // But for hex token we must check that it is a legal hex token... INT32 i = 0; while (TokenBuf[i] != 0) { if (!camIsxdigit(TokenBuf[i])) // Not valid hex data return FALSE; // Try next character i++; } // Valid hex data - return success. TokenIsCached = FALSE; return TRUE; } DelimiterFound = FALSE; // Keep ignoring whitespace/comments etc for(;;) { // No effect if at EOF if (EOFFound) { // Did not find a hex token TokenType = TOKEN_EOF; TokenBuf[0] = 0; return FALSE; } // Ignore white space until we get something useful while (!EOFFound && IsWhitespace()) GetCh(); if (EOFFound) { // Did not find a hex token TokenType = TOKEN_EOF; TokenBuf[0] = 0; return FALSE; } if (Ch == 0) { // Skip line breaks GetCh(); } else if (Ch == CommentMarker) { // It's a comment - ignore the rest of this line GetLine(); GetCh(); } else { // Ok - is it a hex digit? if (camIsxdigit(Ch)) // Yes - fall through to next bit of code to decode it break; else // No - so we can't find a hex string so return an error return FALSE; } } // Read until not a hexadecimal digit, and analyse result. // NB. 0-terminator ends a token => tokens cannot be split over a line. INT32 i = 0; // This loop is hugely critical (e.g. importing large bitmaps), so we resort to direct // buffer access and register variables. (sorry!) register TCHAR *pHexCh = Buf + Ofs - 1; while (camIsxdigit(*pHexCh)) { TokenBuf[i++] = *pHexCh++; } // Update the offset variable and Ch variable so we maintain lookahead. Ofs += i; Ch = Buf[Ofs-1]; // Set up token correctly. TokenBuf[i] = 0; TokenType = TOKEN_NORMAL; // End of hex data - is it a legal or illegal end? if ((i % 2) != 0) { // Not an even number of hex digits => illegal return FALSE; } // Inform caller if the hex data was terminated legally // (i.e. delimiter, whitespace or line-end) return (IsDelim() || IsWhitespace() || (Ch == 0)); } /******************************************************************************************** > void CCLexFile::UngetToken() Author: Tim_Browse (Xara Group Ltd) Created: 03/08/94 Purpose: Put the current token back onto the input stream - i.e. the next time GetToken() is called it will return the token it returned last time. This is not nestable - you can only put back one token at once. SeeAlso: CCLexFile::GetToken(); CCLexFile ********************************************************************************************/ void CCLexFile::UngetToken() { TokenIsCached = TRUE; } /******************************************************************************************** > BOOL CCLexFile::GetLineToken() Author: Tim_Browse (Xara Group Ltd) Created: 09/08/94 Returns: TRUE if all went well; FALSE otherwise. Purpose: Read in a token in a line-based manner. If the current input position is in the middle of a line, the data up until the end of the line is read. If at the start of a line, the whole line is returned. The token is still examined to work out what it is, but obviously it may not match any proper construct, in which case the type of the token is set to TOKEN_LINE. (NB this is the only time that TOKEN_LINE is used) SeeAlso: CCLexFile::GetToken; CCLexFile::GetSimpleToken; CCLexFile::UngetToken ********************************************************************************************/ BOOL CCLexFile::GetLineToken() { // Check to see if the client has put a token back onto the input stream if (TokenIsCached) { TokenIsCached = FALSE; if (Ofs == 1) { // We're at the start of the line, so the last token must have been the // wholeof the rest of the line, so just return it. return TRUE; } // Otherwise, we should append the rest of the current line to the token, // and work out the token type again. camStrcpy( TokenBuf + camStrlen( TokenBuf ), Buf + Ofs - 1 ); if (TokenBuf[0] == CommentMarker) { TokenType = TOKEN_COMMENT; } else { TokenType = TOKEN_LINE; } GetLine(); GetCh(); // We have a token return TRUE; } // No effect if at EOF if (EOFFound) { TokenType = TOKEN_EOF; TokenBuf[0] = 0; return TRUE; } // Ignore white space until we get something useful while (!EOFFound && IsWhitespace()) GetCh(); if (EOFFound) { TokenType = TOKEN_EOF; TokenBuf[0] = 0; return TRUE; } // Check for line breaks if (Ch == 0) { GetCh(); TokenType = TOKEN_EOL; return TRUE; } // Otherwise, just get the rest of the line... camStrcpy( TokenBuf, Buf + Ofs - 1 ); GetLine(); GetCh(); if (TokenBuf[0] == CommentMarker) { TokenType = TOKEN_COMMENT; } else { TokenType = TOKEN_LINE; } // Token extracted ok return TRUE; } /******************************************************************************************** > BOOL CCLexFile::GetStringToken() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Returns: TRUE if all ok; FALSE if not. Purpose: Extracts a string token from the input stream, as defined by the currently installed string delimiters. Errors: String too long. SeeAlso: CCLexFile::InitLexer; CCLexFile; CCLexFile::SetStringDelimiters ********************************************************************************************/ BOOL CCLexFile::GetStringToken() { INT32 i = 0; TokenType = TOKEN_STRING; // Extract the string. // The first time through the loop causes the 'open string' character character to be // discarded. do { GetCh(); TokenBuf[i++] = Ch; if (!IgnoreStringEscapeCodes) { // We are NOT ignoring '\' characters, so have we found one? if (Ch == '\\') { // Backslash character - ignore it and insert the next character in its place. GetCh(); if(Ch == 'r') { TokenBuf[i-1] = '\r'; Ch = 32; } else { TokenBuf[i-1] = Ch; // Set Ch to 32, in case this is a string delimiter - it's been escaped (by // a backslash) so we don't want it to terminate the loop. // (Space (ASCII 32) is a 'safe' value - 0 is out as it causes GetCh() to // read in the next line. Ch = 32; } } } // If string is too long to fit into our buffer, this is classed as an error ERRORIF(i >= TokenBufSize, _R(IDT_LEX_STRINGTOOLONG), FALSE); } while (!EOFFound && (Ch != StringDelimiters[1])); // Null terminate the token string TokenBuf[i-1] = 0; // Discard the 'close string' character GetCh(); // String extracted ok return TRUE; } /******************************************************************************************** > void CCLexFile::GetLine() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Purpose: Read in the next line from the file - used when extracted tokens with CCLexFile::GetToken(). Handles the current line count, number of chars read count, etc. SeeAlso: CCLexFile::GetCh ********************************************************************************************/ void CCLexFile::GetLine() { // End of file? if (eof()) { EOFFound = TRUE; return; } if(SeekingRequired) { // It would be much better to do it via variables rather than doing a tellin() //LastLinePos += CharsRead; //tellIn(); //FilePos StartLastLinePos = LastLinePos; /* static FilePos LastLinePosTmp = 0; static BOOL LastLinePosBool = FALSE; if(LastLinePosTmp == 0) { LastLinePosTmp = LastLinePos + Ofs - 1 + 2; LastLinePosBool = FALSE; } else { LastLinePosTmp += Ofs + 1 + 2; if(LastLinePosBool == FALSE) { LastLinePosTmp -= 2; LastLinePosBool = TRUE; } } LastLinePos = LastLinePosTmp;*/ //LastLinePos += Ofs + 1; // Store position of start of line LexerInitialised = FALSE; LastLinePos = tellIn(); LexerInitialised = TRUE; } else { LastLinePos = 0; } // Get a new line from the file. read( LineBuf ); Line++; Ofs = 0; } /******************************************************************************************** > void CCLexFile::GetCh() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Purpose: Gets the next character from the input stream, reading in a new line if necessary. SeeAlso: CCLexFile::GetLine ********************************************************************************************/ void CCLexFile::GetCh() { // Get a character from the stream. // If end of file, there is no effect if (EOFFound) return; // If at the end of a line, get a new line first if ((Ch == 0) && (Ofs != 0)) GetLine(); // Test again as GetLine() might encounter the end of the file... // NB the above comment inserted for the hard of thinking (e.g. Justin and Simon) if (EOFFound) { Ch = 0; return; } Ch = Buf[Ofs++]; } /******************************************************************************************** > BOOL CCLexFile::IsDelim() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Returns: TRUE if the current character is a delimiter; FALSE if not. Purpose: Test the current character (as read in by CCLexFile::GetCh) to see if it is a delimiter. SeeAlso: CCLexFile::SetDelimiters ********************************************************************************************/ BOOL CCLexFile::IsDelim() { if (DelimiterChars == NULL) return FALSE; return( strchr( DelimiterChars, Ch ) != NULL); } /******************************************************************************************** > BOOL CCLexFile::IsWhitespace() Author: Tim_Browse (Xara Group Ltd) Created: 05/04/94 Returns: TRUE if the current character is white-space; FALSE if not. Purpose: Test the current character (as read in by CCLexFile::GetCh) to see if it is a white-space character. SeeAlso: CCLexFile::SetWhitespace ********************************************************************************************/ BOOL CCLexFile::IsWhitespace() { // 0-terminators are not whitespace if (Ch == 0) return FALSE; return( strchr( WhitespaceChars, Ch ) != NULL ); } /******************************************************************************************** > BOOL CCLexFile::IsWhitespace(TCHAR cToTest) Author: Graham_Walmsley (Xara Group Ltd) Created: 16/5/97 Inputs: cToTest Character to test Returns: TRUE if the character is white-space; FALSE if not. Purpose: Tests the character passed to see if it is a white-space character. SeeAlso: CCLexFile::GetWhitespace() ********************************************************************************************/ BOOL CCLexFile::IsWhitespace( char cToTest ) { // 0-terminators are not whitespace if (cToTest == 0) return FALSE; return( strchr( WhitespaceChars, cToTest ) != NULL ); } /******************************************************************************************** > BOOL CCLexFile::PutString(StringBase& str, UINT32 length=0, TCHAR* Sep=" ") Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: str = string to write length = num chars in str to write (0 means write to termination char) Sep = chars to use as a separator between this string and the next. Outputs: - Returns: TRUE = successful, FALSE = error Purpose: Outputs the string to the file enclosed in the string delimiting chars. (see CCLexFile::SetStringDelimiters for more details) Writes out 'length' chars of str, then finishes off by writing 'Sep' out as a bunch of Sep characters. Errors: - SeeAlso: - ********************************************************************************************/ BOOL CCLexFile::PutString( const StringBase &str, UINT32 length, char* pszSep ) { write( StringDelimiters[0] ); write( str, length ); write( StringDelimiters[1] ); if( strlen( pszSep ) > 0 ) write( pszSep, (UINT32)strlen( pszSep ) ); return (good()); } /******************************************************************************************** > BOOL CCLexFile::PutToken(StringBase& str, UINT32 length=0, TCHAR* Sep=" ") Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: str = string to write length = num chars in str to write (0 means write to termination char) Sep = chars to use as a separator between this string and the next. Outputs: - Returns: TRUE = successful, FALSE = error Purpose: Outputs the string to the file. Writes out 'length' chars of str, then finishes off by writing 'Sep' out as a bunch of Sep characters. Errors: - SeeAlso: - ********************************************************************************************/ BOOL CCLexFile::PutToken( const StringBase &str, UINT32 length, char *pszSep ) { write( str, length ); if( strlen( pszSep ) > 0 ) write( pszSep, (UINT32)strlen( pszSep ) ); return( good() ); } /******************************************************************************************** > BOOL CCLexFile::PutToken(const TCHAR* buf, TCHAR* Sep=" ") Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: buf = buffer of chars to write Sep = chars to use as a separator between this string and the next. Outputs: - Returns: TRUE = successful, FALSE = error Purpose: Outputs the string to the file. Writes out 'length' chars of str, then finishes off by writing 'Sep' out as a bunch of Sep characters. Errors: - SeeAlso: - ********************************************************************************************/ BOOL CCLexFile::PutToken( const TCHAR *buf, char *Sep ) { #if 0 != wxUSE_UNICODE size_t cch = camWcstombs( NULL, (const TCHAR *)buf, 0 ) + 1; PSTR psz = PSTR( alloca( cch ) ); camWcstombs( psz, (const TCHAR *)buf, cch ); write( psz, cch ); #else UINT32 length = camStrlen( buf ); write( buf, length ); #endif if( strlen( Sep ) > 0 ) write( Sep, (UINT32)strlen( Sep ) ); return (good()); } /******************************************************************************************** > BOOL CCLexFile::PutToken(INT32 n, TCHAR* Sep=" ") Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: n = a number to write Sep = chars to use as a separator between this string and the next. Outputs: - Returns: TRUE = successful, FALSE = error Purpose: Outputs the number to the file. Writes out 'n', then finishes off by writing 'Sep' out as a bunch of Sep characters. Errors: - SeeAlso: - ********************************************************************************************/ BOOL CCLexFile::PutToken( INT32 n, char *Sep ) { char buf[256]; _snprintf( buf, 256, "%d", n ); UINT32 length = strlen( buf ); write( buf, length ); if( strlen( Sep ) > 0 ) write( Sep, (UINT32)strlen(Sep) ); return( good() ); } /******************************************************************************************** > BOOL CCLexFile::PutNewLine() Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: - Outputs: - Returns: TRUE = successful, FALSE = error Purpose: Outputs a new line, followed by a number of spaces. The number of spaces output can be changed using IncIndent() and DecIndent(); InitLexer resets the number of indent spaces to 0. Errors: - SeeAlso: - ********************************************************************************************/ BOOL CCLexFile::PutNewLine() { write("\n"); for (INT32 n=0; n < IndentSpaces;n++) write(" "); return (good()); } /******************************************************************************************** > void CCLexFile::IncIndent() Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: - Outputs: - Returns: Increases IndentSpaces by IndentDelta. Purpose: Increases the number of spaces written by PutNewLine() at the start of the next line. It is increased by IndentDelta, which can be altered using SetIndentDelta() Errors: - SeeAlso: - ********************************************************************************************/ void CCLexFile::IncIndent() { IndentSpaces += IndentDelta; } /******************************************************************************************** > void CCLexFile::DecIndent() Author: Mark_Neves (Xara Group Ltd) Created: 6/4/94 Inputs: - Outputs: - Returns: Decreases IndentSpaces by IndentDelta. Purpose: Decreases the number of spaces written by PutNewLine() at the start of the next line. It is decreased by IndentDelta, which can be altered using SetIndentDelta() Errors: - SeeAlso: - ********************************************************************************************/ void CCLexFile::DecIndent() { IndentSpaces -= IndentDelta; if (IndentSpaces < 0) IndentSpaces = 0; } ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// //// //// CCStreamFile //// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// /******************************************************************************************** > CCStreamFile::CCStreamFile(iostream* pStream, UINT32 bufferSize = CCFILE_DEFAULTSIZE, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Inputs: pstream - the iostream to use for inout and output bufferSize - Size of the fixed size buffer (default = 1024) - if size > 0 then create a buffer of the specified size - if size = 0 then create a file without a buffer ReportErrors flag ThrowException flag Purpose: Default constructor. SeeAlso: iostream::setbuf ********************************************************************************************/ CCStreamFile::CCStreamFile(iostream* pStream, UINT32 bufferSize, BOOL ErrorReporting, BOOL ExceptionThrowing) : CCLexFile(ErrorReporting, ExceptionThrowing), buffer(0), StreamFileInitialised(FALSE), IOFile(pStream), GZFile(NULL), GZStream(NULL), ModeOfFile(0) { // Nothing to do if there's no stream (and note that StreamFileInitialised // remains FALSE if no iostream is passed). // TRACEUSER( "JustinF", _T("In CCStreamFile::CCStreamFile\n")); if (IOFile == NULL) { TRACE( _T("Null iostream* passed to CCStreamFile::CCStreamFile - is that OK?\n") ); return; } // Possibly allocate a buffer. /* if (bufferSize > 0) { // Deallocate any existing buffer. if (!IOFile->rdbuf()->setbuf(0, 0)) { TRACEUSER( "JustinF", _T("\t- Can't deallocate iostream buffer\n")); String_256 ErrorMsg(_R(IDE_BUFFER_ERROR)); GotError(_R(IDE_BUFFER_ERROR), ErrorMsg); // handle the error return; } // Assign four extra bytes to workaround an MFC bug. buffer = new char[bufferSize +4]; if (!buffer) { GotError(_R(IDE_NOMORE_MEMORY)); return; } // Set the stream's buffer. if (!IOFile->rdbuf()->setbuf(buffer, bufferSize)) { TRACEUSER( "JustinF", _T("\t- Can't allocate iostream buffer of %u bytes\n"), (UINT32) bufferSize + 4); String_256 ErrorMsg(_R(IDE_BUFFER_ERROR)); GotError(_R(IDE_BUFFER_ERROR), ErrorMsg); // handle the error return; } } */ // Everything is hunky-dory ... StreamFileInitialised = TRUE; } /******************************************************************************************** > CCStreamFile::~CCStreamFile() Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Purpose: Default destructor. Closes file if it is still open. Deallocates buffer. ********************************************************************************************/ CCStreamFile::~CCStreamFile() { // If the compression flag is on then close down the compression system // TRACEUSER( "JustinF", _T("In CCStreamFile::~CCStreamFile\n")); if (CompressData) StopCompression(); // These are the special classes we might use to compress the file. // If present then delete them. if (GZStream) { delete GZStream; GZStream = NULL; } if (GZFile) { delete GZFile; GZFile = NULL; } // Finally, deallocate the stream object. Derived classes should make sure they have set // the IOFile pointer to null if they pass CCStreamFile an iostream that wasn't allocated // on the heap. if (IOFile != NULL) { delete IOFile; IOFile = NULL; } // Finally, deallocate the buffer, as the iostream doesn't. /* delete[] buffer; buffer = 0; */ } /******************************************************************************************** > BOOL CCStreamFile::IsInited() Author: Neville_Humphrys (Xara Group Ltd) Created: 1/9/94 Inputs: None Returns: TRUE if the contructor went without errors or FALSE otherwise. Purpose: Allows errors to be returned from the constructor. SeeAlso: CCStreamFile ********************************************************************************************/ BOOL CCStreamFile::IsInited() { return StreamFileInitialised; } /******************************************************************************************** > virtual iostream* CCStreamFile::SetStream(iostream* pStream) Author: Justin_Flude (Xara Group Ltd) Created: 16/8/96 Inputs: pStream - the new iostream to attach this CCStreamFile to Returns: Pointer to the previous iostream. You should deallocate this sometime if you don't use it again in a different way. Purpose: Changes the iostream that this CCStreamFile uses for I/O. Don't call this unless you know what you're doing - it probably won't work with derived classes, such as CCDiskFile. ********************************************************************************************/ iostream* CCStreamFile::SetStream(iostream* pStream) { iostream* pio = IOFile; IOFile = pStream; return pio; } /******************************************************************************************** > virtual BOOL CCStreamFile::isOpen() const Author: Justin_Flude (Xara Group Ltd) Created: 16/8/96 Returns: TRUE if this CCFile is open. CCStreamFiles are *always* open, provided they were constructed successfully. Purpose: Gives the status of this CCStreamFile. ********************************************************************************************/ BOOL CCStreamFile::isOpen() const { // Stream files are always open, and cannot be closed. return StreamFileInitialised && IOFile != NULL; } /******************************************************************************************** > virtual void CCStreamFile::close() Author: Justin_Flude (Xara Group Ltd) Created: 16/8/96 Purpose: Closes a CCStreamFile. This is a no-op as CCStreamFiles are always open. ********************************************************************************************/ void CCStreamFile::close() { TRACEUSER( "JustinF", _T("CCStreamFile::close called - I wonder why?\n") ); } /******************************************************************************************** > CCFile& CCStreamFile::read(void* buf, UINT32 length) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Inputs: buf - buffer to place the bytes in. length - the number of bytes to read. Outputs: buf - the data read from the file. Returns: Reference to the CCFile object. Purpose: Read a number of bytes from the file. Errors: This function calls the error handling function (which could throw an Exception if the ThrowExceptions flag is set) if the fail flag of the file is set after the read. ********************************************************************************************/ CCFile &CCStreamFile::read( void *buf, UINT32 length ) { /* #ifdef _DEBUG if (length > 1) { TRACEUSER( "JustinF", _T("In CCStreamFile::read(void* 0x%p, %u)\n"), (LPVOID) buf, (UINT32) length); } #endif */ if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error) INT32 RetValue = GZFile->gzread( GZStream, (char *)buf, length ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("Read error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_READ_ERROR)); } if (RetValue == 0) { // found end of file so make sure we return an EOF as the data TCHAR* b = (TCHAR*) buf; *b = EOF; IOFile->clear(ios::eofbit); } if (IOFile->fail()) { TRACEUSER( "JustinF", _T("Read fail error\n") ); GotError(_R(IDE_FILE_READ_ERROR)); } } else { ERROR3("CCStreamFile::read bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } } else { if (IOFile->read((char*) buf, length).fail()) GotError(_R(IDE_FILE_READ_ERROR)); } // Update the CharsRead param CharsRead += length; // and return return *this; } /******************************************************************************************** > CCFile& CCStreamFile::read(StringBase* buf) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Inputs: buf - the String object to place the characters in. Outputs: buf - the characters read from the file. Returns: Reference to the CCFile object. Purpose: Read in a string from the file. The read operation stops at the first newline, or when the string is full. The newline is removed from the input stream. ********************************************************************************************/ CCFile& CCStreamFile::read(StringBase* buf) { // Read characters in until we have MaxLength() of them, or we hit a new line // TRACEUSER( "JustinF", _T("In CCStreamFile::read(String* 0x%p)\n"), (LPVOID) buf); INT32 Max = buf->MaxLength(); INT32 Off = 0; TCHAR* Text = (TCHAR*) (*buf); char Ch; // chars to look for const TCHAR CR = TEXT('\n'); const TCHAR LF = TEXT('\r'); // We have to do this sneeky test for end of file because the iostream classes // are a load of old bollox! if (CompressData) { // First check if our zipping classes are present, if not then fail if (GZStream ==NULL && GZFile == NULL) { ERROR3("CCStreamFile::read string bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error INT32 RetValue = GZFile->gzpeek( GZStream, &Ch ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("Peek error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_READ_ERROR)); } if (RetValue == 0) { // found end of file so make sure we return an EOF as the data Ch = CHAR_EOF; } if (IOFile->fail()) { TRACEUSER( "JustinF", _T("Peek char fail error\n") ); GotError(_R(IDE_FILE_READ_ERROR)); } } else { Ch = IOFile->peek(); } // check if found the EOF if (Ch == CHAR_EOF) { // Mark the EOF has having been reached. IOFile->clear(ios::eofbit); // Its the end of the file all right Text[0] = TEXT('\0'); return *this; } // Get the first char read(&Ch, 1); // loop around until we get to the end of the line or the end of the file if (CompressData) { // Must leave 1 character space in the buffer if we reach the maximum buffer size // so that we can fit the terminating zero in below. while ((Max>1) && (Ch!=CR) && (Ch!=LF) && (Ch!=CHAR_EOF)) { // store the char we read Text[Off++] = Ch; // read another one and decrement the counter read(&Ch, 1); // Keep track of how much we have read Max--; } if (GZStream ==NULL && GZFile == NULL) { ERROR3("CCStreamFile::read string bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error INT32 RetValue = GZFile->gzpeek( GZStream, &Ch ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("Peek error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_READ_ERROR)); } if (RetValue == 0) { // found end of file so make sure we return an EOF as the data Ch = CHAR_EOF; } if (IOFile->fail()) { TRACEUSER( "JustinF", _T("Peek char fail error\n") ); GotError(_R(IDE_FILE_READ_ERROR)); } if ((Ch==LF) || (Ch==CR)) { // eat the other part of the CR LF combo read(&Ch, 1); } // See if we have reached the end of the file if (Ch==CHAR_EOF) { // Mark the End Of File IOFile->clear(ios::eofbit); } } else { // Must leave 1 character space in the buffer if we reach the maximum buffer size // so that we can fit the terminating zero in below. while ((Max>1) && (Ch!=CR) && (Ch!=LF) && (IOFile->peek() != EOF)) { // store the char we read Text[Off++] = Ch; // read another one and decrement the counter read(&Ch, 1); // Keep track of how much we have read Max--; } // if we ended at the end of a line, see if the next char is also part of a new line Ch = IOFile->peek(); if ((Ch==LF) || (Ch==CR)) { // eat the other part of the CR LF combo read(&Ch, 1); } // See if we have reached the end of the file if (Ch==CHAR_EOF) { // Mark the End Of File IOFile->clear(ios::eofbit); } } // Terminate the string Text[Off++] = 0; // return return *this; } /******************************************************************************************** > CCFile& CCStreamFile::read(TCHAR& buf) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Inputs: Pointer to the TCHAR buffer. Outputs: buf - the character read from the file. Returns: Reference to the CCFile object. Purpose: Read a character from the file. ********************************************************************************************/ CCFile &CCStreamFile::read( char &buf ) { // TRACEUSER( "JustinF", _T("In CCStreamFile::read(TCHAR)\n")); if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error char outbuf; INT32 RetValue = GZFile->gzread( GZStream, &outbuf, 1 ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("Read error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_READ_ERROR)); } if (RetValue == 0) { // found end of file so make sure we return an EOF as the data Ch = CHAR_EOF; } if (IOFile->fail()) { TRACEUSER( "JustinF", _T("Read char fail error\n") ); GotError(_R(IDE_FILE_READ_ERROR)); } buf = outbuf; } else { ERROR3("CCStreamFile::read char bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } } else { if (IOFile->get(buf).fail()) GotError(_R(IDE_FILE_READ_ERROR)); } return *this; } /******************************************************************************************** > CCFile& CCStreamFile::write(const StringBase& buf, UINT32 length = 0) Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Inputs: buf - String buffer. length - number of characters to write. (0 => write all of them up to the string terminator) Returns: Reference to the CCFile object. Purpose: Writes the number of charactors specified by length. SeeAlso: fstream::write() ********************************************************************************************/ CCFile &CCStreamFile::write( const StringBase &buf, UINT32 length ) { // TRACEUSER( "JustinF", _T("In CCStreamFile::write(String* 0x%p, %u)\n"), (LPVOID) &buf, (UINT32) length); ENSURE((INT32) length <= buf.Length(), "CCStreamFile::write(): Not enough characters in string!"); #if 0 != wxUSE_UNICODE size_t cch = camWcstombs( NULL, (const TCHAR *)buf, 0 ) + 1; PSTR psz = PSTR( alloca( cch ) ); camWcstombs( psz, (const TCHAR *)buf, cch ); #else PCSTR psz = PCSTR(buf); #endif if( 0 == length ) length = (UINT32)strlen( psz ); if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error INT32 RetValue = GZFile->gzwrite( GZStream, psz, DWORD(length) ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("Write error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_WRITE_ERROR)); } if ((UINT32) RetValue != length) { TRACEUSER( "JustinF", _T("Wrote wrong length = %d\n"), RetValue ); GotError(_R(IDE_FILE_WRITE_ERROR)); } if (IOFile->bad()) { TRACEUSER( "JustinF", _T("Write bad error\n") ); GotError(_R(IDE_FILE_WRITE_ERROR)); } } else { ERROR3("CCStreamFile::write bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } } else { if( IOFile->write( psz, DWORD(length) ).bad() ) GotError( _R(IDE_FILE_WRITE_ERROR) ); } return *this; } /******************************************************************************************** > CCFile& CCStreamFile::write(const void *buf, UINT32 length) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Inputs: buf - pointer to the bytes to write. length - the number of bytes to write. Returns: Reference to the CCFile object. Purpose: Write a number of bytes to the file. ********************************************************************************************/ CCFile& CCStreamFile::write(const void* buf, UINT32 length) { /* #ifdef _DEBUG if (length > 1) { TRACEUSER( "JustinF", _T("In CCStreamFile::write(void* 0x%p, %u)\n"), (LPVOID) buf, (UINT32) length); } #endif */ if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error INT32 RetValue = GZFile->gzwrite( GZStream, PSTR(buf), length ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("Write error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_WRITE_ERROR)); } if ((UINT32) RetValue != length) { TRACEUSER( "JustinF", _T("Wrote wrong length = %d\n") ,RetValue ); GotError(_R(IDE_FILE_WRITE_ERROR)); } if (IOFile->bad()) { TRACEUSER( "JustinF", _T("Write bad error\n") ); GotError(_R(IDE_FILE_WRITE_ERROR)); } } else { ERROR3("CCStreamFile::write bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } } else { if( IOFile->write( PCSTR(buf), length).bad() ) GotError( _R(IDE_FILE_WRITE_ERROR) ); } return *this; } /******************************************************************************************** > CCFile& CCStreamFile::write(TCHAR& buf) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Inputs: buf - the character to write out. Returns: Reference to the CCFile object. Purpose: Writes a character out to the file. ********************************************************************************************/ CCFile &CCStreamFile::write( char &buf ) { // TRACEUSER( "JustinF", _T("In CCStreamFile::write(TCHAR %c)\n"), (TCHAR) buf); if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error INT32 RetValue = GZFile->gzwrite( GZStream, &buf, 1 ); if (RetValue <= 0 || IOFile->bad()) { TRACEUSER( "JustinF", _T("Write char error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_WRITE_ERROR)); } if ((UINT32) RetValue != 1) { TRACEUSER( "JustinF", _T("Wrote wrong length = %d\n"), RetValue ); GotError(_R(IDE_FILE_WRITE_ERROR)); } if (IOFile->bad()) { TRACEUSER( "JustinF", _T("Write char bad error\n") ); GotError(_R(IDE_FILE_WRITE_ERROR)); } } else { ERROR3("CCStreamFile::write char bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } } else { if (IOFile->put(buf).bad()) GotError(_R(IDE_FILE_WRITE_ERROR)); } return *this; } /******************************************************************************************** > CCFile& CCStreamFile::seekIn(FilePos pos) Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Inputs: FilePos - a position in the file Returns: Reference to the CCFile object. Purpose: Sets the input pointer to the file position passed in. SeeAlso: istream::seekg() ********************************************************************************************/ CCFile& CCStreamFile::seekIn(FilePos pos) { if (CompressData) { // This is not implemented in compressed files so error ERROR3("seekIn called in Compressed mode"); GotError(_R(IDE_FILE_READ_ERROR)); return *this; } else { // Stuff to sort a seeking lexer out if (IsLexerInitialised() && SeekingRequired) { Ch = 0; Ofs = 0; LastLinePos = pos; } IOFile->seekg(pos); return *this; } } /******************************************************************************************** > CCFile& CCStreamFile::seekIn(INT32 Offset, ios::seek_dir Dir) Author: Tim_Browse (Xara Group Ltd) Created: 1/9/93 Inputs: Offset - the file offset to seek to. Dir - specifies where in the file the offset is relative to. (can be ios::beg, ios::cur, or ios::end). Returns: Reference to the CCFile object. Purpose: Sets the input pointer to the offset passed in, relative to the specified position in the file. SeeAlso: istream::seekg() ********************************************************************************************/ CCFile& CCStreamFile::seekIn(INT32 Offset, ios::seekdir Dir) { if (CompressData) { // This is not implemented in compressed files so error ERROR3("seekIn (Offset, dir) called in Compressed mode"); GotError(_R(IDE_FILE_READ_ERROR)); } else { IOFile->seekg( Offset, ios_base::seekdir(Dir) ); // Stuff to sort the lexer out if (IsLexerInitialised() && SeekingRequired) { Ch = 0; Ofs = 0; LastLinePos = IOFile->tellg(); } } return *this; } /******************************************************************************************** > FilePos CCStreamFile::tellIn() Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: FilePos - a position in the file Purpose: Gets the input pointer file position. SeeAlso: istream::tellg() ********************************************************************************************/ FilePos CCStreamFile::tellIn() { if (CompressData) { // This is not implemented in compressed files so error //ERROR3("tellIn called in Compressed mode"); //GotError(_R(IDE_FILE_READ_ERROR)); return (FilePos) IOFile->tellg(); } else { if (IsLexerInitialised()) { ERROR3IF(!SeekingRequired, "CCStreamFile::tellIn() will only work properly with seeking enabled"); // -1 for the one character lookahead that's in operation return (FilePos) (Ofs + (INT32) LastLinePos - 1); } return (FilePos) IOFile->tellg(); } } /******************************************************************************************** > CCFile& CCStreamFile::seek(FilePos pos) Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Inputs: FilePos - a position in the file Returns: Reference to the CCFile object. Purpose: Sets the output pointer to the file position passed in. SeeAlso: ostream::seekp() ********************************************************************************************/ CCFile& CCStreamFile::seek(FilePos pos) { if (CompressData) { // This is not implemented in compressed files so error ERROR3("seek called in Compressed mode"); GotError(_R(IDE_FILE_READ_ERROR)); } else IOFile->seekp(pos); return *this; } /******************************************************************************************** > FilePos CCStreamFile::tell() Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: FilePos - a position in the file Purpose: Gets the output pointer file position. SeeAlso: ostream::tellp() ********************************************************************************************/ FilePos CCStreamFile::tell() { if (CompressData) { // This is not implemented in compressed files so error ERROR3("tell called in Compressed mode"); GotError(_R(IDE_FILE_READ_ERROR)); } return (FilePos) IOFile->tellp(); } /******************************************************************************************** > CCFile& CCStreamFile::flush() Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: Reference to the CCFile object. Purpose: Clears the io buffer SeeAlso: iostream::flush ********************************************************************************************/ CCFile& CCStreamFile::flush() { if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error INT32 RetValue = GZFile->gzflush(GZStream, Z_FULL_FLUSH); if (RetValue < 0) { TRACEUSER( "JustinF", _T("flush error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_READ_ERROR)); } if (IOFile->fail()) { TRACEUSER( "JustinF", _T("flush fail error\n") ); GotError(_R(IDE_FILE_READ_ERROR)); } } else { ERROR3("CCStreamFile::flush has bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } // now flush the main IOFIle itself IOFile->flush(); } else IOFile->flush(); return *this; } /******************************************************************************************** > CCFile& CCStreamFile::get(TCHAR& buf) Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Outputs: Single charactor retrieved by get. Returns: Reference to the CCFile object. Purpose: Retrieves a single charactor from the file. If the compression flag is on then it gets the compressed byte from the file and decompresses it. SeeAlso: fstream::operator<<() ********************************************************************************************/ CCFile& CCStreamFile::get( char &buf ) { // TRACEUSER( "JustinF", _T("In CCStreamFile::get(TCHAR)\n")); if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error char outbuf; INT32 RetValue = GZFile->gzread( GZStream, &outbuf, 1 ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("get error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_READ_ERROR)); } if (RetValue == 0) { // end of file reached so return the EOF character buf = CHAR_EOF; } else buf = outbuf; } else { ERROR3("CCStreamFile::get bad GZFile/GZStream"); GotError(_R(IDE_FILE_READ_ERROR)); } } else IOFile->get( buf ); return *this; } /******************************************************************************************** > CCFile& CCStreamFile::put(const TCHAR& buf) Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Inputs: Single charactor to be inserted into file. Returns: Reference to the CCFile object. Purpose: Inserts a single charactor into the file. If the compression flag is on then it sends it out compressed to file. SeeAlso: fstream::operator<<() ********************************************************************************************/ CCFile &CCStreamFile::put( const char &buf ) { // TRACEUSER( "JustinF", _T("In CCStreamFile::put(TCHAR %c)\n"), (TCHAR) buf); if (CompressData) { if (GZStream !=NULL && GZFile != NULL) { // returns the number of uncompressed bytes actually read // (0 for end of file, -1 for error char outbuf = buf; INT32 RetValue = GZFile->gzwrite( GZStream, &outbuf, 1 ); if (RetValue < 0) { TRACEUSER( "JustinF", _T("put error = %d\n"), RetValue ); GZipErrorID = RetValue; GotError(_R(IDE_ZFILE_WRITE_ERROR)); } if ((UINT32) RetValue != 1) { TRACEUSER( "JustinF", _T("put wrong length = %d\n"), RetValue ); GotError(_R(IDE_FILE_WRITE_ERROR)); } } else { ERROR3("CCStreamFile::put bad GZFile/GZStream"); GotError(_R(IDE_FILE_WRITE_ERROR)); } } else IOFile->put(buf); return *this; } /******************************************************************************************** > BOOL CCStreamFile::good() const Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: True if file status is healthy and FALSE otherwize. Purpose: To identify if file is ok SeeAlso: ios::good ********************************************************************************************/ BOOL CCStreamFile::good() const { return IOFile->good(); } /******************************************************************************************** > BOOL CCStreamFile::bad() const Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: True if a serious I/O error occurs and FALSE otherwize. Purpose: To identify an erroneous file status SeeAlso: ios::bad ********************************************************************************************/ BOOL CCStreamFile::bad() const { // If we are about to return True then make sure we call set error // as the caller may not have done this and hence a random error // may be displayed if (IOFile->bad()) Error::SetError( _R(IDE_IO_ERROR) ); return IOFile->bad(); } /******************************************************************************************** > BOOL CCStreamFile::fail() const Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: True if a recoverable fail error occurs and FALSE otherwize. Purpose: To identify recoverable file errors SeeAlso: ios::fail ********************************************************************************************/ BOOL CCStreamFile::fail() const { return IOFile->fail(); } /******************************************************************************************** > BOOL CCStreamFile::eof() const Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Returns: True if end of file and FALSE otherwize. Purpose: To identify end of file SeeAlso: ios::eof ********************************************************************************************/ BOOL CCStreamFile::eof() const { return IOFile->eof(); } /******************************************************************************************** > BOOL CCStreamFile::SetBadState() Author: Neville_Humphrys (Xara Group Ltd) Created: 31/08/94 Returns: None. Purpose: It allows the forceable setting of the test that functions like bad() use so the next check of the current file status to see if we should continue using the file or not will fail. This will be called by the GotError function so that any attempts to read/write after this should fail. SeeAlso: CCFile::GotError ********************************************************************************************/ void CCStreamFile::SetBadState() { // All the status functions should just return the state of eof() // Therefore, just make sure that eof() will fail. IOFile->clear(IOFile->badbit); // remember clear == set badbit } /******************************************************************************************** > BOOL CCStreamFile::SetGoodState() Author: Neville_Humphrys (Xara Group Ltd) Created: 8/12/94 Returns: None. Purpose: It allows the forceable setting of the test that functions like bad() use so the next check of the current file status to see if we should continue using the file or not will pass. It would seem that sometimes the eof() or similar might need forcing by somebody using the class. SeeAlso: CCFile::GotError ********************************************************************************************/ void CCStreamFile::SetGoodState() { // Nuke any existing error states that might exist e.g. a lying eof() bit IOFile->clear(IOFile->goodbit); } /******************************************************************************************** > virtual INT32 CCStreamFile::Size() Author: Justin_Flude (Xara Group Ltd) Created: 13/8/96 Returns: The size of the attached stream, in bytes. ********************************************************************************************/ size_t CCStreamFile::Size() { // We can't really do this for any stream, but we can have a bodgy bash. We'll subtract // the start position from the end position of the file. streampos spOrigin = IOFile->tellg(); size_t sz = IOFile->seekg(0, ios::end).tellg() - IOFile->seekg(0, ios::beg).tellg(); IOFile->seekg(spOrigin); return sz; } /******************************************************************************************** > virtual BOOL CCStreamFile::InitCompression(BOOL Header = FALSE) Author: Neville_Humphrys (Xara Group Ltd) Created: 1/6/95 Purpose: To initialise the compression system ready for use. This is to make sure there is enough memory available for its buffers before writing out any compression tokens into the output file. Usually used for writing only. Reading, there should be no similar requirement. Graeme (15/11/99) - Added the Header parameter to the function to allow compression to use the ZLib header. Previously, the CCFile functions were hardwired to supress this, but Flash export needs it. SeeAlso: StartCompression; StopCompression ********************************************************************************************/ BOOL CCStreamFile::InitCompression(BOOL Header) { // TRACEUSER( "JustinF", _T("CCStreamFile::InitCompression\n")); // We first need to create the classes that we will be using GZFile = new GZipFile; if (GZFile == NULL) { return FALSE; } // Can't seem to get to the read/write (in/out) flag states via IOFile.flags() // so use stored versions String_16 filemode; //return CCStreamFile::isOpen() && cs.is_open(); if (ModeOfFile & ios::out) filemode = _T("w"); else if (ModeOfFile & ios::in) filemode = _T("r"); else ERROR3("filemode incorrect as neither in or out"); // Add in the b if we are in binary mode if (ModeOfFile & ios::binary) filemode += _T("b"); GZStream = GZFile->gz_init( IOFile, (TCHAR*) filemode, Header ); if (GZStream == NULL) { // Remove the class that we allocated delete GZFile; GZFile = NULL; return FALSE; } // Everything went ok return TRUE; } /******************************************************************************************** > virtual BOOL CCStreamFile::StartCompression() Author: Neville_Humphrys (Xara Group Ltd) Created: 25/5/95 Purpose: To start up the compression system. If we are writing then should have called Init before so that we have a chance to fail BEFORE the compression tokens are written If we are reading then no need to do this. SeeAlso: StopCompression ********************************************************************************************/ BOOL CCStreamFile::StartCompression() { // TRACEUSER( "JustinF", _T("CCStreamFile::StartCompression\n")); // We first need to create the classes that we will be using // Only create the GZFile class if not already present as in the writing case // we will have called Init and it will be present if (GZFile == NULL) GZFile = new GZipFile; if (GZFile == NULL) { return FALSE; } // Can't seem to get to the read/write (in/out) flag states via IOFile.flags() // so use stored versions String_16 filemode; if( ModeOfFile & ios::out ) { filemode = _T("w"); } else if( ModeOfFile & ios::in ) { filemode = _T("r"); } else { ERROR3("filemode incorrect as neither in or out"); } // Add in the b if we are in binary mode if( ModeOfFile & ios::binary ) { filemode += _T("b"); } // Pass in the leafname of the file GZipErrorID = Z_OK; // If writing then should have called Init before so that we have a chance to // fail BEFORE the compression tokens are written if (GZStream != NULL) { // In the write case Init has been called so just open the file INT32 RetValue = GZFile->gz_open(GZStream); if (RetValue < 0) { // Only set the error if it is not our special we have found uncompressed // data error if (RetValue == Z_UNCOMPRESSED_ERROR) { // Found uncompressed data so stop compression // Remove the class that we allocated delete GZStream; GZStream = NULL; delete GZFile; GZFile = NULL; CompressData = FALSE; return TRUE; } else { // Some other error has happened so remember this error GZipErrorID = RetValue; } } } else { // In the read case Init will not have been called so we use the full // version of open. GZStream = GZFile->gz_open( IOFile, (TCHAR *)filemode, NULL ); // no paths please! if (GZStream == NULL) { // Remove the class that we allocated delete GZFile; GZFile = NULL; // Return False so that we error return FALSE; } // If it has given our special error then we have found uncompressed // data and should just stop the compression process if (GZStream->z_err == Z_UNCOMPRESSED_ERROR) { delete GZStream; GZStream = NULL; // Remove the class that we allocated delete GZFile; GZFile = NULL; // Make out that compression did start up ok otherwise it will error. // But ensure compression is off CompressData = FALSE; return TRUE; } } if (GZStream->z_err != Z_OK) GZipErrorID = GZStream->z_err; // check if an error was detected in opening if (GZipErrorID != Z_OK) { // Work out if we are reading or writing and use the corresponding // correct error message UINT32 ErrorID = _R(IDE_ZFILE_READ_ERROR); if (ModeOfFile & ios::out) ErrorID = _R(IDE_ZFILE_WRITE_ERROR); else if (ModeOfFile & ios::in) ErrorID = _R(IDE_ZFILE_READ_ERROR); GotError(ErrorID); } return TRUE; } /******************************************************************************************** > virtual BOOL CCStreamFile::StopCompression() Author: Neville_Humphrys (Xara Group Ltd) Created: 25/5/95 Purpose: To stop the compression system. SeeAlso: StartCompression ********************************************************************************************/ BOOL CCStreamFile::StopCompression() { // TRACEUSER( "JustinF", _T("CCStreamFile::StopCompression\n")); BOOL Ok = TRUE; // Try and close down the system if (GZFile && GZStream) { INT32 RetValue = GZFile->gzclose(GZStream); // The close should have removed the GZStream. // Must set our pointer to NULL overwise there will be problems! GZStream = NULL; // TRACEUSER( "JustinF", _T("CCStreamFile::StopCompression gzclose returned %d\n"),RetValue); if (RetValue < 0) { GZipErrorID = RetValue; // Work out if we are reading or writing and use the corresponding // correct error message UINT32 ErrorID = _R(IDE_ZFILE_READ_ERROR); if (ModeOfFile & ios::out) ErrorID = _R(IDE_ZFILE_WRITE_ERROR); else if (ModeOfFile & ios::in) ErrorID = _R(IDE_ZFILE_READ_ERROR); // Set up a friendly form of the error SetZipFileErrorMessage(ErrorID); // return the fact to the caller Ok = FALSE; } // Now try and clean up our special classes for compressing the file. if (GZFile) { delete GZFile; GZFile = NULL; } } return Ok; } /******************************************************************************************** > virtual INT32 CCStreamFile::GetCharsRead() Author: Neville_Humphrys (Xara Group Ltd) Created: 25/5/95 Purpose: To make sure the progress bar does not go over the end SeeAlso: LexFile::GetCharsRead ********************************************************************************************/ INT32 CCStreamFile::GetCharsRead() { // This is then used to update the progress bar on EPS import. // A progress bar is started with the file size. // Hence, if we are compressing/decompressing we must not return the true value // If not compressing then just do what the lexfile does which is return the // number of characters read so far. if (!CompressData) return CharsRead; // Return the current position in the file. This must be the present if (GZFile && GZStream) { // Get the file stream class to tell us where it is currently in the compressed file // Must be the compressed file as the progress bar is started with the actual size of the // file i.e. compressed size. return GZFile->GetCurrentFilePos(GZStream); } else return (INT32) IOFile->tellg(); } /******************************************************************************************** > virtual filedesc CCStreamFile::GetFileHandle() const Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Returns: A "file-handle" for this CCStreamFile. This is faked for plain iostreams. SeeAlso: CCDiskFile::GetFileHandle ********************************************************************************************/ filedesc CCStreamFile::GetFileHandle() const { return (filedesc) fake_filedesc(*IOFile); } PORTNOTE("other","Removed OLE stuff") #ifndef EXCLUDE_FROM_XARALX #ifndef RALPH ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// //// //// CCOleStream //// ///////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////// /******************************************************************************************** > CCOleStream::CCOleStream(IStream* pIStream, UINT32 nBufSize, BOOL fReport, BOOL fThrow) Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Inputs: pIStream - the IStream interface to attach to this CCOleStream. This will be used for all I/O. Purpose: Constructs a CCOleStream attached to the given IStream, or not. ********************************************************************************************/ CCOleStream::CCOleStream(IStream* pIStream, UINT32 cbSize, BOOL fReport, BOOL fThrow) : CCStreamFile(new costream(pIStream), cbSize, fReport, fThrow) { // Work out the access mode, if any. // TRACEUSER( "JustinF", _T("In CCOleStream::CCOleStream\n")); // IOFile = NULL; if (isOpen()) GetCoStream().get_access_mode(&ModeOfFile, 0); } /******************************************************************************************** > costream& CCOleStream::GetCoStream() Author: Chris_Snook (Xara Group Ltd) Created: 9/11/77 Inputs: - Purpose: I don't know why but things seem to be going awire! Basically, camelot has developed a severe BUG; and doing the following: edit-copy, file-exit; causes it to throw a wobobley! The only thing that I managed to find that was responsible for causing this was the inline function CCOleStream::GetCoStream(). The original implementation of this function should be fine (and had been fine for about four years); but (like most things) it seems to have stopped working overnight - in the form of a nasty access violation! Anyway, I've made the function not-inline; and it seems to have solved the bug (and the fellow line on 4021). All I can hazard a guess at is that the compiler was getting things wrong !!!! ********************************************************************************************/ costream& CCOleStream::GetCoStream() const { return ((costream&) *IOFile); } /******************************************************************************************** > CCOleStream::CCOleStream(PathName path, INT32 fileMode, INT32 fileAccess = filebuf::openprot, UINT32 bufferSize = CCFILE_DEFAULTSIZE, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Justin_Flude (Xara Group Ltd) Created: 18/8/96 Inputs: path - the non-structured storage file to open. fileMode - the opening mode, eg. ios::in fileAccess - the sharing mode, eg. costream::sh_none etc Purpose: Opens the given "old" file in conversion mode, using the STGM_CONVERT access mode. See the OLE docs for an explanation of this. SeeAlso: costream::open_file; STGM_CONVERT; StgCreateDocfile ********************************************************************************************/ CCOleStream::CCOleStream(PathName path, INT32 nMode, INT32 nAccess, UINT32 cbSize, BOOL fReport, BOOL fThrow) : CCStreamFile(new costream(path.GetPath(), nMode, nAccess), cbSize, fReport, fThrow) { // TRACEUSER( "JustinF", _T("In CCOleStream::CCOleStream\n")); ModeOfFile = nMode; } /******************************************************************************************** > virtual BOOL CCOleStream::isOpen() const Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Returns: TRUE if this CCOleStream is currently open, ie. attached to an IStream. Purpose: Returns the status of this file object. ********************************************************************************************/ BOOL CCOleStream::isOpen() const { // the inline function GetCoStream seems to have been fouling this up .... // so we are doing this for now .... const costream& cs = (const costream&) *IOFile; return CCStreamFile::isOpen() && cs.is_open(); // instead of this .... //return CCStreamFile::isOpen() && GetCoStream().is_open(); } /******************************************************************************************** > virtual BOOL CCOleStream::open_file(PathName path, INT32 fileMode, INT32 fileAccess = filebuf::openprot) Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Inputs: path - the non-structured storage file to open. fileMode - the opening mode, eg. ios::in fileAccess - the sharing mode, eg. costream::sh_none Returns: TRUE if successful, FALSE if something goes wrong. Purpose: Opens the given "old" file in conversion mode, using the STGM_CONVERT access mode. See the OLE docs for an explanation of this. SeeAlso: costream::open_file; STGM_CONVERT; StgCreateDocfile ********************************************************************************************/ BOOL CCOleStream::open_file(PathName path, INT32 fileMode, INT32 fileAccess) { // Sanity check. // TRACEUSER( "JustinF", _T("In CCOleStream::open_file(%s)\n"), (LPCTSTR) path.GetPath()); ERROR2IF(!path.IsValid(), FALSE, "Invalid PathName in CCOleStream::open_file"); ERROR2IF(!IsInited(), FALSE, "CCOleStream not initiallised in CCOleStream::open_file"); // Nuke any existing open error states that might exist IOFile->clear(IOFile->goodbit); // If we are not opening this file for writing then set the ios::nocreate // flag due to a bug in the iostream classes (but not if the ios::out flag is specified // as well. If this is not set we can not open files on read-only mounts shared by windows 95. if ((fileMode & ios::in) && !(fileMode & ios::out)) fileMode |= ios::nocreate; // Set the sharing mode if the default was passed. if (fileAccess == filebuf::openprot) fileAccess = costream::sh_read | costream::sh_write; // Note the current opening mode. ModeOfFile = fileMode; // Try to open the stream. if (FAILED(GetCoStream().open_file(path.GetPath(), fileMode | ios::binary, fileAccess))) { // TO DO: fix this to be a more appropriate error message. GotError(_R(IDE_OPEN_ERROR)); return FALSE; } // Success. return TRUE; } /******************************************************************************************** > virtual BOOL CCOleStream::attach(IStream* pIStream) Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Inputs: pIStream - the IStream interface to connect to this CCOleStream. This will be used for all subsequent I/O. Returns: TRUE if successful, FALSE if not. Purpose: Attaches this CCOleStream to the IStream. ********************************************************************************************/ BOOL CCOleStream::attach(IStream* pIStream) { // TRACEUSER( "JustinF", _T("In CCOleStream::attach\n")); return SUCCEEDED(GetCoStream().attach(pIStream)); } /******************************************************************************************** > void CCOleStream::close() Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Purpose: Closes this CCOleStream. You must call attach with another IStream before you perform I/O on it again. SeeAlso: CCOleStream::attach ********************************************************************************************/ void CCOleStream::close() { // TRACEUSER( "JustinF", _T("In CCOleStream::close\n")); GetCoStream().close(); } /******************************************************************************************** > virtual INT32 CCOleStream::Size() Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Returns: The size of this IStream, in bytes. ********************************************************************************************/ INT32 CCOleStream::Size() { // Size of what??? if (!isOpen()) { ERROR3("CCOleStream::Size called when stream is not open"); return 0; } // Go direct to the IStream for this. STATSTG statstg; HRESULT hr = ((IStream*) GetCoStream())->Stat(&statstg, STATFLAG_NONAME); if (FAILED(hr)) { ERROR3("CCOleStream::Size failed - why?"); return 0; } // We can only return the lower 31 bits (doh!) return (INT32) statstg.cbSize.LowPart; } /******************************************************************************************** > virtual BOOL CCOleStream::setMode(INT32) Author: Justin_Flude (Xara Group Ltd) Created: 17/8/96 Returns: TRUE Purpose: Set this CCOleStream's mode, either text or binary. Does nothing, as CCOleStreams only support binary mode. ********************************************************************************************/ BOOL CCOleStream::setMode(INT32) { TRACEUSER( "JustinF", _T("CCOleStream::setMode called - is this OK?\n") ); return TRUE; } // WEBSTER-Martin-29/12/96 // no accusoft stuff #ifndef WEBSTER /******************************************************************************************** > CCOleAccusoftStream::CCOleAccusoftStream(IStream* pIStream = 0, UINT32 bufferSize = CCFILE_DEFAULTSIZE, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Justin_Flude (Xara Group Ltd) Created: 3/10/96 Inputs: See CCOleStream::CCOleStream. Purpose: Like its base class, CCOleStream, but redirects the Accusoft libraries to use a different stream as well. SeeAlso: CCOleAccusoftStream::~CCOleAccusoftStream ********************************************************************************************/ CCOleAccusoftStream::CCOleAccusoftStream(IStream* pIStream, UINT32 bufferSize, BOOL ErrorReporting, BOOL ExceptionThrowing) : CCOleStream(pIStream, bufferSize, ErrorReporting, ExceptionThrowing) { // TRACEUSER( "JustinF", _T("CCOleAccusoftStream redirecting Accusoft ...\n")); AccusoftFilters::RedirectStream(); } /******************************************************************************************** > CCOleAccusoftStream::CCOleAccusoftStream(PathName path, INT32 fileMode, INT32 fileAccess = filebuf::openprot, UINT32 bufferSize = CCFILE_DEFAULTSIZE, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Justin_Flude (Xara Group Ltd) Created: 3/10/96 Inputs: See CCOleStream::CCOleStream. Purpose: Like its base class, CCOleStream, but redirects the Accusoft libraries to use a different stream as well. SeeAlso: CCOleAccusoftStream::~CCOleAccusoftStream ********************************************************************************************/ CCOleAccusoftStream::CCOleAccusoftStream(PathName path, INT32 nMode, INT32 nAccess, UINT32 cbSize, BOOL fReport, BOOL fThrow) : CCOleStream(path, nMode, nAccess, cbSize, fReport, fThrow) { // TRACEUSER( "JustinF", _T("CCOleAccusoftStream redirecting Accusoft ...\n")); AccusoftFilters::RedirectStream(); } /******************************************************************************************** > virtual CCOleAccusoftStream::~CCOleAccusoftStream() Author: Justin_Flude (Xara Group Ltd) Created: 3/10/96 Purpose: SeeAlso: CCOleAccusoftStream::CCOleAccusoftStream ********************************************************************************************/ CCOleAccusoftStream::~CCOleAccusoftStream() { AccusoftFilters::UnredirectStream(); // TRACEUSER( "JustinF", _T("CCOleAccusoftStream un-redirecting Accusoft ...\n")); } #endif // WEBSTER #endif // RALPH #endif // !wx PORT //----------------------- /******************************************************************************************** CCDiskFile ********************************************************************************************/ //----------------------- /******************************************************************************************** > CCDiskFile::CCDiskFile(UINT32 bufferSize, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Mario_Shamtani (Xara Group Ltd) (Altered by Neville 01/09/94) Created: 1/9/93 Inputs: bufferSize - Size of the fixed size buffer (default = 1024) - if size > 0 then create a buffer of the specified size - if size = 0 then create a file without a buffer ReportErrors flag ThrowException flag Purpose: Default constructor. SeeAlso: fstream::setbuf() ********************************************************************************************/ CCDiskFile::CCDiskFile(UINT32 bufferSize, BOOL ErrorReporting, BOOL ExceptionThrowing) : CCStreamFile(new fstream, bufferSize, ErrorReporting, ExceptionThrowing) { // TRACEUSER( "JustinF", _T("In CCDiskFile::CCDiskFile\n")); } /******************************************************************************************** > CCDiskFile::CCDiskFile(UINT32 bufferSize, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Mario_Shamtani (Xara Group Ltd) (Altered by Neville 01/09/94) Created: 1/9/93 Inputs: bufferSize - Size of the fixed size buffer (default = 1024) - if size > 0 then create a buffer of the specified size - if size = 0 then create a file without a buffer ReportErrors flag ThrowException flag Purpose: Default constructor. SeeAlso: fstream::setbuf() ********************************************************************************************/ CCDiskFile::CCDiskFile(fstream *pfstream, UINT32 bufferSize, BOOL ErrorReporting, BOOL ExceptionThrowing) : CCStreamFile(pfstream, bufferSize, ErrorReporting, ExceptionThrowing) { // Empty. } /******************************************************************************************** > CCDiskFile(PathName fPath, INT32 fileMode, INT32 fileAccess = filebuf::openprot, UINT32 bufferSize = CCFILE_DEFAULTSIZE BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE); Author: Mario_Shamtani (Xara Group Ltd) (Altered by Neville 01/09/94) Created: 1/9/93 Inputs: fPath - PathName for file to be opened fileMode - Mode in which file is to be opened - use ios flags fileAccess - file access flag(s) as specified by the filebuf flags bufferSize - Size of the fixed size buffer (default = 1024) - if size > 0 then create a buffer of the specified size - if size = 0 then create a file without a buffer ReportErrors flag ThrowExceptions flag Purpose: Constructs a CCDiskFile object and opens the file specified by the Path over it. SeeAlso: fstream::setbuf() SeeAlso: fstream::open() ********************************************************************************************/ CCDiskFile::CCDiskFile(fstream *pfstream, PathName fPath, INT32 fileMode, INT32, UINT32 bufferSize, BOOL ErrorReporting, BOOL ExceptionThrowing) : CCStreamFile(pfstream, bufferSize, ErrorReporting, ExceptionThrowing) { // Set up Path name filePath = fPath; ModeOfFile = fileMode; // note current state // Check if the base class setup OK. if (!IsInited()) return; // Open the file #if 0 != wxUSE_UNICODE { size_t cch = camWcstombs( NULL, (const TCHAR *)filePath.GetPath(), 0 ) + 1; PSTR pszFileName = PSTR( alloca( cch ) ); camWcstombs( pszFileName, (const TCHAR *)filePath.GetPath(), cch ); GetFileStream().open( pszFileName, ios_base::openmode(fileMode) ); } #else GetFileStream().open( filePath.GetPath(), ios_base::openmode(fileMode) ); #endif // If file not opened properly report error if (IOFile->fail() || !GetFileStream().is_open()) { String_256 ErrorMsg(_R(IDE_OPEN_ERROR)); ErrorMsg += filePath.GetFileName(); GotError(_R(IDE_OPEN_ERROR), ErrorMsg); StreamFileInitialised = FALSE; } } /******************************************************************************************** > CCDiskFile(PathName fPath, INT32 fileMode, INT32 fileAccess = filebuf::openprot, UINT32 bufferSize = CCFILE_DEFAULTSIZE BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE); Author: Mario_Shamtani (Xara Group Ltd) (Altered by Neville 01/09/94) Created: 1/9/93 Inputs: fPath - PathName for file to be opened fileMode - Mode in which file is to be opened - use ios flags fileAccess - file access flag(s) as specified by the filebuf flags bufferSize - Size of the fixed size buffer (default = 1024) - if size > 0 then create a buffer of the specified size - if size = 0 then create a file without a buffer ReportErrors flag ThrowExceptions flag Purpose: Constructs a CCDiskFile object and opens the file specified by the Path over it. SeeAlso: fstream::setbuf() SeeAlso: fstream::open() ********************************************************************************************/ CCDiskFile::CCDiskFile(PathName fPath, INT32 fileMode, INT32, UINT32 bufferSize, BOOL ErrorReporting, BOOL ExceptionThrowing) : CCStreamFile(new fstream, bufferSize, ErrorReporting, ExceptionThrowing) { // Set up Path name // TRACEUSER( "JustinF", _T("In CCDiskFile::CCDiskFile\n")); filePath = fPath; ModeOfFile = fileMode; // note current state // Check if the base class setup OK. if (!IsInited()) return; // Open the file #if 0 != wxUSE_UNICODE { size_t cch = camWcstombs( NULL, (const TCHAR *)filePath.GetPath(), 0 ) + 1; PSTR pszFileName = PSTR( alloca( cch ) ); camWcstombs( pszFileName, (const TCHAR *)filePath.GetPath(), cch ); GetFileStream().open( pszFileName, ios_base::openmode(fileMode) ); } #else GetFileStream().open( filePath.GetPath(), ios_base::openmode(fileMode) ); #endif // If file not opened properly report error if (IOFile->fail() || !GetFileStream().is_open()) { GotError(_R(IDE_OPEN_ERROR)); StreamFileInitialised = FALSE; } } /******************************************************************************************** > BOOL CCDiskFile::open(PathName fPath, INT32 fileMode, INT32 fileAccess = filebuf::openprot) Author: Mario_Shamtani (Xara Group Ltd) Created: 1/9/93 Inputs: fPath - PathName for file to be opened fileMode - Mode in which file is to be opened - use ios flags fileAccess - file access flag(s) as specified by the filebuf flags Returns: TRUE if file is opened ok or FALSE otherwize Purpose: opens file specified by the path. SeeAlso: fstream::open() Note: It would appear that calling this with ios::in | ios::out | ios::binary on NT on an existing file truncates the file, whereas on Windows 95 it does not truncate the file. Exporting bitmap and eps files was failing as the data was appended to the end of the file on Windows 95. OpMenuExport::DoWithParam fixed by adding a ios::trunc to the open call. ********************************************************************************************/ BOOL CCDiskFile::open( PathName fPath, INT32 fileMode, INT32 ) { // First check that the constructor went ok if (!StreamFileInitialised) { // Did not construct ok, error should have been reported, so just fail return FALSE; } // Nuke any existing open error states that might exist IOFile->clear(IOFile->goodbit); // If we are not opening this file for writing then set the ios::nocreate // flag due to a bug in the iostream classes (but not if the ios::out flag is specified // as well. If this is not set we can not open files on read-only mounts shared by windows 95. // if ((fileMode & ios::in) && !(fileMode & ios::out)) fileMode |= ios::nocreate; // Set up file pathname filePath = fPath; ModeOfFile = fileMode; // note current state // Open file #if 0 != wxUSE_UNICODE { size_t cch = camWcstombs( NULL, (const TCHAR *)filePath.GetPath(), 0 ) + 1; PSTR pszFileName = PSTR( alloca( cch ) ); camWcstombs( pszFileName, (const TCHAR *)filePath.GetPath(), cch ); GetFileStream().open( pszFileName, ios_base::openmode(fileMode) ); } #else GetFileStream().open( filePath.GetPath(), ios_base::openmode(fileMode) ); #endif // If error on opening file report it! if (IOFile->fail() || !GetFileStream().is_open()) { GotError(_R(IDE_OPEN_ERROR)); return FALSE; } return TRUE; } /******************************************************************************************** > void CCDiskFile::close() Author: Justin_Flude (Xara Group Ltd) Created: 1/9/93 Purpose: To close the file SeeAlso: fstream::close() ********************************************************************************************/ void CCDiskFile::close() { GetFileStream().close(); } /******************************************************************************************** > BOOL CCDiskFile::setMode(INT32 fileMode) Author: Mario_Shamtani (Xara Group Ltd) Created: 1/9/93 Inputs: fileMode - Text or Binary (default is text) Returns: TRUE if the mode has changed and FALSE otherwize. Purpose: Changes the file's mode from text\binary. SeeAlso: fstream::setmode() ********************************************************************************************/ BOOL CCDiskFile::setMode(INT32 fileMode) { // This might cause problems in compressed mode so error if called in this mode ERROR3IF(CompressData, "DiskFile set mode called when compressed"); PORTNOTE("other","ios::setmode not suppport anymore") #ifndef EXCLUDE_FROM_XARALX return GetFileStream().setmode(fileMode) >= 0; #else return true; #endif } /******************************************************************************************** > BOOL CCDiskFile::isOpen() const Author: Mario_Shamtani (Xara Group Ltd) Created: 2/9/93 Returns: TRUE if file is open and FALSE otherwize. Purpose: Determines whether file is open SeeAlso: fstream::is_open() ********************************************************************************************/ BOOL CCDiskFile::isOpen() const { return CCStreamFile::isOpen() && const_cast(GetFileStream()).is_open(); } /******************************************************************************************** > BOOL CCDiskFile::GetName( StringBase* name) const Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: Pointer to a CCFile name Outputs: None Returns: True if a name has been set otherwise False. At present always returns False. Purpose: Given a CCDiskFile*, you can ask for some sort of name which is associated with that file. For filenames it might be a filename, or a pathname, for resource files it might be "Default Bitmap" etc. These names could then be used for making error messages have some extra useful information in. Errors: None ********************************************************************************************/ BOOL CCDiskFile::GetName( StringBase* name) const { // Work out how much space we have INT32 MaxLen = name->MaxLength(); filePath.GetPath(); // Now fit our name into this space String_256 Pathname = filePath.GetPath(); if (MaxLen < Pathname.Length()) { // Use just the filename Pathname = filePath.GetFileName(); // If it is still too long, turn it into the form "...ffff.ext", i.e. have an // ellipsis followed by as much of the filename as we can fit into the string. // (We use the last segment of the filename, i.e. we throw away characters from // the beginning). INT32 FilenameLen = Pathname.Length(); if (MaxLen < FilenameLen) { // Shuffle pathname down to fit into buffer Pathname.Remove(0, FilenameLen - MaxLen); // Put the ellipsis at the front TCHAR *Buf = (TCHAR *) Pathname; Buf[0] = '.'; Buf[1] = '.'; Buf[2] = '.'; } } // Copy into output parameter *name = Pathname; // Successful return TRUE; } /******************************************************************************************** > virtual PathName CCDiskFile::GetPathName() const Author: Rik_Heywood (Xara Group Ltd) Created: 1/2/95 Returns: The pathname we have associated with the CCDiskFile Purpose: To find out the name of the file ********************************************************************************************/ PathName CCDiskFile::GetPathName() const { return filePath; } /******************************************************************************************** > filedesc CCDiskFile::GetFileHandle( ) Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: None Outputs: None Returns: The file handle (descriptor) for this file (really an INT32). Purpose: Given an instance of a CCDiskFile, you can ask for the actual file handle that describes the associated file. Required for the external filters. Errors: None ********************************************************************************************/ // defined in winoil\filehndl.cpp //filedesc CCDiskFile::GetFileHandle() const //{ // // Need to convert this into a real file handle rather than the descriptor. // // At present there seems to be no legal way of doing this. // return _get_osfhandle(IOFile.fd()); //} //----------------------- /******************************************************************************************** CCMemFile ********************************************************************************************/ //----------------------- /******************************************************************************************** > CCMemFile::CCMemFile(BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Neville_Humphrys (Xara Group Ltd) Inputs: ReportErrors flag ThrowExceptions flag Created: 1/9/94 Purpose: Constructs an instance of CCMemFile. ********************************************************************************************/ CCMemFile::CCMemFile(BOOL ErrorReporting, BOOL ExceptionThrowing) { // Set our class variables from the passed in values ReportErrors = ErrorReporting; ThrowExceptions = ExceptionThrowing; WasError = FALSE; MemFileInitialised = TRUE; // Better set these up too or an unused object crashes on destuction MemHandle = BAD_MHANDLE; MemFile = NULL; FileSize = 0; CurrentPos = 0; IsOpen = FALSE; FileProt = CCMemRead; } /******************************************************************************************** > CCMemFile::CCMemFile(void *pFile, UINT32 size, FileAccess fProt, BOOL ErrorReporting = TRUE, BOOL ExceptionThrowing = FALSE) Author: Mario_Shamtani (Xara Group Ltd) Inputs: pFile - a pointer to the file UINT32 - the size of the file FileAccess - read or write access ReportErrors flag ThrowExceptions flag Created: 6/9/93 Purpose: Constructs an instance of CCMemFile and Opens it ********************************************************************************************/ CCMemFile::CCMemFile(void *pFile, UINT32 size, FileAccess fProt, BOOL ErrorReporting, BOOL ExceptionThrowing) { // First, set up our initialised flag to False MemFileInitialised = FALSE; WasError = FALSE; // Set our class variables from the passed in values ReportErrors = ErrorReporting; ThrowExceptions = ExceptionThrowing; FileProt = fProt; IsOpen = FALSE; // If file is opened for reading if (FileProt == CCMemRead) { // Is file pointer NULL? if (pFile == NULL) { // Yes; report error. IsOpen = FALSE; GotError(_R(IDE_NULL_FILE)); return; } MemHandle = BAD_MHANDLE; MemFile = (BYTE*) pFile; // Set Memory file pointer CurrentPos = 0; // Set Current file position // Check that file size is greater than zero if (size > 0) { FileSize = size; // Flag that everything has gone ok MemFileInitialised = TRUE; } else { IsOpen = FALSE; GotError(_R(IDE_FILE_SIZE_ZERO)); return; } IsOpen = TRUE; } // if file is open for writing else if (FileProt == CCMemWrite) { // check file size if (size > 0) FileSize = size; // if not zero use size passed in else FileSize = CCFILE_DEFAULTSIZE; // else used default size //Allocate Memory MemHandle = ClaimBlock(FileSize); // Check allocation worked ok if (MemHandle != BAD_MHANDLE) { IsOpen = TRUE; CurrentPos = 0; // Flag that everything has gone ok MemFileInitialised = TRUE; } else { IsOpen = FALSE; GotError(_R(IDE_MEM_BLOCK_FAILURE)); return; } } } /******************************************************************************************** > CCMemFile::~CCMemFile() Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Purpose: Default destructor. ********************************************************************************************/ CCMemFile::~CCMemFile() { if(isOpen()) { // report error that file is not closed before destructor call GotError(_R(IDE_MEM_CLOSE_ERROR)); // Release any memory block we might have if (MemHandle != BAD_MHANDLE) { ReleaseBlock(MemHandle); MemHandle = BAD_MHANDLE; } } } /******************************************************************************************** > BOOL CCMemFile::IsMemFileInited() Author: Neville_Humphrys (Xara Group Ltd) Created: 1/9/94 Inputs: None Returns: TRUE if the contructor went without errors or FALSE otherwise. Purpose: Allows errors to be returned from the constructor. SeeAlso: CCMemFile ********************************************************************************************/ BOOL CCMemFile::IsMemFileInited() { return MemFileInitialised; } BOOL CCMemFile::GetBuffer(BYTE** ppBuffer, UINT32* pSize) { if (!MemFileInitialised) return(FALSE); BYTE* tempBuf = NULL; size_t tempSize = 0; // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &tempBuf, &tempSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return FALSE; } *ppBuffer = tempBuf; *pSize = (UINT32)tempSize; return(TRUE); } /******************************************************************************************** > BOOL CCMemFile::open(void *pFile, UINT32 size, FileAccess fProt) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Inputs: pFile - a pointer to the file UINT32 - the size of the file fProt - defines the files protection - default = read only Returns: TRUE if file is opened successfully or FALSE otherwize Purpose: Opens an instance of a CCmemFile ********************************************************************************************/ BOOL CCMemFile::open(void *pFile, UINT32 size, FileAccess fProt) { // First check that the constructor went ok if (!MemFileInitialised) { // Did not construct ok, error should have been reported, so just fail IsOpen = FALSE; return FALSE; } FileProt = fProt; // If file is opened for reading if (FileProt == CCMemRead) { // Is file pointer NULL if (!pFile) { IsOpen = FALSE; GotError(_R(IDE_NULL_FILE)); return FALSE; } MemFile = (BYTE*) pFile; // Set Memory file pointer CurrentPos = 0; // Set Current file position // Check that file size is greater than zero if (size > 0) FileSize = size; else { IsOpen = FALSE; GotError(_R(IDE_FILE_SIZE_ZERO)); return FALSE; } } // if file is open for writing else if (FileProt == CCMemWrite) { // check file size if (size > 0) FileSize = size; // if not zero use size passed in else FileSize = CCFILE_DEFAULTSIZE; // else used default size // Allocate Memory MemHandle = ClaimBlock(FileSize); // Check allocation worked ok if (MemHandle != BAD_MHANDLE) { IsOpen = TRUE; CurrentPos = 0; } else { IsOpen = FALSE; GotError(_R(IDE_MEM_BLOCK_FAILURE)); return FALSE; } } return IsOpen; } /******************************************************************************************** > BOOL CCMemFile::GrowMemFile() Author: Mario_Shamtani (Xara Group Ltd) Created: 13/9/93 Return: TRUE if size can be increased otherwize FALSE Purpose: Will increase the size of the memory file by allocating more space in blocks 1k. This function is called by all the write functions when the file size limit is reached. Scope: Private ********************************************************************************************/ BOOL CCMemFile::GrowMemFile() { if (IncreaseBlock(MemHandle, CCFILE_DEFAULTSIZE)) //SplitBlock(MemHandle, CCFILE_DEFAULTSIZE, (FileSize - 1))) { FileSize += CCFILE_DEFAULTSIZE; return TRUE; } else { IsOpen = FALSE; GotError(_R(IDE_MEM_BLOCK_FAILURE)); return FALSE; } } /******************************************************************************************** > BOOL CCMemFile::setMode(INT32 fileMode) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Purpose: None- cannot change the mode on a memory file - either it's binary in which case it's a CCMemFile, or it's text, in which case it's a CCMemTextFile. SeeAlso: CCFile::setMode ********************************************************************************************/ BOOL CCMemFile::setMode(INT32 fileMode) { ENSURE(FALSE, "Should use CCMemFile or CCMemTextFile to set the file mode!"); return FALSE; } /******************************************************************************************** > BOOL CCMemFile::isOpen() const Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Return: TRUE if file is open and FALSE otherwize Purpose: Determines whether an instance of CCMemFile is open ********************************************************************************************/ BOOL CCMemFile::isOpen() const { return IsOpen; } /******************************************************************************************** > CCFile& CCMemFile::read(void* buf, UINT32 length = 1) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Outputs: A pointer to a single byte Returns: Reference to the CCFile object. Purpose: Reads a single byte from the Memory file ********************************************************************************************/ CCFile& CCMemFile::read(void* buf, UINT32 length) { // Make sure the file is open before it is read! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } // If not allowed to read, then exit. if (FileProt != CCMemRead) { GotError(_R(IDE_WRITE_ONLY)); return (CCFile&) *this; } BYTE *TempBuf = (BYTE*) buf; while ((length > 0) && !eof()) { *TempBuf++ = MemFile[CurrentPos++]; length--; } if (length > 0) { // Could not read the required number of bytes. GotError(_R(IDE_EOF_ERROR)); } return (CCFile&) *this; } CCFile& CCMemFile::read(StringBase *buf) { ENSURE(FALSE, "Use a CCMemTextFile for ASCII memory files!"); return (CCFile&) *this; } CCFile &CCMemFile::read( char &buf ) { // Make sure the file is open before it is read! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return *this; } // if file is write protected then exit if (FileProt != CCMemRead) { GotError(_R(IDE_WRITE_ONLY)); return *this; } TCHAR* tempMemFile = (TCHAR*) MemFile; // Cast MemFile to a TCHAR pointer if (!eof()) { buf = tempMemFile[CurrentPos++]; CharsRead ++; } else { // Trying to read pasty EOF GotError(_R(IDE_EOF_ERROR)); } return *this; } /******************************************************************************************** > CCFile& CCMemFile::write(const void* buf, UINT32 length = 1) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Inputs: A pointer to a single byte Length denotes number of bytes to written Returns: Reference to the CCFile object. Purpose: Writes a stream of bytes to the Memory file ********************************************************************************************/ CCFile& CCMemFile::write(const void* buf, UINT32 length) { // Make sure the file is open before it is written! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } // if file is read only then exit if (FileProt != CCMemWrite) { GotError(_R(IDE_READ_ONLY)); return (CCFile&) *this; } BYTE* tempBuf = (BYTE*) buf; // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &MemFile, &FileSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return (CCFile&) *this; } while (length > 0) { if (eof()) { if (GrowMemFile()) { // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &MemFile, &FileSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return (CCFile&) *this; } } else // Can't increase memfile - error break; } // Write input byte MemFile[CurrentPos++] = *tempBuf++; length--; } return (CCFile&) *this; } CCFile& CCMemFile::write(const StringBase& buf, UINT32 length) { ENSURE(FALSE, "Use a CCMemTextFile for ASCII memory files!"); return (CCFile&) *this; } CCFile &CCMemFile::write( char &buf ) { ENSURE(FALSE, "Use a CCMemTextFile for ASCII memory files!"); return (CCFile&) *this; } /******************************************************************************************** > CCFile& CCMemFile::seek(FilePos pos) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Returns: Reference to the CCFile object. Purpose: Sets the file pointer to the file position passed in. (Position zero is the beginning of the file) ********************************************************************************************/ CCFile& CCMemFile::seek(FilePos pos) { if(!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } if (pos <= (FilePos)(FileSize)) { CurrentPos = pos; // There were 1001 problems with memfile seeking / telling, the below sorts them out though if(IsLexerInitialised() && SeekingRequired) { Ch = 0; Ofs = 0; LastLinePos = pos; TokenBuf[0] = 0; Line = 0; CharsRead = 0; LastLinePos = pos; EOFFound = FALSE; // Fill up the buffers with the new chars GetLine(); //GetCh(); } } else { GotError(_R(IDE_FILEPOS_ERROR)); return (CCFile&) *this; } return (CCFile&) *this; } /******************************************************************************************** > FilePos CCMemFile::tell() Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Return: current file pointer position Purpose: Gets the file pointer position of the file. ********************************************************************************************/ FilePos CCMemFile::tell() { return CurrentPos; } /******************************************************************************************** > CCFile& CCMemFile::seekIn(FilePos Pos) Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Inputs: Pos - the desired file position. Returns: Reference to the CCFile object. Purpose: Alter position of the file input pointer. NB. input and output pointers are linked with CCMemFiles, so you will alter the output pointer too. ********************************************************************************************/ CCFile& CCMemFile::seekIn(FilePos Pos) { return seek(Pos); } /******************************************************************************************** > CCFile& CCMemFile::seekIn(INT32 Offset, ios::seek_dir Dir) Author: Jason_Williams (Xara Group Ltd) Created: 16/05/95 Inputs: Offset - the file offset required. Dir - the offset mode to use. Outputs: - Returns: Reference to the CCFile object. Purpose: Alter position of the file input pointer. NB. input and output pointers are linked with CCMemFiles, so you will alter the output pointer too. ********************************************************************************************/ CCFile& CCMemFile::seekIn(INT32 Offset, ios::seekdir Dir) { switch(Dir) { case ios::beg: return(seek(Offset)); case ios::cur: return(seek(tell() + Offset)); case ios::end: { FilePos NewPos = (FilePos)(FileSize - Offset); if (NewPos < 0) { ERROR3("Attempt to seek before beginning of file using seekIn with ios::end"); NewPos = 0; } return(seek(NewPos)); } default: break; // fall through } ERROR3("Illegal seekIn seek_dir value (CCMemFile::seekIn)"); return (CCFile&) *this; } /******************************************************************************************** > FilePos CCMemFile::tellIn() Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Returns: File position. Purpose: Return the position of the file input pointer. ********************************************************************************************/ FilePos CCMemFile::tellIn() { if(IsLexerInitialised()) { if(!SeekingRequired) ERROR3("CCMemFile::tellIn() will only work properly with seeking enabled"); // -1 for the character lookahead in operation return (FilePos)(Ofs + (INT32) LastLinePos - 1); } return tell(); } /******************************************************************************************** > virtual INT32 CCMemFile::Size() Author: Tim_Browse (Xara Group Ltd) Created: 31/03/94 Returns: Size in bytes of the file. Purpose: Find the size of the file. ********************************************************************************************/ size_t CCMemFile::Size() { return FileSize; } /******************************************************************************************** > BOOL CCMemFile::eof() Author: Mario_Shamtani (Xara Group Ltd) (fixed by Andy) Created: 6/9/93 Return: TRUE if end of file and FALSE otherwize Purpose: Determines whether an instance of CCMemFile is open ********************************************************************************************/ BOOL CCMemFile::eof() const { return (CurrentPos >= FileSize); } BOOL CCMemFile::good() const { return !WasError; } BOOL CCMemFile::bad() const { return WasError; } BOOL CCMemFile::fail() const { return WasError; } /******************************************************************************************** > BOOL CCMemFile::SetBadState() Author: Neville_Humphrys (Xara Group Ltd) Created: 31/08/94 Returns: None. Purpose: It allows the forceable setting of the test that functions like bad() use so the next check of the current file status to see if we should continue using the file or not will fail. This will be called by the GotError function so that any attempts to read/write after this should fail. SeeAlso: CCFile::GotError ********************************************************************************************/ void CCMemFile::SetBadState() { WasError = TRUE; } /******************************************************************************************** > BOOL CCMemFile::SetGoodState() Author: Neville_Humphrys (Xara Group Ltd) Created: 8/12/94 Returns: None. Purpose: It allows the forceable setting of the test that functions like bad() use so the next check of the current file status to see if we should continue using the file or not will pass. SeeAlso: CCFile::GotError ********************************************************************************************/ void CCMemFile::SetGoodState() { // Nuke any existing error states that might exist e.g. a lying eof() bit WasError = FALSE; } /******************************************************************************************** > BOOL CCMemFile::GetName( StringBase* name) const Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: Pointer to a CCMemFile name Outputs: None Returns: True if a name has been set otherwise False. At present always returns False. Purpose: Given a CCMemFile*, you can ask for some sort of name which is associated with that file. For filenames it might be a filename, or a pathname, for resource files it might be "Default Bitmap" etc. These names could then be used for making error messages have some extra useful information in. Errors: None ********************************************************************************************/ BOOL CCMemFile::GetName( StringBase* name) const { return FALSE; } /******************************************************************************************** > filedesc CCMemFile::GetFileHandle( ) Author: Neville_Humphrys (Xara Group Ltd) Created: 22/09/94 Inputs: None Outputs: None Returns: The file handle (descriptor) for this file (really an INT32). Purpose: Given an instance of a CCMemFile, you can ask for the actual file handle that describes the associated file. Required for the external filters. Errors: Not appropriate for memory files hence error at present SeeAlso: CCDiskFile::GetFileHandle(); CCFile::GetFileHandle() ********************************************************************************************/ filedesc CCMemFile::GetFileHandle() const { ERROR3("CCMemFile::GetFileHandle() called"); return -1; } /******************************************************************************************** > void CCMemFile::close() Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Purpose: Closes an instance of a CCMemFile ********************************************************************************************/ void CCMemFile::close() { IsOpen = FALSE; // Release any memory block we might have if (MemHandle != BAD_MHANDLE) { ReleaseBlock(MemHandle); MemHandle = BAD_MHANDLE; } } /******************************************************************************************** > virtual BOOL CCMemFile::InitCompression(BOOL Header = FALSE) Author: Neville_Humphrys (Xara Group Ltd) Created: 1/6/95 Purpose: To initialise the compression system ready for use. This is to make sure there is enough memory available for its buffers before writing out any compression tokens into the output file. MemFiles not supported at present so always returns FALSE. Graeme (15/11/99): Added the Header parameter. SeeAlso: StartCompression; StopCompression ********************************************************************************************/ BOOL CCMemFile::InitCompression(BOOL Header) { ERROR3("CCMemFile::InitCompression Cannot compress memory files yet"); return FALSE; } /******************************************************************************************** > virtual BOOL CCMemFile::StartCompression() Author: Neville_Humphrys (Xara Group Ltd) Created: 25/5/95 Purpose: To start up the compression system. MemFiles not supported at present so always returns FALSE. SeeAlso: StopCompression ********************************************************************************************/ BOOL CCMemFile::StartCompression() { ERROR3("CCMemFile::StartCompression Cannot compress memory files yet"); return FALSE; } /******************************************************************************************** > virtual BOOL CCMemFile::StopCompression() Author: Neville_Humphrys (Xara Group Ltd) Created: 25/5/95 Purpose: To stop the compression system. MemFiles not supported at present so always returns FALSE. SeeAlso: StartCompression ********************************************************************************************/ BOOL CCMemFile::StopCompression() { ERROR3("CCMemFile::StartCompression Cannot compress memory files yet"); return FALSE; } /******************************************************************************************** CCMemTextFile ********************************************************************************************/ /******************************************************************************************** > CCMemFile::CCMemFile(TCHAR *pFile, UINT32 size, FileAccess fProt) Author: Mario_Shamtani (Xara Group Ltd) Inputs: pFile - a pointer to the file UINT32 - the size of the file fProt - file protection - default = Read Only Created: 6/9/93 Purpose: Constructs an instance of CCMemTextFile and Opens it ********************************************************************************************/ CCMemTextFile::CCMemTextFile( char *pFile, UINT32 size, FileAccess fProt, BOOL ErrorReporting, BOOL ExceptionThrowing ) : CCMemFile( pFile, size, fProt, ErrorReporting, ExceptionThrowing ) { } /******************************************************************************************** > CCMemTextFile::~CCMemTextFile() Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Purpose: Default destructor. ********************************************************************************************/ CCMemTextFile::~CCMemTextFile() { } /******************************************************************************************** > BOOL CCMemTextFile::open(TCHAR *pFile, UINT32 size, FileAccess fProt) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Inputs: pFile - a pointer to the file UINT32 - the size of the file fProt - file protection - default = Read Only Returns: TRUE if file is opened successfully or FALSE otherwize Purpose: Opens an instance of a CCMemTextFile ********************************************************************************************/ BOOL CCMemTextFile::open( char *pFile, UINT32 size, FileAccess fProt ) { return CCMemFile::open(pFile, size, fProt); } /******************************************************************************************** > CCFile& CCMemTextFile::read(TCHAR& buf) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Outputs; character read in Returns: Reference to the CCFile object. Purpose: Reads a single character from the Memory file ********************************************************************************************/ CCFile &CCMemTextFile::read( char &buf ) { // Make sure the file is open before it is read! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return *this; } // if file is write protected then exit if (FileProt != CCMemRead) { GotError(_R(IDE_WRITE_ONLY)); return *this; } char* tempMemFile = (char*) MemFile; // Cast MemFile to a TCHAR pointer if (!eof()) { buf = tempMemFile[CurrentPos++]; CharsRead ++; } else { // Trying to read pasty EOF GotError(_R(IDE_EOF_ERROR)); } return *this; } /******************************************************************************************** > CCFile& CCMemTextFile::read(StringBase* buf) Author: Mario_Shamtani (Xara Group Ltd) (Fixed by Richard) Created: 6/9/93 (14/4/95) Inputs: - Output: Buf is the string buffer to return the string in Returns: Reference to the CCFile object. Purpose: Reads a stream of characters from the Memory file . We now stop the string if it won't fit in the buffer, or has hit an EOL. ********************************************************************************************/ CCFile& CCMemTextFile::read( StringBase *pBuf ) { // Make sure the file is open before it is read! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } // if file is write protected then exit if (FileProt != CCMemRead) { GotError(_R(IDE_WRITE_ONLY)); return (CCFile&) *this; } // Read characters in until we have MaxLength() of them, or we hit a new line PSTR tempMemFile = PSTR(MemFile); // Cast MemFile to a char pointer char Ch; INT32 Max = pBuf->MaxLength(); INT32 Off = 0; PTSTR Text = *pBuf; // chars to look for const char CR = '\n'; const char LF = '\r'; // We have to do this sneeky test for end of file because the io stream classes // are a load of old bollox! if (eof()) { // Its the end of the file all right Text[0] = 0; return (CCFile&) *this; } // Get the first char read(Ch); // Loop around until we get to the end of the line or the end of the file // Must leave 1 character space in the buffer if we reach the maximum buffer size // so that we can fit the terminating zero in below. while ((Max>1) && (Ch!=CR) && (Ch!=LF) && (!eof())) { // store the char we read #if FALSE != wxUSE_UNICODE Text[Off]=_T('?'); // in case it doesn't convert, we don't want unititalized memory mbtowc( Text + Off, &Ch, 1 ); ++Off; #else Text[Off++] = Ch; #endif // read another one and decrement the counter read(Ch); // Keep track of how much we have read Max--; } // if we ended at the end of a line, see if the next char is also part of a new line Ch = tempMemFile[CurrentPos]; if ((Ch==LF) || (Ch==CR)) { // eat the other part of the CR LF combo read(Ch); } // Terminate the string Text[Off++] = 0; // return return (CCFile&) *this; #if 0 // ******* This is the old Mario code // Make sure the file is open before it is read! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } // if file is write protected then exit if (FileProt != CCMemRead) { GotError(_R(IDE_WRITE_ONLY)); return (CCFile&) *this; } TCHAR* tempMemFile = (TCHAR*) MemFile; // Cast MemFile to a TCHAR pointer TCHAR* pString = *buf; // Cast input string to a TCHAR pointer UINT32 i = 0; // While String Length > String Max size // and not end of file while ((i <= DEF_STRING_SIZE) && (!eof())) { *pString = tempMemFile[CurrentPos++]; // output buffer = char read pString++; // increment output buffer ptr i++; // increment counter } return (CCFile&) *this; #endif } /******************************************************************************************** > CCFile& CCMemTextFile::write(const char& buf) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Inputs: A pointer to a single byte Returns: Reference to the CCFile object. Purpose: Writes a single byte to the Memory file ********************************************************************************************/ CCFile &CCMemTextFile::write( const char &buf ) { // Make sure the file is open before it is written! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } // if file is read only then exit if (FileProt != CCMemWrite) { GotError(_R(IDE_READ_ONLY)); return (CCFile&) *this; } TCHAR* tempMemFile; // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &MemFile, &FileSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return (CCFile&) *this; } // Cast pointer to memory file to TCHAR tempMemFile = (TCHAR*) MemFile; // if the file size limit is reached then increase memory file by default amount if (CurrentPos != (FileSize - 1)) tempMemFile[CurrentPos++] = buf; else { if (GrowMemFile()) { // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &MemFile, &FileSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return (CCFile&) *this; } // Cast pointer to memory file to TCHAR tempMemFile = (TCHAR*) MemFile; // write input byte tempMemFile[CurrentPos++] = buf; } } return (CCFile&) *this; } /******************************************************************************************** > CCFile& CCMemTextFile::write(const StringBase& buf, UINT32 length = 0) Author: Mario_Shamtani (Xara Group Ltd) Created: 6/9/93 Inputs: constant unicode string Length denotes number of bytes to written Returns: Reference to the CCFile object. Purpose: Writes a stream of bytes to the Memory file ********************************************************************************************/ CCFile& CCMemTextFile::write(const StringBase& buf, UINT32 length) { // Make sure the file is open before it is written! if (!isOpen()) { GotError(_R(IDE_NOTOPEN_ERROR)); return (CCFile&) *this; } // if file is read only then exit if (FileProt != CCMemWrite) { GotError(_R(IDE_READ_ONLY)); return (CCFile&) *this; } // Ensure that the length of the string to be written is not longer // than the string's size. if (length == 0) length = buf.Length(); else if ((INT32) length > buf.Length()) { GotError(_R(IDE_STRING_SIZE_ERROR)); return (CCFile&) *this; } const TCHAR* tempBuf = (const TCHAR *) buf; TCHAR* tempMemFile; // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &MemFile, &FileSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return (CCFile&) *this; } // Cast pointer to memory file to TCHAR tempMemFile = (TCHAR*) MemFile; for (UINT32 i = 0; (i <= length); i++) { // if the file size limit is reached then increase memory file by default amount if (CurrentPos != (FileSize - 1)) tempMemFile[CurrentPos++] = *tempBuf++; else if (GrowMemFile()) { // Get Pointer to the memory file if (!DescribeBlock(MemHandle, &MemFile, &FileSize)) { GotError(_R(IDE_MEM_BLOCK_FAILURE)); return (CCFile&) *this; } // Cast pointer to memory file to TCHAR tempMemFile = (TCHAR*) MemFile; // write input byte tempMemFile[CurrentPos++] = *tempBuf++; } } return (CCFile&) *this; } /******************************************************************************************** > BOOL CCMemTextFile::eof() Author: Mario_Shamtani (Xara Group Ltd) Created: 8/9/93 Return: TRUE if end of file and FALSE otherwise. Purpose: Determines whether an instance of CCMemTextFile has reached its EOF or not. ********************************************************************************************/ BOOL CCMemTextFile::eof() const { // Cast pointer to memory file to TCHAR char* tempMemFile = (char*) MemFile; if ((CurrentPos == (FileSize - 1)) || (tempMemFile[CurrentPos] == END_OF_FILE)) return TRUE; else return FALSE; } ///////////////////////////////////////////////////////////////////////////////////////////// /******************************************************************************************** > INT32 fake_filedesc(iostream& io) Author: Justin_Flude (Xara Group Ltd) Created: 11/8/96 Inputs: io - a reference to an iostream object (not constant). Returns: An integer 'file-descriptor'. This can be passed to the stream_* functions to identify the stream they should work on. Purpose: Creates a fake 'file-descriptor' that can be passed to C libraries, such as the Accusoft filter library, that allow the caller to redirect I/O. SeeAlso: unfake_filedesc; stream_read; stream_write; stream_seek; _read; _write; _lseek; fstream::fd ********************************************************************************************/ UINT_PTR fake_filedesc(iostream& io) { // Make sure this dirty trick is possible. ERROR3IF(sizeof(INT32) < sizeof(void*), "type 'INT32' too small for type 'istream*' in fake_filedesc"); // Return a "magic number" file-descriptor which is really a pointer to an iostream. return ~UINT32( (UINT_PTR)(&io) ); } /******************************************************************************************** > iostream* unfake_filedesc(INT32 nFileDesc) Author: Justin_Flude (Xara Group Ltd) Created: 12/8/96 Inputs: nFileDesc - the integer fake 'file-descriptor' previously obtained by a call to fake_filedesc. Returns: A pointer to the iostream object the 'file-descriptor' refers to. Purpose: Complementary function to fake_filedesc. SeeAlso: fake_filedesc; stream_read; stream_write; stream_seek; _read; _write; _lseek; fstream::fd ********************************************************************************************/ iostream* unfake_filedesc( UINT_PTR nFileDesc ) { // Make sure this dirty trick is possible. ERROR3IF(sizeof(INT32) < sizeof(void*), "type 'INT32' too small for type 'istream*' in unfake_filedesc"); // Convert this magic number back into a pointer to an iostream. iostream* ps = (iostream*) (void*) ~nFileDesc; ERROR3IF(ps == 0, "Null 'file-descriptor' in unfake_filedesc"); return ps; } /******************************************************************************************** > extern "C" INT32 ACCUAPI_IO stream_read(INT32 nFileDesc, char* pchBuffer, unsigned nBufSize) Author: Justin_Flude (Xara Group Ltd) Created: 5/8/96 Inputs: nFileDesc - the "file-descriptor" of the "file" to read from. This is really an iostream* cast to an INT32. pchBuffer - where to put the data that is read. nBufSize - the size of the input buffer pointed to by pchBuffer Returns: The number of bytes read by the call, or zero if at the end of the file, or -1 if there is an error. Purpose: Adapts functions that call C-style I/O routines so that they can use C++ streams instead. This function substitutes for the standard C read() function. Instead of nFileDesc being a file-descriptor, it is expected to be an INT32 returned by fake_filedesc. Using this function we can persuade old code, such as the Accusoft library, to read and write from structured storage. Errors: ERROR3 if the given buffer is larger than that allowed by istream. SeeAlso: stream_write; stream_seek; fake_filedesc; unfake_filedesc; iostream; istream::read; ios::eof; ios::bad; costream; fstream; _read ********************************************************************************************/ INT32 ACCUAPI_IO stream_read(INT32 nFileDesc, char* pchBuffer, unsigned nBufSize) { // Extract the input stream object associated with this request. iostream* ps = unfake_filedesc(nFileDesc); if (ps == 0 || ps->bad()) return -1; // Make sure the buffer isn't too big for a signed integer. if (nBufSize > INT_MAX) { ERROR3("Buffer too large for type 'signed INT32' in stream_read"); nBufSize = INT_MAX; } // If we're already at the end of the file then indicate this. if (ps->eof()) return 0; // Try to read the data into the given buffer. if (!ps->read(pchBuffer, (INT32) nBufSize) && !ps->eof()) return -1; // Return the number of bytes actually read. return ps->gcount(); } /******************************************************************************************** > extern "C" INT32 ACCUAPI_IO stream_write(INT32 nFileDesc, char* pchBuffer, unsigned nBufSize) Author: Justin_Flude (Xara Group Ltd) Created: 5/8/96 Inputs: nFileDesc - the "file-descriptor" of the "file" to write to. This is really an iostream* cast to an INT32. pchBuffer - where to get the data that is to be written. nBufSize - the size of the output buffer pointed to by pchBuffer Returns: The number of bytes written by the call, or -1 if there is an error. Purpose: Adapts functions that call C-style I/O routines so that they can use C++ streams instead. This function substitutes for the standard C write() function. Instead of nFileDesc being a file-descriptor, it is expected to be an INT32 returned by fake_filedesc. Using this function we can persuade old code, such as the Accusoft library, to read and write from structured storage. Errors: ERROR3 if the given buffer is larger than that allowed by ostream. SeeAlso: stream_read; stream_seek; fake_filedesc; iostream; ostream::write; costream; fstream; _write ********************************************************************************************/ INT32 ACCUAPI_IO stream_write(INT32 nFileDesc, char* pchBuffer, unsigned nBufSize) { // Extract the output stream object associated with this request. iostream* ps = unfake_filedesc(nFileDesc); if (ps == 0 || ps->bad()) return -1; // Make sure the buffer isn't too big for a signed integer. if (nBufSize > INT_MAX) { ERROR3("Buffer too large for type 'signed INT32' in stream_write"); nBufSize = INT_MAX; } // Try to write the data from the given buffer. if (!ps->write(pchBuffer, (INT32) nBufSize)) return -1; // Return the number of bytes actually written, which is always all or none. return (INT32) nBufSize; } /******************************************************************************************** > extern "C" INT32 ACCUAPI_IO stream_seek(INT32 nFileDesc, INT32 nOffset, unsigned fSeekType) Author: Justin_Flude (Xara Group Ltd) Created: 5/8/96 Inputs: nFileDesc - the "file-descriptor" of the "file" to write to. This is really an iostream* cast to an INT32. nOffset - the amount to seek by or the position to seek to. fSeekType - the direction of the seek (see the run-time docs for the _lseek function to get these flags). Returns: The new seek position, or -1 if there was an error. Purpose: Adapts functions that call C-style I/O routines so that they can use C++ streams instead. This function substitutes for the standard C seek() function. Instead of nFileDesc being a file-descriptor, it is expected to be an INT32 returned by fake_filedesc. Using this function we can persuade old code, such as the Accusoft library, to read and write from structured storage. Note that the function assumes that the stream has only one combined seek pointer, just like fstream and costream. If moving the input seek pointer doesn't also move the output seek pointer, as may be the case for some exotic iostream derivatives, then the function won't work properly. Errors: ERROR3 if the seek type is invalid or if the put and get seek positions aren't tied, as the semantics of the stream require. SeeAlso: stream_read; stream_write; fake_filedesc; iostream; iostream::seekg; fstream; costream; _lseek ********************************************************************************************/ INT32 ACCUAPI_IO stream_seek(INT32 nFileDesc, INT32 nOffset, unsigned fSeekType) { // Extract the stream object associated with this request. Note that in disk-based // streams (including the costream), the get and put seek positions are tied, so // moving one moves the other. Hence we can use a plain istream here. iostream* ps = unfake_filedesc(nFileDesc); if (ps == 0 || ps->bad()) return -1; // Convert the standard C flags for fSeekType into the iostream equivalents. // NB. make sure the flags as passed by Accusoft are the same as those used by // the Microsoft run-time library! ios::seekdir dir; switch (fSeekType) { case SEEK_SET: dir = ios::beg; break; case SEEK_CUR: dir = ios::cur; break; case SEEK_END: dir = ios::end; break; default: ERROR3("Bad seek direction in stream_seek"); return -1; } // Try to seek to the new position. if( !ps->seekg( (streampos)nOffset, ios_base::seekdir(dir) ) ) return -1; // Check if the iostream has similar semantics to fstream. ERROR3IF(ps->tellp() != ps->tellg(), "Put and get seek pointers aren't tied in stream_seek"); // Return the new seek position. return (INT32) ps->tellg(); }