// streaml.cpp - class cStreamlist, emulates "low-level I/O functions"
//
// v0.16B34
//   changed all I/O calls from _open(), _close(), _read(), etc. to the
//   Win32 API equivalents CreateFile(), ReadFile(), CloseHandle(), etc.
//   hopefully, this doesn't introduce any bugs.  The Win32 file I/O routines
//   utilize different return codes (for example, 0 == error, not -1!)
//
// v0.16B33 bug fix (m_dwFileCount-1) in ::my_read() 
//  v0.16B3 - initial release
//    (replaces some code that used to be in mpv_read.cpp)
//
//   For now, the "high-level" emulation = mpeg2decoder I/O call emulation
//    (that is, all calls coming from the MPEG2Decoder are routed to the
//     high-level emulators.)
//   The "low-level" emulation sit between the operating-system calls
//    and the high-level emulation functions.  This allows the "streamlist"
//    to concept to behave (toward the rest of the application)
//    as a single logical file. 
//
// the concept of "streamlists" :
//
//     A "streamlist" =  a list of files to be concatenated into one logical
//     file.  In other words, the list of files are joined into one continuous
//     file, at the logical level.  cStreamlist makes this operation
//     transparent to the rest of the application.
//
//     cStraemlist's public-interface consists of the list-management calls,
//     and the emulated low-level file I/O functions :
//     _open(), _read(), _lseek(), _close()
//
//  one "stream" or "streamlist" = "a list of files."  This is not to be
//  confused with C++'s stream concepts!  hehe
//
// LOW-LEVEL EMULATION FUNCTIONS EMULATED
// --------------------------------------
//  my_read(), my_open(), my_close(), my_lseeki64(), my_telli64() etc.
//
//   differences from actual I/O library calls:
//    my_read() : emulation should be 100% identical
//    my_open() : emulation should be 100% identical
//    my_close() : emulation should be 100% identical
//    my_telli64() : emulation should be 100% identical
//    my_lseeki64() : emulator does *NOT* allow seeking beyond EOF
//	


#include <windows.h>
#include <winbase.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include "streaml.h"  // C++ object definition for class cStreamlist


// FILEOPEN() is used to check wheter the streamlist is open
#define FILEOPEN() ( m_stCFhandle != INVALID_HANDLE_VALUE )

// text manipulator compare in store.c
extern "C" int rstrcmpi( const char a[], const char b[] );

//////////////////////////////////////////////////////
//
//  constructor and destructor
//
//////////////////////////////////////////////////////

cStreamlist::cStreamlist( void )
{ 

	// initialize the streamlist's state
	//m_stCFhandle = _NOFILE;
	m_stCFhandle = INVALID_HANDLE_VALUE;
	m_stCFindex = _NOFILE;
	m_stAliasHandle = _NOFILE;

	// housekeeping variables (text logs and error logs)
	// allocate memory for logs
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	m_szErrorLog = new char[ LOG_LENGTH ];
	m_szMessageLog = new char[ LOG_LENGTH ];
	m_szText = new char[ TEXTMSG_LENGTH ];
	m_szText2 = new char[ TEXTMSG_LENGTH ];
	m_szLastLogErr = new char[ TEXTMSG_LENGTH ];
#endif
	m_lastError = 0;
	m_logCounter = 0;

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	if ( (m_szErrorLog == NULL) || ( m_szMessageLog == NULL ) || 
		( m_szText == NULL ) || ( m_szText2 == NULL ) ||
		( m_szLastLogErr == NULL ) )
	{
		// catastrophic error, couldn't allocate logs
		fprintf( stderr, "\ncStreamlist::cStreamlist() : couldn't allocate memory.");
		// exit( ERROR );
	}

	// clear the logs
	m_szLastLogErr[ 0 ] = 0;  // NULL char
	m_szText2[ 0 ] = 0;  // NULL char
	m_szText[ 0 ] = 0;  // NULL char
	m_szMessageLog[ 0 ] = 0;  // NULL char
	m_szErrorLog[ 0 ] = 0;  // NULL char

	TextLogMsg( LOG_NEW_ENTRY, "cStreamlist() : object construction done." );
#endif
	// clear te filelist array, must come after the logs are inited!
	list_clear(); // also clears m_dwFileCount
};

cStreamlist::~cStreamlist()
{
	if ( FILEOPEN() )	// if the streamlist is open, close it
		my_close( m_stAliasHandle );

	// destroy logs
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	if ( m_szErrorLog != NULL )
		delete( m_szErrorLog );
	if ( m_szMessageLog != NULL )
		delete( m_szMessageLog );
	if ( m_szText != NULL )
		delete( m_szText );
	if ( m_szText2 != NULL )
		delete( m_szText2 );
#endif
};


