blob: b1bf8cd73dafb74dec9511ebd471744f10752aad [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
#include <wchar.h> //for wcsncpy
#include "NAStdioFile.h"
#include "string.h"
#include "time.h"
// -------------------------------------------------------------------
CNAStdioFile::CNAStdioFile():CNADataSource()
{
m_fileHandle = NULL;
}
CNAStdioFile::~CNAStdioFile()
{
Close();
}
// -------------------------------------------------------------------
NABoolean CNAStdioFile::Open(const char *fileName, EOpenMode mode)
{
m_lastError = ENOERR;
if ( m_fileHandle != NULL )
{
// bulk reads should never be opening the file twice
if ( mode == eReadBulk )
throw -1;
// we already have the file open so just reset file pointer back
// to the beginning
// fseek returns 0 if successful, -1 if not
Int32 retcode = fseek(m_fileHandle, 0, SEEK_SET);
if (retcode != ENOERR)
{
m_lastError = errno;
return FALSE;
}
return TRUE;
}
// no file open so figure out which way to open it
switch (mode)
{
case eRead:
m_fileHandle = fopen(fileName, "r");
break;
case eReadBulk:
m_fileHandle = fopen(fileName, "r");
// if the open went OK, then set No Buffering on this file
// if ( m_fileHandle != NULL )
// setvbuf( m_fileHandle, NULL, IONBF, 0 );
break;
case eWrite:
m_fileHandle = fopen(fileName, "w");
break;
case eAppend:
m_fileHandle = fopen(fileName, "a");
break;
case eReadBinary:
m_fileHandle = fopen(fileName, "rb");
break;
case eWriteBinary:
m_fileHandle = fopen(fileName, "wb");
break;
case eReadWrite:
m_fileHandle = fopen(fileName, "r+");
break;
default:
// throw some error here since unknown mode??
break;
}
if (m_fileHandle == NULL)
m_lastError = errno;
return (m_fileHandle != NULL);
}
// -------------------------------------------------------------------
void CNAStdioFile::Close()
{
if (m_fileHandle != NULL)
{
fclose(m_fileHandle);
m_fileHandle = NULL;
}
}
// -------------------------------------------------------------------
// CNAStdioFile::ReadString
//
// return the length of the string read if the method processes
// the user's request successfully.
//
// returns -1 if the method encounters an error while processing
// the user's request. For bulk read operations, the user then
// needs to invoke the method CNAStdioFile::GetLastErrorAsDword
// to get the Microsoft error code; for other kinds of operations,
// i.e., the stdio operations, the user needs to call the method
// CNAStdioFile::GetLastError to get the errno.h error number.
//
// For bulk read operation on Windows NT platforms, the user
// should always check to make sure that the return value
// is zero (0) before calling the CNAStdioFile::IsEOF method
// to find out whether an EOF condition has been encountered.
// -------------------------------------------------------------------
Int32 CNAStdioFile::ReadString(char *buffer, Lng32 bufferSize, NABoolean flipByteOrderNeeded)
{
if (Initialize() == FALSE)
return -1;
ULng32 numRead = 0L;
if ( m_bulkRead )
{
throw -1;
}
else
{
numRead = fread(buffer, sizeof(char), bufferSize, m_fileHandle);
if (ferror(m_fileHandle))
{
m_lastError = errno;
return -1;
}
}
if ( flipByteOrderNeeded == TRUE )
FlipByteOrder(buffer, bufferSize);
return (Int32) numRead;
}
// -------------------------------------------------------------------
// CNAStdioFile::ReadBlock
//
// returns the length, in bytes, of the block of characters read
// if the method processes the user's request successfully. If
// the read block is empty, i.e., the end of the file has been
// reached, returns 0.
//
// returns -1 if the method encounters an error while processing
// the user's request.
//
// After the method CNAStdioFile::ReadBlock completes,
// besides checking the return value, the user can call one
// of the following methods to find out whether the method
// CNAStdioFile::ReadBlock call completed successfully or not:
//
// 1. For bulk read operations on Windows NT platforms, the users
// should invoke the method CNAStdioFile::GetLastErrorAsDword
// (instead of the method CNAStdioFile::GetLastError) to get
// the Microsoft ::GetLastError error code. Please note that
// the error conditions ERROR_IO_PENDING and ERROR_HANDLE_EOF
// are not considered as errors by this method; the method
// CNAStdioFile::GetLastErrorAsDword will return the Microsoft
// error code ERROR_SUCCESS (i.e. 0) for these cases. Note
// that the Microsoft error code ERROR_SUCCESS and the errno.h
// ENOERR value (i.e. 0) can be used interchangeably because
// they both equal to zero. For simplicity, we can safely use
// ENOERR in place of ERROR_SUCCESS, and it is safe to use the
// following check for bulk read operations running on Windows NT
// platforms: if (pStdioFile->GetLastError() != ENOERR) // error!
//
// 2. For other kinds of operations, i.e., the stdio operations,
// the user needs to call the method CNAStdioFile::GetLastError
// to get the errno.h error number. If CNAStdioFile::ReadBlock
// call was successful, the method CNAStdioFile::GetLastError
// returns the ENOERR (i.e. 0) value.
// -------------------------------------------------------------------
Int32 CNAStdioFile::ReadBlock( char *buffer, Lng32 numBytes,
NABoolean flipByteOrderNeeded )
{
if (Initialize() == FALSE)
return( -1 ); // an error has occurred
ULng32 numRead = 0L;
if ( m_bulkRead )
{
throw -1;
}
else
{
numRead = fread(buffer, sizeof(char), numBytes, m_fileHandle);
if (ferror(m_fileHandle))
{
m_lastError = errno;
return( -1 ); // an error has occurred
}
}
if ( flipByteOrderNeeded == TRUE )
FlipByteOrder(buffer, numBytes);
return (Int32)numRead;
}
// -------------------------------------------------------------------
void CNADataSource::FlipByteOrder(char* buffer, Lng32 bufferSize)
{
ComASSERT (bufferSize % 2 == 0);
// modified based on wc_swap_bytes(NAWchar *str, int length), in w:/common/wstr.h
unsigned char* ptr;
unsigned char temp;
if ( buffer == 0 || bufferSize == 0 ) return;
for (Lng32 i = 0; i < bufferSize; i += 2)
{
ptr = (unsigned char*)&buffer[i];
temp = *ptr;
*ptr = *(ptr+1);
*(ptr+1) = temp;
}
}
// -------------------------------------------------------------------
void CNADataSource::FlipByteOrder(char* buffer, TInt64 bufferSizeInBytes)
{
ComASSERT (bufferSizeInBytes % 2 == 0);
// modified based on wc_swap_bytes(NAWchar *str, int length), in w:/common/wstr.h
unsigned char* ptr;
unsigned char temp;
if ( buffer == NULL || bufferSizeInBytes == 0 ) return;
for (TInt64 i = 0; i < bufferSizeInBytes; i += 2)
{
ptr = (unsigned char*)&buffer[i];
temp = *ptr;
*ptr = *(ptr+1);
*(ptr+1) = temp;
}
}
// -------------------------------------------------------------------
// CNAStdioFile::CheckIOCompletion
//
// This method does nothing and returned 0 when running on NSK
// platforms.
//
// For Windows NT platforms, returns the number of characters
// read. After this method is invoked, the user will need to
// call the method CNAStdioFile::GetLastErrorAsDword to find
// out whether an error has occurred.
// -------------------------------------------------------------------
ULng32 CNAStdioFile::CheckIOCompletion()
{
ULng32 numRead = 0;
return( numRead );
}
// -------------------------------------------------------------------
// CNAStdioFile::Read
//
// return the length, in bytes, of the data read if the method
// processes the user's request successfully.
//
// returns -1 if the method encounters an error while processing
// the user's request. The user then needs to call the method
// CNAStdioFile::GetLastError to get the errno.h error number.
// -------------------------------------------------------------------
Int32 CNAStdioFile::Read(void *buffer, Lng32 bufferSize)
{
if (Initialize() == FALSE)
return -1;
Int32 numRead = 0;
numRead = (Int32) fread(buffer, sizeof(char), bufferSize, m_fileHandle);
if (ferror(m_fileHandle))
{
m_lastError = errno;
return -1;
}
return numRead;
}
// -------------------------------------------------------------------
NABoolean CNAStdioFile::IsEOF()
{
if ( m_bulkRead )
{
throw -1;
}
else
{
if ( feof(m_fileHandle) )
{
return TRUE;
}
else
return FALSE;
}
}
// -------------------------------------------------------------------
// CNAStdioFile::ReadLine
//
// Returns TRUE if the method was able to read the input
// successfully.
//
// Returns FALSE if the method encountered an error while
// processing the user's request or it could not read any
// more input data due to the EOF condition. The user
// then needs to call the CNAStdioFile::GetLastError method
// to find out whether an error has occurred or not, and
// the user needs to invoke the CNAStdioFile::IsEOF method
// to find out if an EOF condition has occurred.
// -------------------------------------------------------------------
NABoolean CNAStdioFile::ReadLine(char *buffer, Lng32 bufferSize)
{
if (Initialize() == FALSE)
return FALSE;
Int32 numRead = 0;
char *str = NULL;
str = fgets(buffer, bufferSize, m_fileHandle);
if (str == NULL)
{
if (IsEOF())
buffer[0] = '\0'; // just to be really sure
else
m_lastError = errno;
return FALSE;
}
// remove one trailing '\n' (newline) character if it exists
numRead = (Int32)strlen(buffer);
if (buffer[numRead - 1] == '\n')
buffer[numRead - 1] = '\0';
return TRUE;
}
// -------------------------------------------------------------------
// CNAStdioFile::WriteString
//
// return the length, in bytes, of the string written if the
// method processes the user's request successfully.
//
// returns -1 if the method encounters an error while processing
// the user's request. The user then needs to call the method
// CNAStdioFile::GetLastError to get the error number.
// -------------------------------------------------------------------
Int32 CNAStdioFile::WriteString(const char *strLine)
{
if (Initialize() == FALSE)
return -1;
Int32 strLength = (Int32) strlen(strLine);
Int32 charSize = sizeof(char);
Int32 numWrite = 0;
numWrite = (Int32) fwrite(strLine, charSize, strLength, m_fileHandle);
if (ferror(m_fileHandle))
{
m_lastError = errno;
return -1;
}
return numWrite;
}
// -------------------------------------------------------------------
// CNAStdioFile::Write
//
// return the number of 8-bit characters written if the method
// processes the user's request successfully.
//
// returns -1 if the method encounters an error while processing
// the user's request. The user then needs to call the method
// CNAStdioFile::GetLastError to get the error number.
// -------------------------------------------------------------------
Int32 CNAStdioFile::Write(const char *buffer, Lng32 bufferSize)
{
if (Initialize() == FALSE)
return -1;
Int32 numWrite = 0;
numWrite = (Int32)fwrite(buffer, sizeof(char), bufferSize, m_fileHandle);
if (ferror(m_fileHandle))
{
m_lastError = errno;
return -1;
}
return numWrite;
}
// -------------------------------------------------------------------
// CNAStdioFile::Write
//
// return the number of wide characters data written if the method
// processes the user's request successfully.
//
// returns -1 if the method encounters an error while processing
// the user's request. The user then needs to call the method
// CNAStdioFile::GetLastError to get the error number.
//
// Note that bufferSize contains the number of wide characters
// (in parameter buffer) to be written.
// -------------------------------------------------------------------
Int32 CNAStdioFile::Write(const NAWchar *buffer, Lng32 bufferSize, NABoolean flipByteOrderNeeded)
{
if (Initialize() == FALSE)
return -1;
NAWchar* buffer_write = NULL;
if ( flipByteOrderNeeded == TRUE )
{
buffer_write = new NAWchar[bufferSize];
if (na_wcsncpy (buffer_write, buffer, bufferSize) == 0)
{
// The copy operation failed - very unlikely
m_lastError = EINVAL;
delete [] buffer_write;
return -1;
}
TInt64 bufferSizeInBytes = bufferSize * sizeof(NAWchar);
FlipByteOrder((char*)buffer_write, bufferSizeInBytes);
}
else
buffer_write = (NAWchar*)buffer;
Int32 numWrite =
(Int32)fwrite(buffer_write, sizeof(NAWchar), bufferSize, m_fileHandle);
if (ferror(m_fileHandle))
{
m_lastError = errno;
if (buffer_write)
delete [] buffer_write;
return -1;
}
if ( flipByteOrderNeeded == TRUE )
delete [] buffer_write;
return numWrite; // number of wide characters written
}
// -------------------------------------------------------------------
// CNAStdioFile::Flush
//
// returns ENOERR (0) if successful; otherwise, returns EOF (-1).
// The user can then call the method CNAStdioFile::GetLastError to
// get the error number.
// -------------------------------------------------------------------
Int32 CNAStdioFile::Flush()
{
if (Initialize() == FALSE)
return EOF;
// fflush returns ENOERR if successful
Int32 status = fflush (m_fileHandle);
if (status != ENOERR)
m_lastError = errno;
return status;
}
//------------------------------------------------------------------------
CNADataSource::CNADataSource()
: m_lastError (ENOERR)
{
m_bulkRead = FALSE;
m_newlineStr[0] = '\n';
m_newlineStr[1] = '\0';
m_newlineStrWchar[0] = L'\n';
m_newlineStrWchar[1] = L'\0';
}
//---------------------------------------------------------------------
CNADataSource::~CNADataSource()
{
}
// --------------------------------------------------------------------------
// Helper: GetTimeString
//
// Get the current time in string format by calling ctime.
// If convertSpaceColonToDash is TRUE then all spaces and colons
// are converted to dashes.
//
// the caller needs to allocate CTIME_LENGTH character array prior to calling
// and send a pointer to this array as pTime
// --------------------------------------------------------------------------
void CNADataSource::GetTimeString( char *pTime, NABoolean convertSpaceColonToDash )
{
// This code gets the time from the ctime OSS call.
// ctime returns a 26 byte field in the form:
// Thu Feb 24 11:57:02 2005\n\0
// 1234567890123456789012345 6
//
// This code will:
// remove the \n (newline) and replace with \0
// optionally replace all spaces and ':' in the string with dashes
time_t t;
time (&t);
sprintf(pTime, "%s\n", ctime(&t));
pTime[24] = '\0';
// Replace the spaces with dashes.
if (convertSpaceColonToDash)
{
Int32 pos = 0;
while (pTime[pos] != '\0')
{
if (pTime[pos] == ' ' || pTime[pos] == ':')
pTime[pos] = '-';
pos++;
}
}
}