/********************************************************************
 WRAPSTOR.CPP

 Owner: ErinFox

 Created: 28-Feb-1997
 
 Description: This file contains file system calls that are wrapped
              with the InfoTech IStorage implementation

*********************************************************************/


// For IStorage support
#define INITGUID

#include <windows.h>
#include <basetyps.h>
#include <comdef.h>
#include  <MSITStg.h>

// InfoTech includes
#include <mvopsys.h>
#include <_mvutil.h>
#include <wrapstor.h>
#include "iofts.h"

// DOSFILE support
#include <io.h>
#include <fcntl.h>
#include <sys\types.h>
#include <sys\stat.h>



#define RESERVED 0

// I "borrowed" these from Tome code
#define PLI_To_PFO(PLI) ((FILEOFFSET *) PLI)
#define LI_To_FO(LI)    (*PLI_To_PFO(&LI))

#define PFO_To_PLI(PFO) ((LARGE_INTEGER *) PFO)
#define FO_To_LI(FO) (*PFO_To_PLI(&FO))


// was in iofts.c
#ifdef _DEBUG
static char s_aszModule[] = __FILE__;	// Used by error return functions.
#endif

// was in iofts.c
#define OPENED_HFS (BYTE)0x80

// was in iofts.c
PRIVATE HANDLE NEAR PASCAL IoftsWin32Create(LPCSTR lpstr, DWORD w);
PRIVATE HANDLE NEAR PASCAL IoftsWin32Open(LPCSTR lpstr, DWORD w);

// was in iofts.c
#define	CREAT(sz, w) IoftsWin32Create(sz, w)
#define	OPEN(sz, w)	IoftsWin32Open(sz, w)



//
// These functions came from subfile.c
//
PUBLIC HF PASCAL FAR EXPORT_API HfOpenHfs(HFS hfs, LPCWSTR wsz,
    BYTE bFlags, LPERRB lperrb)
{
	HF hf;
	DWORD grfMode;
	HRESULT hr;

	// TODO: find out how big this really should be
//	OLECHAR wsz[_MAX_PATH];
//	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, wsz, _MAX_PATH);


	if (bFlags & HFOPEN_READWRITE)
		grfMode = STGM_READWRITE;
	else if (bFlags & HFOPEN_READ)
		grfMode = STGM_READ;


	if (!(bFlags & HFOPEN_CREATE))
	{
		hr = hfs->OpenStream(wsz, NULL, grfMode, RESERVED, &hf);
	}
	else
	{
	 	hr = hfs->CreateStream(wsz, grfMode, RESERVED, RESERVED, &hf);
	}

    // make sure we pass back a NULL if open/create failed
    if (!SUCCEEDED(hr))
        hf = NULL;

    // sometimes we get passed NULL for lperrb
    if (lperrb)
	    *lperrb = hr;    

	return hf;
}


PUBLIC HF PASCAL FAR EXPORT_API HfCreateFileHfs(HFS hfs, LPCSTR sz,
    BYTE bFlags, LPERRB lperrb)
{
	HF hf;
	DWORD grfMode;
	HRESULT hr;

	// TODO: find out how big this really should be
	OLECHAR wsz[_MAX_PATH];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, wsz, _MAX_PATH);

	
	if (bFlags & HFOPEN_READWRITE)
		grfMode = STGM_READWRITE;
	else if (bFlags & HFOPEN_READ)
		grfMode = STGM_READ;

	hr = hfs->CreateStream(wsz, grfMode, RESERVED, RESERVED, &hf);

    // make sure we pass back NULL if failure
    if (!SUCCEEDED(hr))
        hf = NULL;

    if (lperrb)
	    *lperrb = hr;   

	return hf;
}

// This is currently the same as HfOpenHfs, but once we have Ron's
// enhancements to Tome we will be able to set the size on the file
PUBLIC HF PASCAL FAR EXPORT_API HfOpenHfsReserve(HFS hfs, LPCSTR sz,
    BYTE bFlags, FILEOFFSET foReserve, LPERRB lperrb)
{
	HF hf;
	DWORD grfMode;
	HRESULT hr;

	// TODO: find out how big this really should be
	OLECHAR wsz[_MAX_PATH];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, wsz, _MAX_PATH);

	if (bFlags & HFOPEN_READWRITE)
		grfMode = STGM_READWRITE;
	else if (bFlags & HFOPEN_READ)
		grfMode = STGM_READ;

	if (!(bFlags & HFOPEN_CREATE))
	{
		hr = hfs->OpenStream(wsz, NULL, grfMode, RESERVED, &hf);
	}
	else
	{
	 	hr = hfs->CreateStream(wsz, grfMode, RESERVED, RESERVED, &hf);
	}

    if (!SUCCEEDED(hr))
        hf = NULL;

	if (lperrb)
        *lperrb = hr;
    
    return hf;
}