//////////////////////////////////////////////////////
//
//  protected/private member functions
//
//////////////////////////////////////////////////////

int
cStreamlist::list_clear( void )
{
	int i;

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "list_clear()" );
#endif
	if ( FILEOPEN() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( STERR_FAIL, "list_clear() : stream is in use!" );
#endif
		return STERR_FAIL;
	}

	for ( i = 0; i < MAXFILES; ++i )
	{
		m_list[ i ].qwLength = 0;
		m_list[ i ].filename[ 0 ] = '\0';
	}

	m_dwFileCount = 0;
	return STERR_OK;
}

// validate_handle()
// checks the passed parameter (input_handle) against the
// the stored aliashandle in the object.  The two should be equal.
// If they are not equal, then the caller may be reffering to a
// *different* file, and any streamlist function should fail.
// returns 1 == handles match
// returns 0    !!!handles do NOT match
int 
cStreamlist::validate_handle( int input_aliashandle )
{
	return ( input_aliashandle == m_stAliasHandle ); // v0.16B34 fixed
}// validate file handle


// get length of entire stream (sum of individual file lengths)
__int64
cStreamlist::qwStreamLength( void )
{
	int i;
	__int64 qwLength = 0;
//	LPDWORD lpdl = (LPDWORD) &qwLength, lpdh = (LPDWORD) &qwLength +1;

	for( i = 0; i < m_dwFileCount; ++ i)
	{	// sum the file-lengths of all files before current file index
		qwLength += m_list[ i ].qwLength;
	}

//	printf("\nqwStreamLength() : 0x%X 0x%X", *lpdh, *lpdl );
	return qwLength;
}



// list_nextfile() advances the stream to the next file
// 1) closes current file (updates appropriate vars)
// 2) opens the next file (updates appropriate vars)
// 3) returns the handle of opened file
HANDLE
cStreamlist::list_nextfile( void )
{
//	int next_handle = _NOFILE;
//	int old_handle;
	HANDLE next_handle = INVALID_HANDLE_VALUE;
	BOOL brc; // boolean return code

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	TextLogMsg( LOG_NEW_ENTRY, "list_nextfile() : " );
#endif	
	// is the current-file index == the 1st file in the stream?
	if ( m_stCFindex == _NOFILE )	
	{	// 1st file in stream, treat as a special case
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "  ...list_nextfile() : #1 = '%s'", 
			m_list[ 0 ].filename );
		printf( "%s", m_szText );
		TextLogMsg( 0, m_szText );
#endif
//		next_handle = _open( m_list[ 0 ].filename, O_RDONLY|O_BINARY );
		next_handle = CreateFile( m_list[ 0 ].filename, GENERIC_READ,
			FILE_SHARE_READ, NULL, OPEN_EXISTING, 
			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
		m_stCFhandle = next_handle ;
		m_stCFindex = 0; // set file index to 0
	}
	else if ( m_stCFindex < m_dwFileCount )	// not 1st file, handle normally
	{
		//old_handle	= _close( m_stCFhandle );
		brc	= CloseHandle( m_stCFhandle );
		if ( brc == 0 )	// check for error
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "list_nextfile() : couldn't close current file '%s' !",
				m_list[ m_stCFindex ].filename );
			TextLogErr( _NOFILE, m_szText );
#endif
			return INVALID_HANDLE_VALUE;	// error condition
		}

//		m_stCFhandle = _NOFILE;
		m_stCFhandle = INVALID_HANDLE_VALUE;
		++m_stCFindex; // increment file index

//		next_handle = _open( m_list[ m_stCFindex ].filename, O_RDONLY|O_BINARY );
		next_handle = CreateFile( m_list[ m_stCFindex ].filename,
			GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 
			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );
		if ( next_handle == INVALID_HANDLE_VALUE ) // check for error
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "list_nextfile() : couldn't open file#%d '%s' !",
				m_stCFindex + 1, m_list[ m_stCFindex ].filename );
			TextLogErr( _NOFILE, m_szText );
#endif
			return INVALID_HANDLE_VALUE; // error condition
		}

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "  ...list_nextfile() : #%d = '%s'\n", 
			m_stCFindex+1, m_list[ m_stCFindex ].filename );
		printf("%s", m_szText );
		TextLogMsg( 0, m_szText );
#endif
		m_stCFhandle = next_handle;
	}
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	else
		TextLogMsg( 0,"...list_nextfile() : end of the list!" );
#endif
	return next_handle;
}


/*
HANDLE CreateFile(
  LPCTSTR lpFileName,          // pointer to name of the file
  DWORD dwDesiredAccess,       // access (read-write) mode
  DWORD dwShareMode,           // share mode
  LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                               // pointer to security attributes
  DWORD dwCreationDisposition,  // how to create
  DWORD dwFlagsAndAttributes,  // file attributes
  HANDLE hTemplateFile         // handle to file with attributes to 
                               // copy
);*/


