/*
++	File name: File.h
++	File comments: This class is used for file handling.
		You may copy, reproduce and redistribute this code
		with the condition that you include this copyright
		notice and don't recieve payment in any kind for this
		code in original or modified form.
++	Copyright (c) 2002, Jesper Öqvist
*/

//created: 2002-0?-??
//last updated: 2002-11-05

#ifndef _JSH_FILE_H
#define _JSH_FILE_H

//includes:
#include <windows.h>

//Use these macros to specify what kind of access you need
#define FILE_ROM	GENERIC_READ
#define FILE_WOM	GENERIC_WRITE
#define FILE_RW		(GENERIC_READ | GENERIC_WRITE)

//Use these macros to specify how the file will be created/opened
#define FILE_CREATE_NEW		CREATE_NEW
#define FILE_CREATE_ALWAYS	CREATE_ALWAYS
#define FILE_OPEN_EXISTING	OPEN_EXISTING
#define FILE_OPEN_ALWAYS	OPEN_ALWAYS

//Various file attributes.
#define FILE_ATTRB_NORMAL		FILE_ATTRIBUTE_NORMAL
#define FILE_ATTRB_HIDDEN		FILE_ATTRIBUTE_HIDDEN
#define FILE_ATTRB_ROM			FILE_ATTRIBUTE_READONLY
//FILE_ATTRIBUTE_NORMAL
//FILE_ATTRIBUTE_HIDDEN
//FILE_ATTRIBUTE_READONLY

//These are used to specify if other programs will be able
// to access the file at the same time as you are.
//FILE_SHARE_READ
//FILE_SHARE_WRITE
#define FILE_SHARE_RNW		(FILE_SHARE_READ | FILE_SHARE_WRITE)

//These are used when moving the file pointer.
//FILE_CURRENT
//FILE_BEGIN
//FILE_BEGIN
//FILE_END

class cFile
{
public:
	DWORD	m_rw;

private:
	HANDLE	m_fh;
	char*	m_fname;
	bool	m_write;
	bool	m_read;

public:
	cFile() {m_fh = m_fname = NULL;m_write = m_read = false;}
	cFile(cFile& of){
			DuplicateHandle(
				GetCurrentProcess(), of.m_fh, GetCurrentProcess(),
				&m_fh, 0, false, DUPLICATE_SAME_ACCESS);
			m_write = of.m_write;m_read = of.m_read;};
	~cFile() {if (m_fh) CloseHandle(m_fh);}

	bool OpenRW(char* filename){
		return Open(filename, FILE_RW, 0, FILE_OPEN_ALWAYS);}

	bool OpenROM(char* filename){
		return Open(filename, FILE_ROM, FILE_SHARE_READ,
			FILE_OPEN_EXISTING);}

	bool OpenWOM(char* filename){
		return Open(filename, FILE_WOM, 0, FILE_CREATE_ALWAYS);}

	bool Open(char* filename, DWORD access, DWORD sharemode,
		DWORD openmode, DWORD attributes = 0)
	{
		if (m_fh)
			return false;
		m_fname = filename;
		m_fh = CreateFile(m_fname, access, sharemode, NULL, openmode,
			attributes,NULL);
		if (m_fh == INVALID_HANDLE_VALUE)
			return false;
		if (access & FILE_RW)
		{
			m_write = m_read = true;
		}
		else if (access & FILE_ROM)
		{
			m_read = true;
			m_write = false;
		}
		else
		{
			m_read = false;
			m_write = true;
		}
		return true;
	}

	template <class T>
		bool Write(T& data) {return Write(&data, sizeof(data));}
	bool Write(const void* data, DWORD len, DWORD* bwritten = NULL)
	{
		if (m_fh && m_write)
		{
			if (bwritten)
			{
				if (!WriteFile(m_fh, data, len, bwritten, NULL))
					return false;
			}
			else
			{
				if (!WriteFile(m_fh, data, len, &m_rw, NULL))
					return false;
			}
			return true;
		}
		return false;
	}

	template <class T>
		bool Read(T& data) {return Read(&data, sizeof(data));}
	bool Read(void* data, DWORD len, DWORD* bread = NULL)
	{
		if (m_fh && m_read)
		{
			if (bread)
			{
				if (!ReadFile(m_fh, data, len, bread, NULL))
					return false;
			}
			else
			{
				if (!ReadFile(m_fh, data, len, &m_rw, NULL))
					return false;
			}
			return true;
		}
		return false;
	}

	void Close() {if (m_fh) CloseHandle(m_fh);m_fh = NULL;}

	HANDLE GetHandle() {return m_fh;}
	HANDLE Handle() {return m_fh;}
	void SetHandle(HANDLE handle) {m_fh = handle;}
	void Handle(HANDLE handle) {m_fh = handle;}
	DWORD SetPointer(DWORD moveto, DWORD movemethod){
		return SetFilePointer(m_fh, moveto, NULL, movemethod);}
	DWORD Pointer(DWORD moveto, DWORD movemethod){
		return SetFilePointer(m_fh, moveto, NULL, movemethod);}
	DWORD GetPointer(){
		return SetFilePointer(m_fh, 0, NULL, FILE_CURRENT);}
	DWORD Pointer(){
		return SetFilePointer(m_fh, 0, NULL, FILE_CURRENT);}
	DWORD GetSize() {return GetFileSize(m_fh, NULL);}
	DWORD Size() {return GetFileSize(m_fh, NULL);}

	cFile& operator=(const cFile& of){
			DuplicateHandle(
				GetCurrentProcess(), of.m_fh, GetCurrentProcess(),
				&m_fh, 0, false, DUPLICATE_SAME_ACCESS);
			m_write = of.m_write;m_read = of.m_read;
			return *this;};

			bool IsOpen() {return (m_fh == INVALID_HANDLE_VALUE) ? false : true;}
};

#endif	//_JSH_FILE_H