PUBLIC LONG PASCAL FAR EXPORT_API LcbReadHf(HF hf, LPVOID lpvBuffer,
	LONG lcb, LPERRB lperrb)
{
	ULONG cbRead;
	HRESULT hr;

	hr = hf->Read(lpvBuffer, lcb, &cbRead);

    if (lperrb)
	    *lperrb = hr;
	
	return cbRead;
}

PUBLIC LONG PASCAL FAR EXPORT_API LcbWriteHf(HF hf, LPVOID lpvBuffer,
	LONG lcb, LPERRB lperrb)
{
	ULONG cbWrote;
	HRESULT hr;

	hr = hf->Write(lpvBuffer, lcb, &cbWrote);

    if (lperrb)
	    *lperrb = hr;  

	return cbWrote;
}


PUBLIC FILEOFFSET PASCAL FAR EXPORT_API FoSeekHf(HF hf, FILEOFFSET foOffset, 
	WORD wOrigin, LPERRB lperrb)
{

	HRESULT hr;
	ULARGE_INTEGER liNewPos;
	LARGE_INTEGER liOffset = FO_To_LI(foOffset);

	hr = hf->Seek(liOffset, (DWORD)wOrigin, &liNewPos);

    if (lperrb)
	    *lperrb = hr;

	return LI_To_FO(liNewPos);


}

PUBLIC RC PASCAL FAR EXPORT_API RcCloseHf(HF hf)
{
	if (hf)
		hf->Release();
	
	return S_OK;
}


PUBLIC BOOL PASCAL FAR EXPORT_API FAccessHfs( HFS hfs, LPCSTR szName, BYTE bFlags, LPERRB lperrb)
{
	HRESULT hr;
	HF hf = NULL;
	BOOL fRet = FALSE;

    if (lperrb)
	    *lperrb = S_OK;          // for now

	// TODO: find out how big this really should be
	OLECHAR wszName[_MAX_PATH];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, szName, -1, wszName, _MAX_PATH);

	hr = hfs->OpenStream(wszName, NULL, STGM_READWRITE, RESERVED, &hf);

	if (S_OK == hr)
	{
		if (bFlags & FACCESS_EXISTS)
			fRet = TRUE;

	}
	else if (STG_E_FILENOTFOUND == hr)
	{
		SetErrCode (lperrb, E_FILENOTFOUND);
	}
 // else
 // {
 //		Need to set error if anything but NOTFOUND
 // }
	
	if (hf)
		hf->Release();

	return fRet;
}


PUBLIC FILEOFFSET PASCAL FAR EXPORT_API FoSizeHf(HF hf, LPERRB lperrb)
{
	STATSTG stat;
	HRESULT hr;
    FILEOFFSET foSize;

	hr = hf->Stat(&stat, STATFLAG_NONAME);

    if (S_OK == hr)
        foSize = LI_To_FO(stat.cbSize);
    else
        foSize = foNil;

    if (lperrb)
        *lperrb = hr;

    
    return foSize;
}


///////////////////////////////////////////////////////////////////
//  These functions came from iofts.c
///////////////////////////////////////////////////////////////////