// list_get_ff() : get a list of filenames from the file "listname[]"
// (implicitly verifies the list's integrity)
// reads the file listname[], parses for filenames (stores in m_filenames[])
// returns the # of filenames, or STERR_FAIL (-1)
int 
cStreamlist::list_get_ff( const char listname[] )
{
	char szLine[ MAXLINELENGTH ];
	char filename[ MAXLINELENGTH ];
	char *prc = NULL;
	int i;
	long lCounter = 0; // line counter, #lines read from listname[]
	long lNumFiles = 0;	// file counter, #files read from listname[]
	BOOL fFileExists; // boolean flag indicating current file's status
	BOOL fDone = FALSE;	// loop exit condition flag
	FILE *fpin = NULL;
	int dwrc = 0; // dword return code

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "list_get_ff( '%s' ) : ", listname );
	TextLogMsg( LOG_NEW_ENTRY, m_szText );
#endif
	fpin = fopen( listname, "rt" ); // open the streamlist
	if ( fpin == NULL )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "list_get_ff() : couldn't open streamlist '%s'", 
			listname );
		TextLogErr( STERR_FAIL, m_szText );
#endif
		return STERR_FAIL;
	}

	szLine[ 0 ] = 'a'; // initialize buffer
	fFileExists = TRUE; // initialize flag  condition code
	do  {	// do loop until fDone == TRUE
		// clear key parts of the buffer, so we can detect certain error codes
		szLine[ 0 ] = 0;	// clear line before reading, just in case
		szLine[ MAXLINELENGTH - 2 ] = 0; // clear 2nd to last buffer byte
		// the 2nd to last buffer byte will be set to '\n', if szLine is too
		// short to hold the read line

		++lCounter; // increment line-counter

		prc = fgets( szLine, MAXLINELENGTH, fpin ); // read text from file
//		printf( "\nline#%d : ", lCounter, szLine );

		if ( szLine[ MAXLINELENGTH - 2 ] == '\n' )
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "list_get_ff() : line#%d too long!",lCounter);
			TextLogErr( STERR_FAIL, m_szText );
#endif
			exit( ERROR );	// need to fix this
		}

		// strip out the newline char, replace with end of line char \0
		// skip first character, just in case the line was blank
		// otherwise the while() expression will falsely exit
		for ( i = 1; i < strlen( szLine ); ++i )
		{
			if ( szLine[ i ] == '\n' )
				szLine[ i ] = 0;	// set to NULL
		}

		if ( szLine[ 0 ] == SKIP_CHAR )
			continue;	// ignore current line, it is a remark

		i = sscanf( szLine, " %s", filename ); // get filename
		if ( i != 1 )
			continue;	// ignore current line, no information
		
		// try to add current file to end of streamlist
		dwrc = list_insert_file( filename, lNumFiles );
		if ( dwrc == STERR_OK )
			++lNumFiles;	// success, increment #files
		else
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "list_get_ff() : error parsing line#%d ",
				lCounter );
			TextLogErr( 0, m_szText );
#endif
			fFileExists = FALSE;	// flag an error condition
		}

	} 	while ( (!fDone) && (prc != NULL) && lNumFiles < MAXFILES );

	fclose( fpin );	// close the listfile
	if ( fFileExists == FALSE )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( STERR_FAIL, "list_get_ff() : Errors occured during streamlist parsing, cannot continue.");
#endif
		return STERR_FAIL;
	}

	if ( lNumFiles <= 0 )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( STERR_FAIL, "list_get_ff() : No files found!" );
#endif
		return STERR_FAIL;
	}

	if ( lNumFiles >= MAXFILES )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "list_get_ff() : Too many files (%d)", lNumFiles);
		TextLogErr( STERR_FAIL, m_szText );
#endif
		return STERR_FAIL;
	}

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	//printf("\nlist_get_ff( '%s' ) : ", listname );
	for ( i = 0 ; i < lNumFiles; ++i )
	{
		sprintf( m_szText, "\n\tFILE#%d = '%s'", (i+1), m_list[ i ].filename );
		printf( "%s", m_szText );
		TextLogMsg( 0, m_szText );
	}
#endif

	return lNumFiles;	// all files are there, ok!
} // cStreamlist::list_get_ff()


// list_insert_file( filename[], index ) : 
//
//   checks existence & size of filename[].  If all is well, stores the data
//   into the filelist array @ m_list[ index ]
//
// returns STERR_FAIL or STERR_OK
int 
cStreamlist::list_insert_file( const char filename[], int index )
{
	int fhtemp = _NOFILE; // temporary file handle
	int rc; // integer return code
	__int64 int64rc = _NOFILE; // return code from function
	BOOL fFileExists = FALSE;	// success condition flag 

	// attempt to open filename[]
	fhtemp = _open( filename, _O_RDONLY | _O_BINARY );
	if ( fhtemp == _NOFILE )	// check if _open() succeeded
	{	// nope, couldn't open the file "filename[]"
		fprintf( stderr, "\nlist_insert_file() : line could not open '%s'", 
			filename );
		fFileExists = FALSE;
	}
	else
	{	// the file in the streamlist exists, now get its filelength
		int64rc = _lseeki64( fhtemp, 0, SEEK_END );  // seek end of file
		if ( int64rc == -1 ) // did _lseeki64() fail?
		{
			fprintf( stderr, "\nlist_insert_file() : _lseeki64( '%s' ) failed", 
				filename );
			fFileExists = FALSE;	// deliberately flag an error condition
		}
		else
		{	// sucessfully acquired file-length of filename[]
			if ( strlen( filename ) > MAXLINELENGTH )
			{
				// length of filename is TOO LONG, must abort 
				fprintf( stderr, "\nlist_insert_file() : the name '%s' is too long!",
					filename );
				fFileExists = FALSE; // force error condition
			}
			else
			{
				// finally, store the record into our m_list[] array
				m_list[ index ].qwLength = int64rc;
				strcpy( m_list[ index ].filename, filename ); // store filename
				fFileExists = TRUE;
			}

		} // end if ( int64rc == -1 ) 

		rc = _close( fhtemp ); // close file
		if ( rc == -1 ) // error condition
		{
			fprintf( stderr, "\nlist_insert_file( %d ) : couldn't close '%s'",
				index, filename );
		}
	} // end if ( fhtemp == _NOFILE )

	return ( fFileExists ? STERR_OK : STERR_FAIL ); // 1 = success, 0 = failure

} // cStreamlist::list_insert_file( )


////////////////////////////////////////////////////////////////////////
//
//  low-level I/O emulation functions
//
////////////////////////////////////////////////////////////////////////



// low level emulation of _telli64()
__int64 
cStreamlist::my_telli64( int handle )
{
	int i;
	__int64 qwOffset = 0; // total length up until current file
	__int64 qwCFoffset = 0; // byte position in current file m_file[m_stCFindex]
	LARGE_INTEGER liCFP; // large_integer "current file position"

	liCFP.QuadPart = 0;

//	LPDWORD lpdl = (DWORD *)&qwOffset, lpdh = (DWORD *) &qwOffset +1;

	//sprintf( m_szText, "my_telli64( %d ) : ", handle );
	//TextLogMsg( LOG_NEW_ENTRY, m_szText );
	if ( !FILEOPEN() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_telli64(%d) : No file was open!", handle );
		TextLogErr( STERR_FAIL, m_szText );
#endif
		return STERR_FAIL;
	}

	if ( !validate_handle( handle ) ) // check if ( handle == our file handle)
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_telli64(%d) : file handle does not match stored handle(%d)!",
			handle, m_stAliasHandle );
		TextLogErr( -1, m_szText );
#endif
		return -1;	// fail code 
	}

	// calculate the logical offset within the stream
	for( i = 0; i < m_stCFindex; ++ i)
	{	// sum the file-lengths of all files before current file index
		qwOffset += m_list[ i ].qwLength;
	}

	// qwOffset = logical position of file[ m_stCFindex ]
	//qwCFoffset = _telli64( m_stCFhandle );
/*
DWORD SetFilePointer(
  HANDLE hFile,          // handle of file
  LONG lDistanceToMove,  // number of bytes to move file pointer
  PLONG lpDistanceToMoveHigh,
                         // pointer to high-order DWORD of 
                         // distance to move
  DWORD dwMoveMethod     // how to move
);*/
	liCFP.LowPart = 0;
	liCFP.HighPart = 0;
	liCFP.LowPart = 
		SetFilePointer( m_stCFhandle, 0, &liCFP.HighPart, FILE_CURRENT );

	// now we need to check for an error
	if ( liCFP.LowPart = 0xFFFFFFFF )
	  if ( GetLastError() != NO_ERROR )
	  {
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "\nmy_telli64( %d ) : _telli64( %d ) failed!",
			handle, m_stCFhandle );
		TextLogErr( -1, m_szText );
#endif
		return -1;	// return error code
	  }

	qwCFoffset = liCFP.QuadPart;

/*	if ( qwCFoffset == -1 )	// error condition ?
	{
		sprintf( m_szText, "\nmy_telli64( %d ) : _telli64( %d ) failed!",
			handle, m_stCFhandle );
		TextLogErr( -1, m_szText );
		return -1;	// return error code
	} */

	qwOffset += qwCFoffset;

//	sprintf( m_szText" position is ( 0x%X 0x%X )", *lpdh, *lpdl );
//	TextLogMsg( 0, m_szText );

	return qwOffset;	// return logical offset
} // endfunction my_telli64()