PUBLIC HFPB FAR PASCAL FileCreate (HFPB hfpbSysFile, LPCSTR lszFilename,
	int fFileType, LPERRB lperrb)
{
	LPFPB lpfpb;	/* Pointer to file parameter block */
	HANDLE hMem;
	HFPB hfpb;
	HRESULT hr;
	OLECHAR wszFileName[_MAX_PATH];
	FM fm;
	HFS hfs;

	/* Check for valid filename */
	if (lszFilename == NULL )
	{
		SetErrCode (lperrb, E_INVALIDARG);
		return 0;
	}

	/* Allocate a file's parameter block */
	if (!(hMem = _GLOBALALLOC(GMEM_ZEROINIT, sizeof(FPB))))
	{	
		SetErrCode(lperrb, E_OUTOFMEMORY);
		return NULL;
	}

	if (!(lpfpb = (LPFPB)_GLOBALLOCK(hMem)))
	{
	 	_GLOBALUNLOCK(hMem);
		SetErrCode(lperrb,E_OUTOFMEMORY);
		return NULL;
	}

	_INITIALIZECRITICALSECTION(&lpfpb->cs);
	lpfpb->hStruct = hMem;

	switch (fFileType)
	{
		case FS_SYSTEMFILE:

			IClassFactory* pCF;
			
			hr = CoGetClassObject(CLSID_ITStorage, CLSCTX_INPROC_SERVER, NULL, 
                                  IID_IClassFactory, (VOID **)&pCF);

			// Error check!

			IITStorage* pITStorage;
			hr = pCF->CreateInstance(NULL, IID_ITStorage, 
                                      (VOID **)&pITStorage);
			if (pCF)
				pCF->Release();

			fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL);
			MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, fm, -1, wszFileName, _MAX_PATH);

			hr = pITStorage->StgCreateDocfile(wszFileName, STGM_READWRITE, RESERVED, &hfs);

            // if call failed, make sure to set hfs NULL
            if (!SUCCEEDED(hr))
            {
                hfs = NULL;
                SetErrCode(lperrb, hr);
            }

			lpfpb->fs.hfs = hfs;


			if (pITStorage)
				pITStorage->Release();

			DisposeFm(fm);

			break;


		case FS_SUBFILE:
			hfs = GetHfs(hfpbSysFile,lszFilename,TRUE,lperrb);
			if (hfs)
			{
				lpfpb->fs.hf = HfCreateFileHfs(hfs,GetSubFilename(lszFilename,
					NULL),HFOPEN_READWRITE,lperrb);

				lpfpb->ioMode = OF_READWRITE;
				
				if (lpfpb->fs.hf == NULL)
				{
					if (!hfpbSysFile)
					 	RcCloseHfs(hfs);				
					goto ErrorExit;
				}
				else
				{
				 	if (!hfpbSysFile)
						lpfpb->ioMode |= OPENED_HFS;
				}
			}
			else
			{
			 	goto ErrorExit;
			}
			break;

		case REGULAR_FILE:
			// Create the file 
			if ((lpfpb->fs.hFile = (HFILE_GENERIC)CREAT (lszFilename, 0))
			    == HFILE_GENERIC_ERROR)
			{
				SetErrCode(lperrb,E_FILECREATE);
				goto ErrorExit;
			}
			lpfpb->ioMode = OF_READWRITE;
			break;
	}

	// Set the filetype 
	lpfpb->fFileType = (BYTE) fFileType;

	_GLOBALUNLOCK(hfpb = lpfpb->hStruct);
	return hfpb;

ErrorExit:
	_DELETECRITICALSECTION(&lpfpb->cs);
	_GLOBALFREE(hMem);
	return 0;
}




PUBLIC HFPB FAR PASCAL FileOpen (HFPB hfpbSysFile, LPCSTR lszFilename,
	int fFileType, int ioMode, LPERRB lperrb)
{
	LPFPB lpfpb;	/* Pointer to file parameter block */
	HANDLE hMem;
	HFPB hfpb;
	FM fm;
	OLECHAR wszFileName[_MAX_PATH];
	HFS hfs;

	HRESULT hr;

	/* Check for valid filename */
	if (lszFilename == NULL )
	{
		SetErrCode (lperrb, E_INVALIDARG);
		return 0;
	}

	/* Allocate a file's parameter block */
	if (!(hMem = _GLOBALALLOC(GMEM_ZEROINIT, sizeof(FPB))))
	{	
		SetErrCode(lperrb,E_OUTOFMEMORY);
		return NULL;
	}

	if (!(lpfpb = (LPFPB)_GLOBALLOCK(hMem)))
	{
	 	_GLOBALUNLOCK(hMem);
		SetErrCode(lperrb,E_OUTOFMEMORY);
		return NULL;
	}

	_INITIALIZECRITICALSECTION(&lpfpb->cs);
	lpfpb->hStruct = hMem;

	switch (fFileType)
	{
		case FS_SYSTEMFILE:

			IClassFactory* pCF;
			
			hr = CoGetClassObject(CLSID_ITStorage, CLSCTX_INPROC_SERVER, NULL, 
                                  IID_IClassFactory, (VOID **)&pCF);

			// Error check!

			IITStorage* pITStorage;
			hr = pCF->CreateInstance(NULL, IID_ITStorage, 
                                      (VOID **)&pITStorage);
			if (pCF)
				pCF->Release();


			fm = FmNewSzDir((LPSTR)lszFilename, dirCurrent, NULL);
			MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, fm, -1, wszFileName, _MAX_PATH);

			hr = pITStorage->StgOpenStorage(wszFileName, NULL, (ioMode==READ) ? STGM_READ:STGM_READWRITE, 
			                                NULL, RESERVED, &hfs);

            if (!SUCCEEDED(hr))
            {
                hfs = NULL;
                SetErrCode(lperrb, hr);
            }

			lpfpb->fs.hfs = hfs;

			if (pITStorage)
				pITStorage->Release();

			DisposeFm(fm);

			break;

		case FS_SUBFILE:
			hfs = GetHfs(hfpbSysFile,lszFilename,FALSE,lperrb);
			if (hfs)
			{	
            	OLECHAR wsz[_MAX_PATH];
                LPCSTR sz = GetSubFilename(lszFilename, NULL);
            	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sz, -1, wsz, _MAX_PATH);
				lpfpb->fs.hf = HfOpenHfs(hfs, wsz,
                                (BYTE)((ioMode==READ)?HFOPEN_READ:HFOPEN_READWRITE),lperrb);

				lpfpb->ioMode = (BYTE) ioMode;
				
				if (lpfpb->fs.hf == 0)
				{
					if (!hfpbSysFile)
					 	RcCloseHfs(hfs);
					SetErrCode (lperrb, E_NOTEXIST);				
					goto ErrorExit;
				}
				else
				{
				 	if (!hfpbSysFile)
						lpfpb->ioMode|=OPENED_HFS;
				}
			}
			else
			{
				SetErrCode (lperrb, E_NOTEXIST);				
			 	goto ErrorExit;
			}
			break;

		case REGULAR_FILE:
			/* Set the IO mode and appropriate error messages */
			if (ioMode == READ)
			{
				/* Open the file */
				if ((lpfpb->fs.hFile = (HFILE_GENERIC)OPEN (lszFilename,
				    ioMode)) == HFILE_GENERIC_ERROR) 
				{
					SetErrCode(lperrb,E_NOTEXIST);
					goto ErrorExit;
				}

			}
			else
			{
				ioMode = OF_READWRITE;
				/* Open the file */
				if ((lpfpb->fs.hFile = (HFILE_GENERIC)OPEN(lszFilename, ioMode))
				    == HFILE_GENERIC_ERROR)
				{
					SetErrCode(lperrb,E_FILECREATE);
					goto ErrorExit;
				}
			}
			lpfpb->ioMode = (BYTE) ioMode;
			break;

	}

	// set filetype
	lpfpb->fFileType = (BYTE) fFileType;

	_GLOBALUNLOCK(hfpb = lpfpb->hStruct);
	return hfpb;