__int64 
cStreamlist::my_lseeki64( int handle, __int64 offset, int origin )
{
	int i, rc;
	BOOL brc;	// boolean return code
	__int64 qwOffset;	// byte position, temp working variable
	__int64 qwCFoffset; // byte position in CURRENT file m_file[m_stCFindex]
	LARGE_INTEGER li_offset; // LARGE_INTEGER version of input param "offset"
	LARGE_INTEGER li_rc;	// return code from SetFilePointer()

	li_offset.QuadPart = offset;

//	sprintf( m_szText, "my_lseeki64( 0x%X 0x%X )", *lpdwh, *lpdwl );
//	TextLogMsg( LOG_NEW_ENTRY, m_szText );


	// 1) validate/verify the specified handle
	if ( !FILEOPEN() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_lseeki64(%d) : No file was open!", handle );
		TextLogErr( _NOFILE, m_szText );
#endif
		return _NOFILE;
	}

	if ( !validate_handle( handle ) ) // check if ( handle == our file handle)
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_lseeki64() : file handle(%d) does not match stored handle(%d)!",
			handle, m_stAliasHandle );
		TextLogErr( -1, m_szText );
#endif
		return -1;	// fail code for _close()
	}

	// 2) convert the supplied <offset, origin> ==> offset, SEEK_SET
	//    store the converted value in li_offset
	switch( origin )
	{
		case SEEK_SET :
//			printf(" SEEK_SET" );
			break;
		case SEEK_END :
//			printf(" SEEK_END" );
			li_offset.QuadPart = qwStreamLength() - offset;
			break;
		case SEEK_CUR :
			qwOffset = my_telli64( handle );
			if ( qwOffset == -1 )
			{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
				sprintf( m_szText, "my_lseeki64( SEEK_CUR ) : my_telli64() failed");
				TextLogErr( -1, m_szText );
#endif
				return -1; // fail code
			}
			//offset += qwOffset;
			li_offset.QuadPart = offset + qwOffset;
			break;
		default:
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "my_lseeki64( 0x%X ) : unknown origin (0x%X)", 
				origin, origin );
			TextLogErr( -1, m_szText );
#endif
			return -1;
	}	// end switch( origin )
	// li_offset is now a byte Offset, with origin at the START of the stream

	// 3) validate the converted li_offset value...is it still within range?
	if ( li_offset.QuadPart < 0 || li_offset.QuadPart > qwStreamLength() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_lseeki64(%d, offset<0x%X | 0x%X> ) : offset out of range! ",
			handle, li_offset.HighPart, li_offset.LowPart );
		TextLogErr( -1, m_szText );
#endif
		return -1;	// fail code
	}

//	printf("\nmy_lseeki64() : => left offset 0x%X 0x%X", li_offset.HighPart, 
//		li_offset.LowPart );

	// 4) calculate the correct file# (new value for m_stCFindex)
	qwOffset =0;
	i = 0;
	while ( ( qwOffset + m_list[ i ].qwLength ) < li_offset.QuadPart
		&& ( (i+1) < m_dwFileCount ) )
	{	// loop until we just pass offset
		qwOffset += m_list[ i ].qwLength;
		++i;
//		lpdwl = (LPDWORD) &qwOffset;
//		lpdwh = (LPDWORD) &qwOffset + 1;
//		printf("\nmy_lseeki64() : loop(%d)=> qwOffset 0x%X 0x%X", i, *lpdwh, *lpdwl );
	}
	// Meaning of variables after while() loop has finished execution :
	//	i = the new current file index m_stCFindex
	//	qwOffset = absolute position of the beginning of file#i 

	// qwCFoffset = calculated offset for current file
	qwCFoffset = li_offset.QuadPart - qwOffset;
	if ( qwCFoffset < 0 || ( qwCFoffset > m_list[ i ].qwLength ) )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( -1, "my_lseeki64() : opps, qwCFoffset out of bound!" );
#endif
		return -1; // fail code
	}

	// 5) check if the desired seek position (offset) is outside the range
	//    of the currently open file (m_list[m_stCFindex])
	//    If so, we must close it, and re-open the correct file.
	if ( m_stCFindex != i )
	{	// we need to close current file and open a new file
		//rc = _close( m_stCFhandle );	// close current file
		brc = CloseHandle( m_stCFhandle );
//		printf("\nseek() : openning file #%d", m_stCFindex + 1 );
		m_stCFindex = i;
//		if ( rc == -1 )
		if ( brc == 0 )
		{
			m_stCFindex = _NOFILE;	// reset
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			TextLogErr( -1, "my_lseeki64() : couldn't close old file !" );
#endif
			return -1; // fail code
		}

//		m_stCFhandle = _open( m_list[ m_stCFindex ].filename, m_st_oflag );
		m_stCFhandle = CreateFile( m_list[ m_stCFindex ].filename, 
			GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 
			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL );

		if ( m_stCFhandle == INVALID_HANDLE_VALUE )
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			sprintf( m_szText, "my_lseeki64() : couldn't open new file '%s'!",
				m_list[ m_stCFindex ].filename );
			TextLogErr( -1, m_szText );
#endif
			m_stCFindex = _NOFILE;	// reset
			return -1; // fail code
		}

		// m_stCFindex = index of the new file
		// m_stCFhandle = handle of the new file
	}

	// 6) seek the correct position in the open file
//	li_offset.QuadPart = qwCFoffset; // li_offset is a copy of qwCFoffset
	li_rc.QuadPart = qwCFoffset;

	li_rc.LowPart = SetFilePointer( m_stCFhandle, li_rc.LowPart, 
		&li_rc.HighPart, FILE_BEGIN );

//	qwCFoffset = _lseeki64( m_stCFhandle, qwCFoffset, SEEK_SET );
	// check for function failure
	if ( li_rc.LowPart == 0xFFFFFFFF )
	  if ( GetLastError() != NO_ERROR )
	  {
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( -1, "my_lseeki64() : _lseeki64() failed!" );
#endif
		return -1;
	  }

/*	if ( qwCFoffset == -1 ) // check for errors
	{
		TextLogErr( -1, "my_lseeki64() : _lseeki64() failed!" );
		return -1;
	}*/

//	lpdwl = (LPDWORD) &qwCFoffset;
//	lpdwh = (LPDWORD) &qwCFoffset + 1;
//	printf(" , qwCFoffset 0x%X 0x%X", *lpdwh, *lpdwl );

	qwOffset += li_rc.QuadPart; // update the logical position

//	lpdwl = (LPDWORD) &qwOffset;
//	lpdwh = (LPDWORD) &qwOffset + 1;
//	printf("\nmy_lseeki64() : => Pos 0x%X 0x%X", *lpdwh, *lpdwl );

//	if (  qwOffset != offset )
//	{
//		TextLogErr( -1, "my_lseeki64() : uh oh... requested offset != seeked position!" ); 
//		return -1; 
//	}
	if (  qwOffset != li_offset.QuadPart )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_lseeki64() : uh oh ... Requested pos(0x%X, 0x%X) != Returned pos(0x%X, 0x%X )",
			(qwOffset >> 32), qwOffset, li_offset.HighPart, li_offset.LowPart );
		//TextLogErr( -1, "my_lseeki64() : uh oh... requested offset != seeked position!" ); 
		TextLogErr( -1, m_szText ); 
#endif
		return -1; 
	}

	return qwOffset ; // new position (absolute position within "stream")
}	// my_lseeki64()


// my_read() is the low-level emulation of _read()
int
cStreamlist::my_read( int handle, void *buffer, unsigned int count )
{
	int rc = 0, rc2;
	HANDLE thandle;
	BOOL brc;
	DWORD dwRead = 0, dwRead2 = 0; // number of bytes read from file
	unsigned char *lpBuffer = (unsigned char *) buffer;	// char pointer to buffer

	//sprintf( m_szText, ""my_read( h=%d, count=%u) : ", handle, count );
	//TextLogMsg( LOG_NEW_ENTRY, m_szText );
	if ( !FILEOPEN() )
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_read(%d, %u) : No file was open!", handle, count );
		TextLogErr( _NOFILE, m_szText );
#endif
		return _NOFILE;
	}

/*BOOL ReadFile(
  HANDLE hFile,                // handle of file to read
  LPVOID lpBuffer,             // pointer to buffer that receives data
  DWORD nNumberOfBytesToRead,  // number of bytes to read
  LPDWORD lpNumberOfBytesRead, // pointer to number of bytes read
  LPOVERLAPPED lpOverlapped    // pointer to structure for data
);*/

//	rc = _read( m_stCFhandle, buffer, count );
	brc = ReadFile( m_stCFhandle, (LPVOID) buffer, count, &dwRead, NULL );

	// check whether we reached end of current file
	// v0.16B33 bug fix (m_dwFileCount-1)
	//if ( (rc < count) && (m_stCFindex < (m_dwFileCount-1) ) )
	if ( (dwRead < count) && (m_stCFindex < (m_dwFileCount-1) ) )
	{	// only have rc bytes. Still need to read (count - rc) more bytes
		thandle = list_nextfile(); // advance to next file
		//if ( thandle >= 0 )
		if ( thandle != INVALID_HANDLE_VALUE  )
		{	// we've switched to the next file, continue to fill buffer
			// read remaining bytes (count-dwRead), and append to buffer[dwRead]
			lpBuffer += dwRead;	// advance buffer position
			//dwRead2 = _read( m_stCFhandle, lpBuffer, count - dwRead );
			brc = ReadFile( m_stCFhandle, (LPVOID) lpBuffer, 
				count - dwRead, &dwRead2 , NULL );
			dwRead = dwRead + dwRead2; // update rc
		}
	}

	return dwRead;  // rc == total # bytes read
} // endfunction my_read()