ErrorExit:
	_DELETECRITICALSECTION(&lpfpb->cs);
	_GLOBALFREE(hMem);
	return 0;

}

PUBLIC RC FAR PASCAL FileClose(HFPB hfpb)
{
	RC rc;
	LPFPB	lpfpb;


	if (hfpb == NULL)
		return E_HANDLE;

	lpfpb = (LPFPB)_GLOBALLOCK(hfpb);
	_ENTERCRITICALSECTION(&lpfpb->cs);

	rc = S_OK;
	switch (lpfpb->fFileType)
	{
		case FS_SYSTEMFILE:
            if (lpfpb->fs.hfs)
			    lpfpb->fs.hfs->Release();
			break;

		case FS_SUBFILE:
            if (lpfpb->fs.hf)
                lpfpb->fs.hf->Release();
			break;

		case REGULAR_FILE:
			if (lpfpb->fs.hFile)
				rc = (!CloseHandle(lpfpb->fs.hFile))?E_FILECLOSE:S_OK;
			break;
	}

	/* Free the file parameter block structure */
	_LEAVECRITICALSECTION(&lpfpb->cs);
	_DELETECRITICALSECTION(&lpfpb->cs);

    _GLOBALUNLOCK(hfpb);
	_GLOBALFREE(hfpb);

	return rc;
}


// These are verbatim from iofts.c. I put them here so we can compile
PRIVATE HANDLE NEAR PASCAL IoftsWin32Create(LPCSTR lpstr, DWORD w)
{
	SECURITY_ATTRIBUTES sa;
	HANDLE hfile;

	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = 0;

	hfile= CreateFile(lpstr, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
		&sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	return hfile;
}

PRIVATE HANDLE NEAR PASCAL IoftsWin32Open(LPCSTR lpstr, DWORD w)
{
	SECURITY_ATTRIBUTES sa;

	sa.nLength = sizeof(SECURITY_ATTRIBUTES);
	sa.lpSecurityDescriptor = NULL;
	sa.bInheritHandle = 0;

	return CreateFile(lpstr, (w == READ) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE, 
                      FILE_SHARE_READ, &sa,OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}

#if 0
// This is new functionality
PUBLIC FM EXPORT_API FAR PASCAL FmFromHfs(HFS hfs)
{
	char szStoreName[_MAX_PATH];
	FM fm;
	ERRB errb;

	STATSTG StoreStat;
	HRESULT hr;

	// get storage name 
	// Turns out this isn't IMPLEMENTED yet!
	hr = hfs->Stat(&StoreStat, STATFLAG_DEFAULT);
	if (S_OK == hr)
	{
		// and convert it since FMs aren't Unicode
		WideCharToMultiByte(CP_ACP, 0, StoreStat.pwcsName, -1,
							szStoreName, _MAX_PATH, NULL, NULL);

		// free memory associated with pwcsName
		CoTaskMemFree(StoreStat.pwcsName);

		// create new FM
		fm = FmNew(szStoreName, &errb);
	}
	else
		fm = NULL;

	return fm;
}
#endif