int 
cStreamlist::my_open( const char *filename, int oflag )
{
	int rc = -1;	// initialize return code to FAILURE
	HANDLE hrc = INVALID_HANDLE_VALUE; //  init return code to failure

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "my_open( '%s', 0x%X ) : ", filename, oflag );
	TextLogMsg( LOG_NEW_ENTRY, m_szText);
#endif

	if ( FILEOPEN() )	// is the streamlist already open?
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		TextLogErr( STERR_LIST_OPEN, 
			"my_open() : another streamlist is already open!" );
#endif
		return STERR_LIST_OPEN;
	}

	list_clear();	// clear streamlist for new file

	m_stCFindex = _NOFILE;	// reset streamlist's file-index-pointer
		// when list_nextfile() is called, it will open the 1st file
	m_st_oflag = oflag;	// capture the chosen file-mode

	// is the input filename a streamlist?  check filename's extension
	if ( rstrcmpi( filename, ".lst" ) == 0 )
	{	// filename points to a streamlist
		rc = list_get_ff( filename); // get file-list from streamlist
		if ( rc <= 0 )  // <0 indicates error, ==0 means no files!
		{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
			TextLogErr( -1, "my_open() : streamlist verification failed." );
#endif
			return -1; // fail code
		}

		m_dwFileCount = rc; // set streamlist.numfiles
		// get first file

	//	rc = list_nextfile( ); // get 1st file
		hrc = list_nextfile( ); // get 1st file
		//printf("\nmy_open() : multi-file %d %d", m_stAliasHandle, m_stCFhandle );
		if ( hrc == INVALID_HANDLE_VALUE )	// did we successfully open the file?
			rc = -1;	// no, error code
		else
		{	// yes return an arbitrary value as the "alias handle"
			rc = ARBITRARY_VALUE;	// yes assign an arbitrary value
			m_stAliasHandle = rc; // set alias handle of 1st file
		}
		return rc;
	}	// end if ( rstrcmpi( filename, ".lst" ) == 0 )

	// normal single-bitstream input
	rc = list_insert_file( filename, 0 );	// add 1 file to list[ 0 ]
	m_dwFileCount = 1;	// 1 file only
//	rc = list_nextfile( ); // get 1st file
	hrc = list_nextfile( ); // get 1st file
//	if ( rc >= 0 )
	if ( hrc != INVALID_HANDLE_VALUE )
	{
//		m_stCFhandle = rc;	// set actual file handle
		m_stAliasHandle = ARBITRARY_VALUE;	// set alias handle
		rc = m_stAliasHandle;
//		m_stCFindex = 0;	// set index to 1st file
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "succeeded! alias handle => %d", m_stAliasHandle );
		TextLogMsg( 0, m_szText );
#endif
	}
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	else
		TextLogMsg( 0, "failed!" );
#endif
	return rc;
} // endfunction my_open()

int 
cStreamlist::my_close( int handle )
{
	int rc; // return code
	BOOL brc; // boolean return code

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
	sprintf( m_szText, "my_close( %d ) : ", handle );
	TextLogMsg( LOG_NEW_ENTRY, m_szText );

	if ( !FILEOPEN() )
		TextLogErr( 0, "my_close() : No file was open!" ); // non-fatal error
#endif

	if ( !validate_handle( handle ) ) // check if ( handle == our file handle)
	{
//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG
		sprintf( m_szText, "my_close() : handle(%d) does not match stored handle(%d)!",
			handle, m_stAliasHandle );
		TextLogErr( -1, m_szText );
#endif
		return -1;	// fail code for _close()
	}

	//printf("\nmy_close( %d ) : closing file...", handle );
//	rc = _close( m_stCFhandle );
	brc = CloseHandle( m_stCFhandle );	// close the file
	if ( brc == 0 )	// did CloseHandle() fail?
		rc = -1;	// yes, set return value to ERROR code
	else
		rc = 0;		// no error, success code

	m_stCFindex = _NOFILE;	// set file to no index
	m_stCFhandle = INVALID_HANDLE_VALUE; // set file handle to no file, IMPORTANT
	m_stAliasHandle = _NOFILE;

	return rc;
}


//
// -----------------------------------------------------------------------------
//
// Housekeeping functions
//
// -----------------------------------------------------------------------------
//

//SVE 03.06.2001 TextLogMsg nur im Debug-Modus
#ifdef _DEBUG

void 
cStreamlist::TextLogErr( DWORD errorID, char text[] )
{
	char temp_text[ TEXTMSG_LENGTH ];

	static DWORD dwPurgeCount = 0;

	if ( strlen( m_szErrorLog ) > ( ( LOG_LENGTH >> 1 ) - TEXTMSG_LENGTH ) )
	{
		++dwPurgeCount;
		printf("\ncStreamlist::TextLogErr() : Warning log-size exceeded %ld bytes",
			strlen( m_szErrorLog ) );
		printf("\n\tPurging log...");
		sprintf( m_szErrorLog, "<ErrLog purged %ld times>\n", dwPurgeCount );
	}

	sprintf( temp_text, "\n#%ld cStreamlist::", m_logCounter );
	if ( text != NULL )
		strcat( temp_text, text );
	else
		strcat( temp_text, "<NULL>");
	strcat( m_szErrorLog, temp_text );
	strcpy( m_szLastLogErr, temp_text );

	printf( "%s", temp_text );


	sprintf( temp_text," Error ID = %0X ", errorID );
	strcat( m_szErrorLog, temp_text );
	strcat( m_szLastLogErr, temp_text );

	printf( "%s\n", temp_text );

	m_lastError = errorID; // update last error variable

	// counter is incremented by TextLogMsg()
} // cStreamlist::TextLogErr()


void 
cStreamlist::TextLogMsg( DWORD dwFlags, char text[] )
{
	char temp_text[ TEXTMSG_LENGTH ];

	static DWORD dwPurgeCount = 0;

	if ( strlen( m_szMessageLog ) > ( ( LOG_LENGTH >> 1 ) - TEXTMSG_LENGTH ) )
	{
		++dwPurgeCount;
		printf("\ncStreamlist::TextLogMsg() : Warning log-size exceeded %ld bytes",
			strlen( m_szMessageLog ) );
		printf("\n\tPurging log...");
		sprintf( m_szMessageLog, "<Log purged %ld times>\n", dwPurgeCount );
	}


	if ( dwFlags & LOG_NEW_ENTRY )
	{
		sprintf( temp_text, "\n#%ld cStreamlist::", m_logCounter );
		if ( text != NULL )
			strcat( temp_text, text );
		else
			strcat( temp_text, "<NULL>");
		strcat( m_szMessageLog, temp_text );

		m_lastError = STERR_OK; // clear lastError flag
		strcpy( m_szLastLogErr, "<NO ERROR>"); // clear lasterror msg
		++m_logCounter;  // increment counter
	}
	else
	{
		strcat( m_szMessageLog, text );
	}
} // cStreamlist::TextLogMsg()

#endif
 
/*

   old v0.16b31 implementation, used _open(), _read(), _close(), etc.
int
cStreamlist::list_nextfile( void )
{
	int next_handle = _NOFILE;
	int old_handle;

	TextLogMsg( LOG_NEW_ENTRY, "list_nextfile() : " );
	
	if ( m_stCFindex == _NOFILE )	// 1st file in stream, special case
	{
		sprintf( m_szText, "  ...list_nextfile() : #1 = '%s'", 
			m_list[ 0 ].filename );
		printf( "%s", m_szText );
		TextLogMsg( 0, m_szText );
		next_handle = _open( m_list[ 0 ].filename, O_RDONLY|O_BINARY );
		m_stCFhandle = next_handle;
		m_stCFindex = 0; // set file index to 0
	}
	else if ( m_stCFindex < m_dwFileCount )	// not 1st file, handle normally
	{
		old_handle	= _close( m_stCFhandle );
		if ( old_handle == -1 )	// check for error
		{
			sprintf( m_szText, "list_nextfile() : couldn't close current file '%s' !",
				m_list[ m_stCFindex ].filename );
			TextLogErr( _NOFILE, m_szText );
			return _NOFILE;	// error condition
		}

		m_stCFhandle = _NOFILE;
		++m_stCFindex; // increment file index

		next_handle = _open( m_list[ m_stCFindex ].filename, O_RDONLY|O_BINARY );
		if ( next_handle == -1 ) // check for error
		{
			sprintf( m_szText, "list_nextfile() : couldn't open file#%d '%s' !",
				m_stCFindex + 1, m_list[ m_stCFindex ].filename );
			TextLogErr( _NOFILE, m_szText );
			return _NOFILE; // error condition
		}

		sprintf( m_szText, "  ...list_nextfile() : #%d = '%s'\n", 
			m_stCFindex+1, m_list[ m_stCFindex ].filename );
		printf("%s", m_szText );
		TextLogMsg( 0, m_szText );
		m_stCFhandle = next_handle;
	}
	else
		TextLogMsg( 0,"...list_nextfile() : end of the list!" );

	return next_handle;
}
*/