Add OP2Editor project for the map editor backend (DLL).

git-svn-id: https://svn.outpostuniverse.org:8443/svn/outpost2@1051 7b3b2116-5498-11dd-abe4-fb2d8bf8a5a8
master
Hooman 2016-01-23 13:51:58 +00:00
parent 0124737576
commit 96c4c93763
47 changed files with 21804 additions and 0 deletions

View File

@ -0,0 +1,343 @@
#include "stdafx.h"
#include "CClmReader.h"
#include "CMemoryStreamReader.h"
#include "GlobalFunctions.h"
extern int g_cLocks;
const char CClmReader::tagClmFile[] = "OP2 Clump File Version 1.0\x01A";
ULONG __stdcall CClmReader::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CClmReader::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CClmReader::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_ArchiveReader)
*ppv = (ArchiveReader*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// ArchiveReader
// *************
HRESULT CClmReader::get_NumFiles(int *numFiles)
{
*numFiles = this->numFiles;
return S_OK;
}
HRESULT CClmReader::get_FileName(int index, BSTR *fileName)
{
int stringLength;
// Cache string length
for (stringLength = 0; stringLength < 8; stringLength++)
if (indexTable[index].fileName[stringLength] == NULL) break;
// Allocate space for the string
SysReAllocStringLen(fileName, NULL, stringLength);
// Convert the string to Unicode
MultiByteToWideChar(CP_ACP, 0, indexTable[index].fileName,
stringLength, *fileName, stringLength);
return S_OK;
}
HRESULT CClmReader::OpenStreamRead(BSTR fileName, StreamReader **stream)
{
int fileIndex;
int numBytesRead;
CMemoryStreamReader *memStream;
HRESULT hr;
LPVOID buffer;
int bAttachToBuffer = 0;
// Initialize returned stream pointer to NULL
*stream = NULL;
// Lookup the filename in the index
fileIndex = GetFileIndex(fileName);
// Check if the file was not found
if (fileIndex == -1)
{
// File was not found
return E_INVALIDARG;
}
// Cache the data buffer pointer
buffer = dataBuffer[fileIndex];
// Check if data hasn't been loaded yet
if (buffer == NULL)
{
// Load the data from the stream
// Allocate a buffer for this file
buffer = new char[indexTable[fileIndex].size];
// Seek to the start of the file
attachedStream->Seek(streamStartOffset + indexTable[fileIndex].offset);
// Read in the file data
attachedStream->Read(indexTable[fileIndex].size, (int)dataBuffer[fileIndex], &numBytesRead);
bAttachToBuffer = 1;
}
// Create a stream to read the data
try
{
// **TODO** Create a new reader class that will load data
// from the origianl CLM file. Would make rebuilding the
// CLM file much less memory intensive.
// Create a memory stream reading with the file contents
memStream = new CMemoryStreamReader(indexTable[fileIndex].size,
(char*)(dataBuffer[fileIndex]),
bAttachToBuffer);
if (memStream == NULL)
{
// Check if buffer is discardable
if (bAttachToBuffer == 1)
delete [] buffer;
// Return error code
return E_OUTOFMEMORY;
}
}
catch(...)
{
// Check if buffer is discardable
if (bAttachToBuffer == 1)
delete [] buffer;
// Return error code
return E_FAIL;
}
hr = memStream->QueryInterface(IID_StreamReader, (void**)stream);
memStream->Release();
return hr;
}
// Class specific
// **************
CClmReader::CClmReader(SeekableStreamReader *inStream, int bAttachToStream) : m_cRef(1)
{
// Initialize variables
numFiles = 0;
indexTable = NULL;
dataBuffer = NULL;
attachedStream = NULL;
// Check if reader should attach to the stream
if (bAttachToStream == 1)
{
attachedStream = inStream;
inStream->AddRef();
}
// Load the Clm info from the stream
if (LoadClm(inStream, bAttachToStream) != 0)
{
// Error loading Clm info
FreeMemory();
throw L"Error loading CLM info.";
}
g_cLocks++;
}
CClmReader::~CClmReader()
{
g_cLocks--;
FreeMemory();
// Check if reader attached to a stream
if (attachedStream != NULL)
attachedStream->Release();
}
void CClmReader::FreeMemory()
{
unsigned int i;
// Check if the index table needs to be deleted
if (indexTable != NULL)
delete [] indexTable; // Delete the index table
// Check if the array of data buffer pointers needs to be deleted
if (dataBuffer != NULL)
{
// Release each data buffer
for (i = 0; i < numFiles; i++)
{
// Check if the data buffer exists
if (dataBuffer[i] != NULL)
delete [] dataBuffer[i]; // Delete the data buffer
}
// Delete the array of data buffer pointers
delete [] dataBuffer;
}
// Reset variables
indexTable = NULL;
dataBuffer = NULL;
numFiles = 0;
}
int CClmReader::GetFileIndex(BSTR fileName)
{
int stringLength;
char *tempString;
unsigned int i;
// Allocate space for a temporary ASCII fileName string
stringLength = SysStringLen(fileName);
tempString = new char[stringLength+1];
tempString[stringLength] = 0; // NULL terminate it
// Convert the BSTR to ASCII
WideCharToMultiByte(CP_ACP, 0, fileName, stringLength, tempString, stringLength, 0, 0);
// **TODO** Improve this to a binary search? Or is that not general enough
// Outpost2 doesn't seem to require a sorted index
// Perform a linear search of the index
for (i = 0; i < numFiles; i++)
{
// Check if fileName matches this index entry
if (strncmp(indexTable[i].fileName, tempString, 8) == 0)
{
// File names match. Return index
delete [] tempString;
return i;
}
}
delete [] tempString;
return -1; // File not found
}
int CClmReader::LoadClm(SeekableStreamReader *inStream, int bAttachToStream)
{
char buff[32];
int numBytesRead;
unsigned int i, j, maxOffset;
try
{
// Record the starting stream position for later seeking
// (Note: This allows CLM contents to be part of a larger stream)
inStream->get_ReadOffset(&streamStartOffset);
// Read header tag
inStream->Read(32, (int)buff, &numBytesRead);
// Check if header tag is invalid
if (strncmp(buff, tagClmFile, 32) != 0)
throw L"Format Error. Invalid Clump file header tag.";
// Read WAVEFORMATEX structure
inStream->Read(sizeof(waveFormat), (int)&waveFormat, &numBytesRead);
// Check for format errors
if (waveFormat.wFormatTag != WAVE_FORMAT_PCM)
throw L"Format Error. Wave format is not encoded as WAVE_FORMAT_PCM.";
if (waveFormat.nChannels != 1)
throw L"Format Error. Wave format is not mono channel.";
if (waveFormat.nBlockAlign != 2)
throw L"Format Error. Wave format is not block aligned on a 2 byte boundary.";
if (waveFormat.nSamplesPerSec != 22050)
throw L"Format Error. Wave format is not 22050 samples per second.";
// Pass over alignment bytes
inStream->Read(2, (int)buff, &numBytesRead);
// Read ??? **TODO** Find out what this DWORD means
inStream->Read(4, (int)&unknown, &numBytesRead);
// Read numFiles stored in CLM
inStream->Read(4, (int)&numFiles, &numBytesRead);
// Allocate space for CLM index table
indexTable = new IndexEntry[numFiles];
// Read CLM index table
inStream->Read(numFiles*sizeof(IndexEntry), (int)indexTable, &numBytesRead);
// Allocate space to hold all the file buffer pointers
dataBuffer = new LPVOID[numFiles];
memset(dataBuffer, 0, numFiles*sizeof(LPVOID));
// Check if data needs to be loaded into memory
if (bAttachToStream == 0)
{
// Data must be loaded into memory
// Load each internal file
for (i = 0; i < numFiles; i++)
{
// Allocate a buffer for this file
dataBuffer[i] = new char[indexTable[i].size];
// Seek to the start of the file
inStream->Seek(streamStartOffset + indexTable[i].offset);
// Read in the file data
inStream->Read(indexTable[i].size, (int)dataBuffer[i], &numBytesRead);
}
}
// Determine maximum offset of CLM data
maxOffset = 0;
j = 0;
for (i = 0; i < numFiles; i++)
{
j = indexTable[i].offset + indexTable[i].size;
if (j > maxOffset)
maxOffset = j;
}
if (maxOffset < 0x3C + numFiles*sizeof(IndexEntry) + 1)
maxOffset = 0x3C + numFiles*sizeof(IndexEntry) + 1;
// Seek to end of CLM data
inStream->Seek(streamStartOffset + maxOffset);
}
catch(WCHAR *errorMsg)
{
// Return a COM error message
PostErrorMsg(errorMsg);
return 1; // Failed to load file
}
catch(...)
{
// Error loading Clm data
return -1; // Failed to load file
}
return 0; // Success
}

View File

@ -0,0 +1,60 @@
#include "OP2Editor.h"
class CClmReader : public ArchiveReader
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// ArchiveReader
// *************
// [propget]
HRESULT STDMETHODCALLTYPE get_NumFiles(
/* [retval][out] */ int __RPC_FAR *numFiles);
// [propget]
HRESULT STDMETHODCALLTYPE get_FileName(
/* [in] */ int index,
/* [retval][out] */ BSTR __RPC_FAR *fileName);
HRESULT STDMETHODCALLTYPE OpenStreamRead(
/* [in] */ BSTR filename,
/* [retval][out] */ StreamReader __RPC_FAR *__RPC_FAR *stream);
// Class specific
// **************
CClmReader(SeekableStreamReader *inStream, int bAttachToStream);
~CClmReader();
private:
ULONG m_cRef;
// Private constant used for Clm loading/saving
static const char tagClmFile[];
void FreeMemory();
int LoadClm(SeekableStreamReader *inStream, int bAttachToStream);
int GetFileIndex(BSTR fileName);
struct IndexEntry
{
char fileName[8];
int offset;
int size;
};
WAVEFORMATEX waveFormat; // Format of all stored sound data
int unknown; // Unknown **TODO** Find out meaning
unsigned int numFiles; // Number of wave files stored in the clump file
IndexEntry *indexTable; // Array of all index entries
LPVOID *dataBuffer; // Array of pointers to data buffers
int streamStartOffset; // Start offset of clm data in stream
SeekableStreamReader *attachedStream; // Clm data input stream
};

View File

@ -0,0 +1,299 @@
#include "stdafx.h"
#include "CClmWriter.h"
extern int g_cLocks;
const char CClmWriter::tagClmFile[32] = "OP2 Clump File Version 1.0\x01A";
ULONG __stdcall CClmWriter::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CClmWriter::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CClmWriter::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_ArchiveWriter)
*ppv = (ArchiveWriter*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// ArchiveWriter
// *************
HRESULT CClmWriter::AddToArchive(BSTR fileName, SeekableStreamReader *inStream, int reserved)
{
LinkedListNode *newNode;
int stringLength;
// Check for invalid parameters
if (reserved != 0)
return E_INVALIDARG;
if (inStream == NULL)
return E_INVALIDARG;
stringLength = SysStringLen(fileName); // Cache the string length
if (stringLength > 8)
return E_INVALIDARG;
// Create a new linked list node to hold the data
newNode = new LinkedListNode;
memset(newNode->indexEntry.fileName, 0, 8); // NULL pad the string/initialize
// Convert the filename from UNICODE to ASCII
WideCharToMultiByte(CP_ACP, 0, fileName, stringLength, newNode->indexEntry.fileName, stringLength, 0, 0);
// Store the stream pointer
newNode->inStream = inStream;
inStream->AddRef();
// Store the starting stream offset and data size
inStream->get_ReadOffset(&newNode->streamStartOffset);
inStream->get_StreamSize(&newNode->indexEntry.dataSize);
newNode->indexEntry.dataSize -= newNode->streamStartOffset; // Adjust for start of data
// Store the new node to the linked list
newNode->next = head;
head = newNode;
numNodes++;
// Update max data size
if (newNode->indexEntry.dataSize > maxDataSize)
maxDataSize = newNode->indexEntry.dataSize;
return S_OK;
}
HRESULT CClmWriter::WriteArchive(StreamWriter *outStream)
{
WAVEFORMATEX waveFormat;
int temp = 0; // Used for NULL padding
int offset;
int numBytesWritten;
LinkedListNode *current;
char *buffer = NULL;
// Sort the index
head = SortIndex(head);
// Prepare WAVEFORMATEX structure
// ******************************
waveFormat.cbSize = sizeof(WAVEFORMATEX);
waveFormat.wFormatTag = WAVE_FORMAT_PCM;
waveFormat.nChannels = 1;
waveFormat.nSamplesPerSec = 22050;
waveFormat.nAvgBytesPerSec = 44100;
waveFormat.nBlockAlign = 2;
waveFormat.wBitsPerSample = 16;
// Create a write buffer
buffer = new char[maxDataSize];
if (buffer == NULL)
return E_OUTOFMEMORY;
// Begin writing the CLM file contents
// ***********************************
// Write out the header
// ********************
// Write the header tag
outStream->Write(32, (int)tagClmFile, &numBytesWritten);
// Write the WAVEFORMATEX structure
outStream->Write(sizeof(WAVEFORMATEX), (int)&waveFormat, &numBytesWritten);
// Pad with NULL bytes
outStream->Write(2, (int)&temp, &numBytesWritten);
// Write unknown DWORD **TODO** Find out what this DWORD means
outStream->Write(4, (int)&unknown, &numBytesWritten);
// Write out the number of files stored in archive
outStream->Write(4, (int)&numNodes, &numBytesWritten);
// Write out the index table
// *************************
// Calculate the starting data offset
offset = 32 + sizeof(WAVEFORMATEX) + 2 + 4 + 4 + numNodes*sizeof(IndexEntry);
current = head;
while (current)
{
// Store the offset to the data
current->indexEntry.dataOffset = offset;
// Update the current data offset
offset += (current->indexEntry.dataSize + 3) & ~3;
// Write out the index entry
outStream->Write(sizeof(IndexEntry), (int)&current->indexEntry, &numBytesWritten);
// Process next node
current = current->next;
}
// Write out the file data
// ***********************
current = head;
while (current)
{
// Seek to the start of the file data
current->inStream->Seek(current->streamStartOffset);
// Read in the file data
current->inStream->Read(current->indexEntry.dataSize, (int)buffer, &numBytesWritten);
// Write out the file data
outStream->Write(current->indexEntry.dataSize, (int)buffer, &numBytesWritten);
// Pad with NULL bytes
outStream->Write(-current->indexEntry.dataSize & 3, (int)&temp, &numBytesWritten);
// Proccess next node
current = current->next;
}
// Release the write buffer
delete [] buffer;
return S_OK;
}
// Class specific
// **************
CClmWriter::CClmWriter() : m_cRef(1)
{
// Initialize variables
head = NULL;
numNodes = 0;
unknown = 65536;
maxDataSize = 0;
g_cLocks++;
}
CClmWriter::~CClmWriter()
{
LinkedListNode *current, *next;
// Delete the linked list
current = head;
while (current)
{
next = current->next; // Read the pointer to the next node
current->inStream->Release(); // Release the input stream for this node
delete current; // Release this node
current = next; // Process next node
}
g_cLocks--;
}
// Performs a Merge Sort on the linked list
CClmWriter::LinkedListNode* CClmWriter::SortIndex(LinkedListNode *list)
{
struct Tape
{
LinkedListNode *head;
LinkedListNode *tail;
int count;
};
Tape tape[4];
LinkedListNode *current, *next;
int destTape, sourceTape;
int blockSize;
int blockCount[2];
// Initialize tapes
tape[0].head = NULL;
tape[0].tail = NULL;
tape[0].count = 0;
tape[1].head = NULL;
tape[1].tail = NULL;
tape[1].count = 0;
// Break list into two
destTape = 0;
for (current = list; current != NULL; destTape ^= 1)
{
// Cache the next node in the list
next = current->next;
// Add the node to the tape
if (tape[destTape].head == NULL)
tape[destTape].head = current;
else
tape[destTape].tail->next = current;
tape[destTape].tail = current;
tape[destTape].count++;
// Process next node
current = next;
}
// Note: The tail nodes will have invalid next pointers at this point
// Merge tapes using successively larger blocks in sorted order and split output
for (blockSize = 1; tape[1].count != 0; blockSize <<= 1)
{
// Initialize new tapes
tape[2].head = NULL;
tape[2].tail = NULL;
tape[2].count = 0;
tape[3].head = NULL;
tape[3].tail = NULL;
tape[3].count = 0;
// Merge all blocks on two tapes and split the output
for (destTape = 2; (tape[0].count != 0) || (tape[1].count != 0); destTape ^= 1)
{
// Merge a block from each tape
blockCount[0] = blockCount[1] = blockSize;
if (blockCount[0] > tape[0].count)
blockCount[0] = tape[0].count;
if (blockCount[1] > tape[1].count)
blockCount[1] = tape[1].count;
for ( ; blockCount[0] | blockCount[1]; )
{
// Check for empty tapes
if (blockCount[0] == 0)
sourceTape = 1; // Node must come from tape[1]
else if (blockCount[1] == 0)
sourceTape = 0; // Node must come from tape[0]
// Check for proper sorted order
else if (strcmp(tape[0].head->indexEntry.fileName, tape[1].head->indexEntry.fileName) < 0)
sourceTape = 0; // Node on tape[0] comes before
else
sourceTape = 1; // Node on tape[1] comes before
// Move the node from the source tape to the dest tape
// Extract the node from the source tape
blockCount[sourceTape]--;
next = tape[sourceTape].head;
tape[sourceTape].head = tape[sourceTape].head->next;
tape[sourceTape].count--;
// Add the node to the dest tape
if (tape[destTape].tail == NULL)
tape[destTape].head = next;
else
tape[destTape].tail->next = next;
tape[destTape].tail = next;
next->next = NULL;
tape[destTape].count++;
}
}
// Swap tapes for next round
tape[0] = tape[2];
tape[1] = tape[3];
}
// Return the first element of the sorted list
return tape[0].head;
}

View File

@ -0,0 +1,63 @@
#include "OP2Editor.h"
class CClmWriter : public ArchiveWriter
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// ArchiveWriter
// *************
HRESULT STDMETHODCALLTYPE AddToArchive(
/* [in] */ BSTR fileName,
/* [in] */ SeekableStreamReader __RPC_FAR *inStream,
/* [in] */ int reserved);
HRESULT STDMETHODCALLTYPE WriteArchive(
/* [in] */ StreamWriter __RPC_FAR *outStream);
// Class specific
// **************
CClmWriter();
~CClmWriter();
private:
ULONG m_cRef;
// Private constant used for Clm loading/saving
static const char tagClmFile[32];
#pragma pack(push, 1)
struct IndexEntry
{
char fileName[8]; // Internal archive filename
int dataOffset; // Offset to data
int dataSize; // Size of data
};
#pragma pack(pop)
struct LinkedListNode
{
LinkedListNode *next; // Next node in the linked list
SeekableStreamReader *inStream; // Input stream object for file data
IndexEntry indexEntry; // Index entry to save in the index section
int streamStartOffset; // Starting offset of data in stream to store
};
LinkedListNode* SortIndex(LinkedListNode *list);
// Linked list variables
LinkedListNode *head;
int numNodes;
int unknown; // **TODO** Find out what this DWORD means
int maxDataSize;
};

View File

@ -0,0 +1,172 @@
#include "stdafx.h"
#include "CFileStreamReader.h"
extern int g_cLocks;
// IUnknown
// ********
ULONG __stdcall CFileStreamReader::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CFileStreamReader::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CFileStreamReader::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_StreamReader)
*ppv = (StreamReader*)this;
else if(riid == IID_SeekableStreamReader)
*ppv = (SeekableStreamReader*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// StreamReader
// ************
HRESULT CFileStreamReader::Read(int numBytes, int pBuffer, int *numBytesRead)
{
BOOL bResult;
unsigned long numberOfBytesRead;
// Read in the info
bResult = ReadFile(hFile, (void*)pBuffer, numBytes, &numberOfBytesRead, NULL);
*numBytesRead = numberOfBytesRead;
// Adjust the status of the stream
if ((bResult == 0) || (*numBytesRead < numBytes))
{
if (bResult == 0)
OutputDebugStringW(L"Error. ReadFile error.");
else if (*numBytesRead < numBytes)
OutputDebugStringW(L"End of file reached.");
// An error occured or a read past EOF occured
status = 1; // Nonzero denotes error
}
return S_OK;
}
HRESULT CFileStreamReader::get_Status(int *status)
{
*status = this->status;
return S_OK;
}
// SeekableStreamReader
// ********************
HRESULT CFileStreamReader::get_ReadOffset(int *readOffset)
{
*readOffset = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
return S_OK;
}
HRESULT CFileStreamReader::get_StreamSize(int *streamSize)
{
*streamSize = GetFileSize(hFile, NULL);
return S_OK;
}
HRESULT CFileStreamReader::Seek(int offset)
{
if (SetFilePointer(hFile, offset, NULL, FILE_BEGIN) == -1)
{
// Seek error.
status = 1; // Error
return E_FAIL;
}
return S_OK;
}
// Class specific
// **************
CFileStreamReader::CFileStreamReader(BSTR fileName) : m_cRef(1)
{
// Initialize class variables
status = 0;
// Open the file
hFile = CreateFileW(fileName, // lpFileName
GENERIC_READ, // dwDesired access
FILE_SHARE_READ,// dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN,
// dwFlagsAndAttributes
NULL // hTemplate
);
// Check if the file was opened successfully
if (hFile == INVALID_HANDLE_VALUE)
throw L"Could not open file for writing.";
// Check for alternate error
if (hFile == 0)
{
// Try to open the file using ANSI version of CreateFile
// Allocate space for a temporary ASCII fileName string
int stringLength = SysStringLen(fileName);
char *tempString = new char[stringLength+1];
tempString[stringLength] = 0; // NULL terminate it
// Convert the BSTR to ASCII
WideCharToMultiByte(CP_ACP, 0, fileName, stringLength, tempString, stringLength, 0, 0);
// Try to open the file with ANSI version of CreateFile
hFile = CreateFileA(tempString, // lpFileName
GENERIC_READ, // dwDesired access
FILE_SHARE_READ,// dwShareMode
NULL, // lpSecurityAttributes
OPEN_EXISTING, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN,
// dwFlagsAndAttributes
NULL // hTemplate
);
// Check for errors
if (hFile == INVALID_HANDLE_VALUE)
throw L"Could not open file for writing.";
}
g_cLocks++;
}
CFileStreamReader::~CFileStreamReader()
{
CloseHandle(hFile);
g_cLocks--;
}

View File

@ -0,0 +1,54 @@
#include "OP2Editor.h"
class CFileStreamReader : public SeekableStreamReader
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// StreamReader
// ************
// [local]
HRESULT STDMETHODCALLTYPE Read(
/* [in] */ int numBytes,
/* [in] */ int pBuffer,
/* [retval][out] */ int __RPC_FAR *numBytesRead);
// [propget]
HRESULT STDMETHODCALLTYPE get_Status(
/* [retval][out] */ int __RPC_FAR *status);
// SeekableStreamReader
// ********************
// [propget]
HRESULT STDMETHODCALLTYPE get_ReadOffset(
/* [retval][out] */ int __RPC_FAR *readOffset);
// [propget]
HRESULT STDMETHODCALLTYPE get_StreamSize(
/* [retval][out] */ int __RPC_FAR *streamSize);
HRESULT STDMETHODCALLTYPE Seek(
/* [in] */ int offset);
// Class specific
// **************
CFileStreamReader(BSTR fileName);
~CFileStreamReader();
private:
ULONG m_cRef;
HANDLE hFile; // Handle to opened file
int status; // Stream status code
};

View File

@ -0,0 +1,130 @@
#include "stdafx.h"
#include "CFileStreamWriter.h"
extern int g_cLocks;
// IUnknown
// ********
ULONG __stdcall CFileStreamWriter::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CFileStreamWriter::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CFileStreamWriter::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_StreamWriter)
*ppv = (StreamWriter*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
CFileStreamWriter::CFileStreamWriter(BSTR fileName) : m_cRef(1)
{
// Initialize class variables
status = 0;
// Open the file
hFile = CreateFileW(fileName, // lpFileName
GENERIC_WRITE, // dwDesired access
0, // dwShareMode
NULL, // lpSecurityAttributes
CREATE_ALWAYS, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN,
// dwFlagsAndAttributes
NULL // hTemplate
);
// Check if the file was opened successfully
if (hFile == INVALID_HANDLE_VALUE)
throw L"Could not open file for writing.";
// Check for alternate error
if (hFile == 0)
{
// Try to open the file using ANSI version of CreateFile
// Allocate space for a temporary ASCII fileName string
int stringLength = SysStringLen(fileName);
char *tempString = new char[stringLength+1];
tempString[stringLength] = 0; // NULL terminate it
// Convert the BSTR to ASCII
WideCharToMultiByte(CP_ACP, 0, fileName, stringLength, tempString, stringLength, 0, 0);
// Try to open the file with ANSI version of CreateFile
hFile = CreateFileA(tempString, // lpFileName
GENERIC_WRITE, // dwDesired access
0, // dwShareMode
NULL, // lpSecurityAttributes
CREATE_ALWAYS, // dwCreationDisposition
FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_SEQUENTIAL_SCAN,
// dwFlagsAndAttributes
NULL // hTemplate
);
// Check for errors
if (hFile == INVALID_HANDLE_VALUE)
throw L"Could not open file for writing.";
}
g_cLocks++;
}
CFileStreamWriter::~CFileStreamWriter()
{
CloseHandle(hFile);
g_cLocks--;
}
HRESULT CFileStreamWriter::Write(int numBytes, int pBuffer, int *numBytesWritten)
{
BOOL bResult;
unsigned long numberOfBytesWritten;
// Read in the info
bResult = WriteFile(hFile, (void*)pBuffer, numBytes, &numberOfBytesWritten, NULL);
*numBytesWritten = numberOfBytesWritten;
// Adjust the status of the stream
if ((bResult == 0) || (*numBytesWritten < numBytes))
{
// An error occured or not all bytes were written
status = 1; // Nonzero denotes error
}
return S_OK;
}
HRESULT CFileStreamWriter::get_Status(int *status)
{
*status = this->status;
return S_OK;
}

View File

@ -0,0 +1,33 @@
#include "OP2Editor.h"
class CFileStreamWriter : public StreamWriter
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// IFileStreamWriter
// [local]
HRESULT STDMETHODCALLTYPE Write(
/* [in] */ int numBytes,
/* [in] */ int pBuffer,
/* [retval][out] */ int __RPC_FAR *numBytesWritten);
// [propget]
HRESULT STDMETHODCALLTYPE get_Status(
/* [retval][out] */ int __RPC_FAR *status);
// Class specific
CFileStreamWriter(BSTR fileName);
~CFileStreamWriter();
private:
ULONG m_cRef;
HANDLE hFile; // Handle to opened file
int status; // Stream status code
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,237 @@
#include "OP2Editor.h"
#include "CTileGroup.h"
//#include "CTileSetManager.h"
class CMapFile : public MapFile, public ISupportErrorInfo
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// TileGroup
// *********
// [propget]
HRESULT STDMETHODCALLTYPE get_TileWidth(
/* [retval][out] */ int __RPC_FAR *tileWidth);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileHeight(
/* [retval][out] */ int __RPC_FAR *tileHeight);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSetManager(
/* [retval][out] */ TileSetManager __RPC_FAR *__RPC_FAR *tileSetManager);
// [propget]
HRESULT STDMETHODCALLTYPE get_MappingIndex(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *tileMappingIndex);
// [propput]
HRESULT STDMETHODCALLTYPE put_MappingIndex(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int tileMappingIndex);
HRESULT STDMETHODCALLTYPE Draw(
/* [in] */ int destDC,
/* [in] */ int sourcePixelX,
/* [in] */ int sourcePixelY,
/* [in] */ int pixelWidth,
/* [in] */ int pixelHeight);
// MapFile
// ********
// [propget]
HRESULT STDMETHODCALLTYPE get_AroundTheWorld(
/* [retval][out] */ int __RPC_FAR *bAroundTheWorld);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileData(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *tile);
// [propput]
HRESULT STDMETHODCALLTYPE put_TileData(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int newTile);
// [propget]
HRESULT STDMETHODCALLTYPE get_CellType(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *cellType);
// [propput]
HRESULT STDMETHODCALLTYPE put_CellType(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int newCellType);
// [propget]
HRESULT STDMETHODCALLTYPE get_UnitIndex(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *unitIndex);
// [propput]
HRESULT STDMETHODCALLTYPE put_UnitIndex(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int newUnitIndex);
//[propget]
HRESULT STDMETHODCALLTYPE get_Lava(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *lava);
// [propput]
HRESULT STDMETHODCALLTYPE put_Lava(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int lava);
// [propget]
HRESULT STDMETHODCALLTYPE get_LavaPossible(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *lavaPossible);
// [propput]
HRESULT STDMETHODCALLTYPE put_LavaPossible(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int lavaPossible);
// [propget]
HRESULT STDMETHODCALLTYPE get_Expand(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *expand);
// [propput]
HRESULT STDMETHODCALLTYPE put_Expand(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int expand);
// [propget]
HRESULT STDMETHODCALLTYPE get_Microbe(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *microbe);
// [propput]
HRESULT STDMETHODCALLTYPE put_Microbe(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int microbe);
// [propget]
HRESULT STDMETHODCALLTYPE get_WallOrBuilding(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *wallOrBuilding);
// [propput]
HRESULT STDMETHODCALLTYPE put_WallOrBuilding(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int wallOrBuilding);
HRESULT STDMETHODCALLTYPE Copy(
/* [in] */ int tileX1,
/* [in] */ int tileY1,
/* [in] */ int tileX2,
/* [in] */ int tileY2,
/* [retval][out] */ TileGroup __RPC_FAR *__RPC_FAR *tileGroup);
HRESULT STDMETHODCALLTYPE Paste(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ TileGroup __RPC_FAR *tileGroup);
// [propget]
HRESULT STDMETHODCALLTYPE get_NumTileGroups(
/* [retval][out] */ int __RPC_FAR *numTileGroups);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileGroup(
/* [in] */ int tileGroupIndex,
/* [retval][out] */ TileGroup __RPC_FAR *__RPC_FAR *tileGroup);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileGroupName(
/* [in] */ int tileGroupIndex,
/* [retval][out] */ BSTR __RPC_FAR *tileGroupName);
// [propput]
HRESULT STDMETHODCALLTYPE put_TileGroupName(
/* [in] */ int tileGroupIndex,
/* [in] */ BSTR tileGroupName);
HRESULT STDMETHODCALLTYPE AddTileGroup(
/* [in] */ TileGroup __RPC_FAR *newTileGroup);
HRESULT STDMETHODCALLTYPE RemoveTileGroup(
/* [in] */ int tileGroupIndex);
HRESULT STDMETHODCALLTYPE SaveMap(
/* [in] */ StreamWriter __RPC_FAR *stream,
/* [in] */ enum MapLoadSaveFormat saveFlags,
/* [retval][out] */ int __RPC_FAR *status);
// ISupportErrorInfo
// *****************
HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(REFIID riid);
// Class specific
// **************
CMapFile(TileSetSource *tileSetSource, int width, int height);
CMapFile(TileSetSource *tileSetSource, StreamReader *stream, enum MapLoadSaveFormat loadFlags);
~CMapFile();
private:
ULONG m_cRef;
// Class internal structures
#pragma pack(push, 1) // Make sure structures are byte aligned
struct MapHeader
{
int tag;
int unknown;
int lgTileWidth;
int tileHeight;
int numTileSets;
};
struct ClippingRect
{
int x1; // Left edge of map (x coordinate)
int y1; // Top edge of map (y coordinate)
int x2; // Rigth edge of map (x coordinate)
int y2; // Bottom edge of map (y coordinate)
};
#pragma pack(pop)
struct TileGroupInfo
{
TileGroup *tileGroup;
int nameLen;
char *name;
};
// Private functions
// *****************
int LoadMap(StreamReader *stream, TileSetSource *tileSetSource, int loadFlags);
void FreeMemory();
// Private variables
// *****************
MapHeader mapHeadInfo;
ClippingRect clipRect;
int tileWidth; // Cached width value (header contains lgTileWidth)
int *tileData; // Tile data array
CTileSetManager *tileSetManager; // Handles all tile sets for this map
TileSetSource *tileSource; // Source of all tile sets that need to be loaded
int numTileGroups; // Number of tile groups stored in map file
TileGroupInfo *tileGroupInfo; // Array of named tile groups
};

View File

@ -0,0 +1,142 @@
#include "stdafx.h"
#include "CMemoryStreamReader.h"
extern int g_cLocks;
// IUnknown
// ********
ULONG __stdcall CMemoryStreamReader::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CMemoryStreamReader::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CMemoryStreamReader::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_StreamReader)
*ppv = (StreamReader*)this;
else if(riid == IID_SeekableStreamReader)
*ppv = (SeekableStreamReader*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// StreamReader
// ************
HRESULT CMemoryStreamReader::Read(int numBytes, int pBuffer, int *numBytesRead)
{
// Initialize returned number of bytes read to 0
*numBytesRead = 0;
// Check for read past end of stream
if (readPtr >= bufferSize)
{
// Error. Read past end of stream
streamStatus = 1; // Error. Read past end of stream
return E_FAIL;
}
// Default to number of bytes requested
*numBytesRead = numBytes;
// Check for partial read past end of stream
if (readPtr + numBytes > bufferSize)
{
// Adjust number of bytes to read
streamStatus = 1; // Error. Read past end of stream
*numBytesRead = bufferSize - readPtr;
}
// Perform a memory copy
memcpy((void*)pBuffer, &streamBuffer[readPtr], *numBytesRead);
// Update the read pointer
readPtr += *numBytesRead;
return S_OK;
}
HRESULT CMemoryStreamReader::get_Status(int *status)
{
*status = streamStatus;
return S_OK;
}
// SeekableStreamReader
// ********************
HRESULT CMemoryStreamReader::get_ReadOffset(int *readOffset)
{
*readOffset = readPtr;
return S_OK;
}
HRESULT CMemoryStreamReader::get_StreamSize(int *streamSize)
{
*streamSize = bufferSize;
return S_OK;
}
HRESULT CMemoryStreamReader::Seek(int offset)
{
if (offset < bufferSize)
readPtr = offset;
return S_OK;
}
// Class specific
// **************
CMemoryStreamReader::CMemoryStreamReader(int streamLength, char *buffer, int bAttachToBuffer)
: m_cRef(1)
{
// Initialize variables
streamStatus = 0;
readPtr = 0;
bufferSize = streamLength;
if (bAttachToBuffer == 0)
{
// Allocate space for stream data
streamBuffer = new char[bufferSize];
// Copy the data into the buffer
memcpy(streamBuffer, buffer, bufferSize);
}
else
streamBuffer = buffer;
g_cLocks++;
}
CMemoryStreamReader::~CMemoryStreamReader()
{
delete [] streamBuffer;
g_cLocks--;
}

View File

@ -0,0 +1,56 @@
#include "OP2Editor.h"
class CMemoryStreamReader : public SeekableStreamReader
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// StreamReader
// ************
// [local]
HRESULT STDMETHODCALLTYPE Read(
/* [in] */ int numBytes,
/* [in] */ int pBuffer,
/* [retval][out] */ int __RPC_FAR *numBytesRead);
// [propget]
HRESULT STDMETHODCALLTYPE get_Status(
/* [retval][out] */ int __RPC_FAR *status);
// SeekableStreamReader
// ********************
// [propget]
HRESULT STDMETHODCALLTYPE get_ReadOffset(
/* [retval][out] */ int __RPC_FAR *readOffset);
// [propget]
HRESULT STDMETHODCALLTYPE get_StreamSize(
/* [retval][out] */ int __RPC_FAR *streamSize);
HRESULT STDMETHODCALLTYPE Seek(
/* [in] */ int offset);
// Class specific
// **************
CMemoryStreamReader(int streamLength, char *buffer, int bAttachToBuffer);
~CMemoryStreamReader();
private:
ULONG m_cRef;
int streamStatus;
int readPtr;
int bufferSize;
char *streamBuffer;
};

View File

@ -0,0 +1,653 @@
#include "stdafx.h"
#include "CResourceManager.h"
#include "CFileStreamReader.h"
#include "CFileStreamWriter.h"
#include "CVolReader.h"
#include "CVolWriter.h"
#include "CClmReader.h"
#include "CClmWriter.h"
#include "CMapFile.h"
#include "GlobalFunctions.h"
extern int g_cLocks;
ULONG __stdcall CResourceManager::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CResourceManager::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CResourceManager::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown)
*ppv = (IUnknown*)(ResourceManager*)this;
else if (riid == IID_IResourceManager)
*ppv = (IResourceManager*)this;
else if (riid == IID_ISupportErrorInfo)
*ppv = (ISupportErrorInfo*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
CResourceManager::CResourceManager(BSTR gamePath) : m_cRef(1)
{
// Initilize linked list of archives in search path
head = NULL;
tail = NULL;
int stringLength;
// Cache string length
stringLength = SysStringLen(gamePath);
// Add a trailing "\" if none exists
if ((stringLength > 0) && (gamePath[stringLength-1] != L'\\'))
{
// Allocate space for string + "\"
path = SysAllocStringLen(NULL, stringLength+1);
// Copy the string
memcpy(path, gamePath, stringLength*2);
// Append a trailing "\"
path[stringLength] = L'\\';
}
else
{
// Save the path to the game folder
path = SysAllocString(gamePath);
}
// Create a new tile set source object
tileSetSource = new CTileSetSource(this);
g_cLocks++;
}
CResourceManager::~CResourceManager()
{
LinkedListNode *current, *next;
g_cLocks--;
// Unload all archives in search path and delete linked list nodes
current = head;
while (current)
{
current->archive->Release();
next = current->next;
delete current;
current = next;
}
// Free the tile set source object
tileSetSource->Release();
// Free the game path BSTR
SysFreeString(path);
}
HRESULT CResourceManager::get_RootPath(BSTR *path)
{
SysReAllocString(path, this->path);
return S_OK;
}
HRESULT CResourceManager::put_RootPath(BSTR newPath)
{
int stringLength;
// Cache string length
stringLength = SysStringLen(newPath);
// Add a trailing "\" if none exists
if ((stringLength > 0) && (newPath[stringLength-1] != L'\\'))
{
// Allocate space for string + "\"
SysReAllocStringLen(&path, NULL, stringLength+1);
// Copy the string
memcpy(path, newPath, stringLength*2);
// Append a trailing "\"
path[stringLength] = L'\\';
}
else
{
// Save the path to the game folder
SysReAllocString(&path, newPath);
}
// Replace the resource sources
delete tileSetSource;
tileSetSource = new CTileSetSource(this);
return S_OK;
}
HRESULT CResourceManager::OpenStreamRead(
/* [in] */ BSTR fileName,
/* [retval][out] */ StreamReader **stream)
{
int lenFileName = SysStringLen(fileName);
int lenPath = SysStringLen(path);
BSTR pathAndFile = NULL;
// Initialize returned stream pointer to NULL
*stream = NULL;
// Check if relative path given
if (IsRelative(fileName))
{
// Form the full path name rooted at the desired directory
pathAndFile = SysAllocStringLen(NULL, lenFileName + lenPath);
memcpy(pathAndFile, path, lenPath*2);
memcpy((char*)pathAndFile + (lenPath * 2), fileName, lenFileName*2);
}
else
{
// Absolute path. Copy the string
pathAndFile = SysAllocString(fileName);
}
// Check if file exists in directory rooted at the game path
try
{
*stream = new CFileStreamReader(pathAndFile);
}
catch(...)
{
}
// Release the path string (Not needed for searching archives)
SysFreeString(pathAndFile);
if (*stream)
{
// Stream successfully opened
return S_OK;
}
// Failed to open a file. Search the loaded vol files for this resource.
LinkedListNode *current = head;
while (current)
{
// Try to open the stream from each archive
// Note: Don't use full path. Only resource name.
current->archive->OpenStreamRead(fileName, stream);
// Check if successful
if (*stream != NULL)
{
// Stream opened successfully
return S_OK;
}
current = current->next;
}
// Could not find resource.
PostErrorMsg(L"Could not find resource.");
return E_FAIL;
}
HRESULT CResourceManager::OpenStreamWrite(
/* [in] */ BSTR fileName,
/* [retval][out] */ StreamWriter **stream)
{
int lenFileName = SysStringLen(fileName);
int lenPath = SysStringLen(path);
BSTR pathAndFile = NULL;
// Initialize returned stream pointer to NULL
*stream = NULL;
// Check if relative path given
if (IsRelative(fileName))
{
// Form the full path name rooted at the desired directory
pathAndFile = SysAllocStringLen(NULL, lenFileName + lenPath);
memcpy(pathAndFile, path, lenPath*2);
memcpy((char*)pathAndFile + (lenPath * 2), fileName, lenFileName*2);
}
else
{
// Absolute path. Copy the string
pathAndFile = SysAllocString(fileName);
}
// Try to open the file for writing
try
{
*stream = new CFileStreamWriter(pathAndFile);
if (stream == NULL)
{
SysFreeString(pathAndFile);
PostErrorMsg(L"Failed to create stream writer.");
return E_OUTOFMEMORY;
}
}
catch(...)
{
}
if (*stream)
{
// Stream successfully opened
SysFreeString(pathAndFile);
return S_OK;
}
// **Possible future expansion**
// See if an existing archive file can accept the new data
// Could not open the file for writing
SysFreeString(pathAndFile);
PostErrorMsg(L"Failed to create stream writer.");
return E_FAIL;
}
HRESULT CResourceManager::LoadMapFile(BSTR fileName, enum MapLoadSaveFormat loadFlags, MapFile **mapFile)
{
StreamReader *inStream;
// Initialize returned mapFile pointer to NULL
*mapFile = NULL;
// Try to open the file as a stream
OpenStreamRead(fileName, &inStream);
// Check if a stream was constructed
if (inStream == NULL)
{
// Failed to open the file as a stream
return E_INVALIDARG;
}
// Read in the map data
HRESULT hr = LoadMap(inStream, loadFlags, mapFile);
// Release the input stream
inStream->Release();
return hr;
}
HRESULT CResourceManager::LoadMap(StreamReader *inStream, enum MapLoadSaveFormat loadFlags, MapFile **mapFile)
{
CMapFile *pMapFile;
// Initialize returned mapFile pointer to NULL
*mapFile = NULL;
try
{
pMapFile = new CMapFile(tileSetSource, inStream, loadFlags);
if (pMapFile == 0) return E_OUTOFMEMORY;
}
catch(...)
{
// Error constructing object
return E_FAIL;
}
HRESULT hr = pMapFile->QueryInterface(IID_MapFile, (void**)mapFile);
pMapFile->Release();
return hr;
}
HRESULT CResourceManager::CreateNewMap(int width, int height, MapFile** newMap)
{
CMapFile *pMapFile;
// Initialize returned mapFile pointer to NULL
*newMap = NULL;
try
{
pMapFile = new CMapFile(tileSetSource, width, height);
if (pMapFile == 0) return E_OUTOFMEMORY;
}
catch(...)
{
// Error constructing object
return E_FAIL;
}
HRESULT hr = pMapFile->QueryInterface(IID_MapFile, (void**)newMap);
pMapFile->Release();
return hr;
}
HRESULT CResourceManager::LoadTileSetFile(BSTR fileName, TileSet **tileSet)
{
StreamReader *inStream;
// Initialize returned tileSet pointer to NULL
*tileSet = NULL;
// Try to open the file as a stream
OpenStreamRead(fileName, &inStream);
// Check if a stream was constructed
if (inStream == NULL)
{
// Failed to open the file as a stream
return E_FAIL;
}
// Read in the tile set data
HRESULT hr = LoadTileSet(inStream, tileSet);
// Release the input stream
inStream->Release();
return hr;
}
HRESULT CResourceManager::LoadTileSet(StreamReader *stream, TileSet **tileSet)
{
CTileSet *pTileSet;
// Initialize returned tileSet pointer to NULL
*tileSet = NULL;
try
{
pTileSet = new CTileSet(stream);
if (pTileSet == 0) return E_OUTOFMEMORY;
}
catch(...)
{
// Error constructing object
return E_FAIL;
}
HRESULT hr = pTileSet->QueryInterface(IID_TileSet, (void**)tileSet);
pTileSet->Release();
return hr;
}
HRESULT CResourceManager::CreateTileSet(int numTiles, int bitDepth, int width, TileSet **newTileSet)
{
CTileSet *pTileSet;
// Initialize returned tileSet pointer to NULL
*newTileSet = NULL;
try
{
pTileSet = new CTileSet(numTiles, bitDepth, width);
if (pTileSet == 0) return E_OUTOFMEMORY;
}
catch(...)
{
// Error constructing object
return E_FAIL;
}
HRESULT hr = pTileSet->QueryInterface(IID_TileSet, (void**)newTileSet);
pTileSet->Release();
return hr;
}
HRESULT CResourceManager::LoadVolFile(BSTR fileName, int bAttachToStream, ArchiveReader **volReader)
{
StreamReader *inStream;
SeekableStreamReader *inSeekStream;
// Initialize returned ArchiveReader to NULL
*volReader = NULL;
// Try to open the file as a stream
OpenStreamRead(fileName, &inStream);
// Check if a stream was constructed
if (inStream == NULL)
{
// Failed to open the file as a stream
return E_FAIL;
}
// Obtain the SeekableStreamReader interface
inStream->QueryInterface(IID_SeekableStreamReader, (void**)&inSeekStream);
inStream->Release();
// Check if the interface was obtained
if (inSeekStream == NULL)
{
// Failed to obtain a SeekableStreamReader interface
return E_FAIL;
}
// Read in the vol data
HRESULT hr = LoadVol(inSeekStream, bAttachToStream, volReader);
// Release the stream
inSeekStream->Release();
return hr;
}
HRESULT CResourceManager::LoadVol(SeekableStreamReader *inStream, int bAttachToStream, ArchiveReader **volReader)
{
CVolReader *pVolReader;
// Initialize returned ArchiveReader to NULL
*volReader = NULL;
// Try to create a VOL reader
try
{
pVolReader = new CVolReader(inStream, bAttachToStream);
if (pVolReader == NULL) return E_OUTOFMEMORY;
}
catch(...)
{
return E_FAIL;
}
// Obtain the ArchiveReader interface
HRESULT hr = pVolReader->QueryInterface(IID_ArchiveReader, (void**)volReader);
pVolReader->Release();
return hr;
}
HRESULT CResourceManager::CreateVolFile(ArchiveWriter **volWriter)
{
CVolWriter *pVolWriter;
// Initialize returned ArchiveWriter to NULL
*volWriter = NULL;
try
{
pVolWriter = new CVolWriter();
if (pVolWriter == NULL) return E_OUTOFMEMORY;
}
catch(...)
{
// Failed to create CVolWriter object
return E_FAIL;
}
// Obtain the ArchiveWriter interface
HRESULT hr = pVolWriter->QueryInterface(IID_ArchiveWriter, (void**)volWriter);
pVolWriter->Release();
return hr;
}
HRESULT CResourceManager::LoadClmFile(BSTR fileName, int bAttachToStream, ArchiveReader **clmReader)
{
StreamReader *inStream;
SeekableStreamReader *inSeekStream;
// Initialize returned ArchiveReader to NULL
*clmReader = NULL;
// Try to open the file as a stream
OpenStreamRead(fileName, &inStream);
// Check if a stream was constructed
if (inStream == NULL)
{
// Failed to open the file as a stream
PostErrorMsg(L"Error. Could not open stream.");
return E_FAIL;
}
// Obtain the SeekableStreamReader interface
inStream->QueryInterface(IID_SeekableStreamReader, (void**)&inSeekStream);
inStream->Release();
// Check if the interface was obtained
if (inSeekStream == NULL)
{
// Failed to obtain a SeekableStreamReader interface
PostErrorMsg(L"Error. Stream was not seekable.");
return E_FAIL;
}
// Read in the vol data
HRESULT hr = LoadClm(inSeekStream, bAttachToStream, clmReader);
// Release the stream
inSeekStream->Release();
return hr;
}
HRESULT CResourceManager::LoadClm(SeekableStreamReader *inStream, int bAttachToStream, ArchiveReader **clmReader)
{
CClmReader *pClmReader;
// Initialize returned ArchiveReader to NULL
*clmReader = NULL;
// Try to create a CLM reader
try
{
pClmReader = new CClmReader(inStream, bAttachToStream);
if (pClmReader == NULL) return E_OUTOFMEMORY;
}
catch(...)
{
return E_FAIL;
}
// Obtain the ArchiveReader interface
HRESULT hr = pClmReader->QueryInterface(IID_ArchiveReader, (void**)clmReader);
pClmReader->Release();
return hr;
}
HRESULT CResourceManager::CreateClmFile(ArchiveWriter **clmWriter)
{
CClmWriter *pClmWriter;
// Initialize returned ArchiveWriter to NULL
*clmWriter = NULL;
try
{
pClmWriter = new CClmWriter();
if (pClmWriter == NULL) return E_OUTOFMEMORY;
}
catch(...)
{
// Failed to create CVolWriter object
return E_FAIL;
}
// Obtain the ArchiveWriter interface
HRESULT hr = pClmWriter->QueryInterface(IID_ArchiveWriter, (void**)clmWriter);
pClmWriter->Release();
return hr;
}
HRESULT CResourceManager::AddArchiveToSearch(ArchiveReader *volReader)
{
LinkedListNode *newNode;
// Create a new linked list node
newNode = new LinkedListNode;
newNode->next = NULL;
newNode->archive = volReader;
// Increment the reference count
volReader->AddRef();
// Check if list is empty
if (head == NULL)
head = newNode;
// Add archive to tail of linked list
if (tail != NULL)
tail->next = newNode;
// Update tail of linked list
tail = newNode;
return S_OK;
}
HRESULT CResourceManager::ClearSearchPath()
{
LinkedListNode *current, *next;
// Clear linked list of archives in search path
current = head;
while (current)
{
current->archive->Release(); // Release the archive
next = current->next; // Get the next linked list node
delete current; // Release the current linked list node
current = next; // Process next node
}
head = NULL;
tail = NULL;
return S_OK;
}
// ISupportErrorInfo
// *****************
HRESULT CResourceManager::InterfaceSupportsErrorInfo(REFIID riid)
{
if (riid == IID_IResourceManager)
return S_OK;
else
return S_FALSE;
}

View File

@ -0,0 +1,112 @@
#include "OP2Editor.h"
#include "CTileSetSource.h"
class CResourceManager : public IResourceManager, public ISupportErrorInfo
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// IResource Manager
// *****************
// [propget]
HRESULT STDMETHODCALLTYPE get_RootPath(
/* [retval][out] */ BSTR __RPC_FAR *path);
// [propput]
HRESULT STDMETHODCALLTYPE put_RootPath(
/* [in] */ BSTR path);
HRESULT STDMETHODCALLTYPE OpenStreamRead(
/* [in] */ BSTR fileName,
/* [retval][out] */ StreamReader __RPC_FAR *__RPC_FAR *stream);
HRESULT STDMETHODCALLTYPE OpenStreamWrite(
/* [in] */ BSTR fileName,
/* [retval][out] */ StreamWriter __RPC_FAR *__RPC_FAR *stream);
HRESULT STDMETHODCALLTYPE LoadMapFile(
/* [in] */ BSTR fileName,
/* [in] */ enum MapLoadSaveFormat loadFlags,
/* [retval][out] */ MapFile __RPC_FAR *__RPC_FAR *mapFile);
HRESULT STDMETHODCALLTYPE LoadMap(
/* [in] */ StreamReader __RPC_FAR *inStream,
/* [in] */ enum MapLoadSaveFormat loadFlags,
/* [retval][out] */ MapFile __RPC_FAR *__RPC_FAR *mapFile);
HRESULT STDMETHODCALLTYPE CreateNewMap(
/* [in] */ int width,
/* [in] */ int height,
/* [retval][out] */ MapFile __RPC_FAR *__RPC_FAR *newMap);
HRESULT STDMETHODCALLTYPE LoadTileSetFile(
/* [in] */ BSTR fileName,
/* [retval][out] */ TileSet __RPC_FAR *__RPC_FAR *tileSet);
HRESULT STDMETHODCALLTYPE LoadTileSet(
/* [in] */ StreamReader __RPC_FAR *inStream,
/* [retval][out] */ TileSet __RPC_FAR *__RPC_FAR *tileSet);
HRESULT STDMETHODCALLTYPE CreateTileSet(
/* [in] */ int numTiles,
/* [in] */ int bitDepth,
/* [in] */ int width,
/* [retval][out] */ TileSet __RPC_FAR *__RPC_FAR *newTileSet);
HRESULT STDMETHODCALLTYPE LoadVolFile(
/* [in] */ BSTR fileName,
/* [in] */ int bAttachToStream,
/* [retval][out] */ ArchiveReader __RPC_FAR *__RPC_FAR *volReader);
HRESULT STDMETHODCALLTYPE LoadVol(
/* [in] */ SeekableStreamReader __RPC_FAR *inStream,
/* [in] */ int bAttachToStream,
/* [retval][out] */ ArchiveReader __RPC_FAR *__RPC_FAR *volReader);
HRESULT STDMETHODCALLTYPE CreateVolFile(
/* [retval][out] */ ArchiveWriter __RPC_FAR *__RPC_FAR *volWriter);
HRESULT STDMETHODCALLTYPE LoadClmFile(
/* [in] */ BSTR fileName,
/* [in] */ int bAttachToStream,
/* [retval][out] */ ArchiveReader __RPC_FAR *__RPC_FAR *clmReader);
HRESULT STDMETHODCALLTYPE LoadClm(
/* [in] */ SeekableStreamReader __RPC_FAR *inStream,
/* [in] */ int bAttachToStream,
/* [retval][out] */ ArchiveReader __RPC_FAR *__RPC_FAR *clmReader);
HRESULT STDMETHODCALLTYPE CreateClmFile(
/* [retval][out] */ ArchiveWriter __RPC_FAR *__RPC_FAR *clmWriter);
HRESULT STDMETHODCALLTYPE AddArchiveToSearch(
/* [in] */ ArchiveReader __RPC_FAR *volReader);
HRESULT STDMETHODCALLTYPE ClearSearchPath(void);
// ISupportErrorInfo
// *****************
HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(REFIID riid);
// Constructor/Destructor
// **********************
CResourceManager(BSTR gamePath);
~CResourceManager();
private:
ULONG m_cRef; // COM object reference count
struct LinkedListNode
{
LinkedListNode *next;
ArchiveReader *archive;
};
// Class specific variables
BSTR path;
CTileSetSource *tileSetSource;
// LinkedList
LinkedListNode *head;
LinkedListNode *tail;
};

View File

@ -0,0 +1,63 @@
#include "stdafx.h"
#include "CResourceManagerFactory.h"
#include "CResourceManager.h"
ULONG CResourceManagerFactory::AddRef()
{
return ++m_cRef;
}
ULONG CResourceManagerFactory::Release()
{
if(--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT CResourceManagerFactory::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_IClassFactory)
*ppv = (IClassFactory*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
HRESULT CResourceManagerFactory::CreateInstance(IUnknown *pUnknownOuter,
REFIID riid, void** ppv)
{
if(pUnknownOuter != NULL)
return CLASS_E_NOAGGREGATION;
// Initialize returned object pointer to NULL
*ppv = NULL;
CResourceManager *pResManager = new CResourceManager(NULL);
if(pResManager == NULL)
return E_OUTOFMEMORY;
HRESULT hr = pResManager->QueryInterface(riid, ppv);
pResManager->Release();
return hr;
}
HRESULT CResourceManagerFactory::LockServer(BOOL bLock)
{
if(bLock)
g_cLocks++;
else
g_cLocks--;
return S_OK;
}

View File

@ -0,0 +1,23 @@
extern int g_cLocks;
class CResourceManagerFactory : public IClassFactory
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// IClassFactory
HRESULT __stdcall CreateInstance(IUnknown* pUnknownOuter,
REFIID riid, void** ppv);
HRESULT __stdcall LockServer(BOOL bLock);
CResourceManagerFactory() : m_cRef(1) { g_cLocks++; }
~CResourceManagerFactory() { g_cLocks--; }
private:
ULONG m_cRef;
};

View File

@ -0,0 +1,188 @@
#include "stdafx.h"
#include "CTileGroup.h"
#include "GlobalFunctions.h"
extern int g_cLocks;
// IUnknown functions
// ******************
ULONG __stdcall CTileGroup::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CTileGroup::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CTileGroup::QueryInterface(REFIID riid, void** ppv)
{
if (riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if (riid == IID_TileGroup)
*ppv = (TileGroup*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// TileGroup functions
// *******************
HRESULT CTileGroup::get_TileWidth(int *width)
{
*width = tileWidth;
return S_OK;
}
HRESULT CTileGroup::get_TileHeight(int *height)
{
*height = tileHeight;
return S_OK;
}
HRESULT CTileGroup::get_TileSetManager(TileSetManager **tileSetManager)
{
this->tileSetManager->QueryInterface(IID_TileSetManager, (void**)tileSetManager);
return S_OK;
}
HRESULT CTileGroup::get_MappingIndex(int tileX, int tileY, int *tileMappingIndex)
{
// Error check array indicies
if ((tileX < 0) || (tileX >= tileWidth) || (tileY < 0) || (tileY >= tileHeight))
{
PostErrorMsg(L"Invalid tile location");
return E_INVALIDARG;
}
// Get the tile mapping index
*tileMappingIndex = tileData[tileY*tileWidth + tileX];
return S_OK;
}
HRESULT CTileGroup::put_MappingIndex(int tileX, int tileY, int tileMappingIndex)
{
// Error check array indicies
if ((tileX < 0) || (tileX >= tileWidth) || (tileY < 0) || (tileY >= tileHeight))
{
PostErrorMsg(L"Invalid tile location");
return E_INVALIDARG;
}
// Set the tile mapping index
tileData[tileY*tileWidth + tileX] = tileMappingIndex;
return S_OK;
}
HRESULT CTileGroup::Draw(int destDC, int sourcePixelX, int sourcePixelY, int pixelWidth, int pixelHeight)
{
int startXTile = sourcePixelX >> 5;
int startYTile = sourcePixelY >> 5;
int endXTile = (sourcePixelX+pixelWidth+31) >> 5;
int endYTile = (sourcePixelY+pixelHeight+31) >> 5;
int x, y;
int tileIndex;
TileSet *tileSet;
CTileSetManager::TileSetTileMapping *tileMap;
int destPixelX = -(sourcePixelX & 0x1F);
int destPixelY = -(sourcePixelY & 0x1F);
if (endYTile > tileHeight)
endYTile = tileHeight;
if (endXTile > tileWidth)
endXTile = tileWidth;
// Draw all tiles in visible range
for (y = startYTile; y < endYTile; y++)
{
for (x = startXTile; x < endXTile; x++)
{
// Load the tile mapping index
tileIndex = tileData[y*tileWidth + x];
// Get the tile mapping
tileMap = &tileSetManager->mapping[tileIndex];
// Paste the tile
tileSet = tileSetManager->tileSetInfo[tileMap->tileSetIndex].tileSet;
if (tileSet)
{
tileSet->PasteTile(destDC, destPixelX+((x-startXTile)*32), destPixelY+((y-startYTile)*32), tileMap->tileIndex);
}
}
}
return S_OK;
}
// Class specific
// **************
CTileGroup::CTileGroup(int tileWidth, int tileHeight, CTileSetManager *tileSetManager) : m_cRef(1)
{
// Initialize variables
this->tileWidth = tileWidth;
this->tileHeight = tileHeight;
this->tileSetManager = tileSetManager;
// Increment reference count of tile set manager object
tileSetManager->AddRef();
// Check for NULL tile set manager object pointer
if (tileSetManager == NULL)
throw L"Error: TileSetManager object pointer is NULL.";
// Allocate space for data
tileData = new int[tileWidth*tileHeight];
// Increment module lock count
g_cLocks++;
}
CTileGroup::CTileGroup(int tileWidth, int tileHeight, TileSetSource *tileSetSource) : m_cRef(1)
{
// Initialize variables
this->tileWidth = tileWidth;
this->tileHeight = tileHeight;
// Allocate space for data
tileData = new int[tileWidth*tileHeight];
tileSetManager = new CTileSetManager(tileSetSource);
// Increment module lock count
g_cLocks++;
}
CTileGroup::~CTileGroup()
{
if (tileData != NULL)
delete [] tileData;
if (tileSetManager != NULL)
tileSetManager->Release();
// Decrement module lock count
g_cLocks--;
}

View File

@ -0,0 +1,70 @@
#include "OP2Editor.h"
#include "CTileSetManager.h"
class CTileGroup : public TileGroup
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// TileGroup
// *********
// [propget]
HRESULT STDMETHODCALLTYPE get_TileWidth(
/* [retval][out] */ int __RPC_FAR *tileWidth);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileHeight(
/* [retval][out] */ int __RPC_FAR *tileHeight);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSetManager(
/* [retval][out] */ TileSetManager __RPC_FAR *__RPC_FAR *tileSetManager);
// [propget]
HRESULT STDMETHODCALLTYPE get_MappingIndex(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [retval][out] */ int __RPC_FAR *tileMappingIndex);
// [propput]
HRESULT STDMETHODCALLTYPE put_MappingIndex(
/* [in] */ int tileX,
/* [in] */ int tileY,
/* [in] */ int tileMappingIndex);
HRESULT STDMETHODCALLTYPE Draw(
/* [in] */ int destDC,
/* [in] */ int sourcePixelX,
/* [in] */ int sourcePixelY,
/* [in] */ int pixelWidth,
/* [in] */ int pixelHeight);
// ISupportErrorInfo
// *****************
HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(REFIID riid);
// Class specific
// **************
CTileGroup(int tileWidth, int tileHeight, CTileSetManager *tileSetManager);
CTileGroup(int tileWidth, int tileHeight, TileSetSource *tileSetSource);
~CTileGroup();
private:
ULONG m_cRef;
// Private variables
// *****************
int tileWidth; // Width of this tile group
int tileHeight; // Height of this tile group
int *tileData; // Array of mapping indexes
CTileSetManager *tileSetManager; // TileSetManager for this tile group
};

View File

@ -0,0 +1,865 @@
#include "stdafx.h"
#include "CTileSet.h"
#include "GlobalFunctions.h"
extern int g_cLocks;
// IUnknown
// ********
ULONG __stdcall CTileSet::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CTileSet::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CTileSet::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_TileSet)
*ppv = (TileSet*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// ITileSet
// ********
HRESULT CTileSet::get_NumTiles(int *numTiles)
{
*numTiles = numberOfTiles;
return S_OK;
}
HRESULT CTileSet::get_TileSize(int *tileSize)
{
*tileSize = headInfo.width;
return S_OK;
}
HRESULT CTileSet::get_BitDepth(int *bitDepth)
{
*bitDepth = headInfo.bitDepth;
return S_OK;
}
HRESULT CTileSet::get_NumPaletteEntries(int *numPaletteEntries)
{
*numPaletteEntries = bmInfo->bmiHeader.biClrUsed;
return S_OK;
}
HRESULT CTileSet::get_PaletteEntry(int index, int *palEntry)
{
// Error check the array bounds
if ((index < 0) || (index >= 256))
{
PostErrorMsg(L"Invalid index value");
return E_INVALIDARG;
}
*palEntry = *(int*)(&bmInfo->bmiColors[index]);
return S_OK;
}
HRESULT CTileSet::put_PaletteEntry(int index, int palEntry)
{
// Error check the array bounds
if ((index < 0) || (index >= 256))
{
PostErrorMsg(L"Invalid index value");
return E_INVALIDARG;
}
bmInfo->bmiColors[index] = *((RGBQUAD*)(&palEntry));
SetDIBColorTable(memDC, index, 1, (RGBQUAD*)&palEntry);
return S_OK;
}
HRESULT CTileSet::SetNumTiles(int newNumTiles)
{
HBITMAP newTileSet;
unsigned char *newPixelData;
int newSizeOfPixelData;
// Calculate new DIB dimensions
headInfo.height = headInfo.width * newNumTiles;
bmInfo->bmiHeader.biHeight = -headInfo.width * newNumTiles;
newSizeOfPixelData = scanlineByteWidth*headInfo.width*newNumTiles;
if (sizeOfPixelData > newSizeOfPixelData) sizeOfPixelData = newSizeOfPixelData;
// Create a new DIB section
newTileSet = CreateDIBSection(NULL, bmInfo, DIB_RGB_COLORS, (void**)&newPixelData, NULL, 0);
tileSet = (HBITMAP)SelectObject(memDC, originalBm); // Unselect the old DIB section
// Copy tile set pixel data to the new DIB section
GdiFlush();
memcpy(newPixelData, pixelData, sizeOfPixelData);
// Blank out new pixels
memset(newPixelData + sizeOfPixelData, 0, newSizeOfPixelData - sizeOfPixelData);
// Replace the old DIB section
DeleteObject(tileSet); // Release the old DIB section
originalBm = (HBITMAP)SelectObject(memDC, newTileSet); // Select the new DIB section into the DC
// Update class variables
numberOfTiles = newNumTiles;
sizeOfPixelData = newSizeOfPixelData;
pixelData = newPixelData;
tileSet = newTileSet;
// **TODO** Update zoomPixelData and array size
return S_OK;
}
// Copies internal data to a client specified buffer
HRESULT CTileSet::GetPixelData(int pBuffer, int startOffset, int numBytes)
{
// Error check the arguments
if (startOffset < 0)
{
PostErrorMsg(L"Must have positive value for startOffset");
return E_INVALIDARG;
}
// **TODO** Improve error checking
if (startOffset+numBytes <= sizeOfPixelData) // Bounds check the memory copy
memcpy((void*)pBuffer, pixelData+startOffset, numBytes); // Copy the pixel data
return S_OK;
}
// Copies data to the internal buffer from a client specified buffer
HRESULT CTileSet::SetPixelData(int pBuffer, int startOffset, int numBytes)
{
// Error check the arguments
if (startOffset < 0)
{
PostErrorMsg(L"Must have positive value for startOffset");
return E_INVALIDARG;
}
// **TODO** Improve error checking
if (startOffset+numBytes <= sizeOfPixelData) // Bounds check the memory copy
memcpy(pixelData+startOffset, (void*)pBuffer, numBytes); // Copy the pixel data
// Recalculate minimap colors
int bytesPerTile = scanlineByteWidth * headInfo.width; // Note: Assume square tiles
//CalcMiniMapColors(startOffset/bytesPerTile, (startOffset+numBytes-1)/bytesPerTile);
return S_OK;
}
// **TODO** Remove
HRESULT CTileSet::get_MiniMapColors(int tileIndex, int *color)
{
*color = *(int*)&miniMapColors[tileIndex];
return S_OK;
}
// Pastes the specified tile to the destination Device Context at the given coordinates
HRESULT CTileSet::PasteTile(int destDC, int pixelX, int pixelY, int tileNum)
{
// Paste the tile to the destDC at given coordinates. Note: Tile are assumed
// to be square, and stored in the bitmap as a column of tiles.
BitBlt((HDC)destDC, pixelX, pixelY, headInfo.width, headInfo.width, memDC, 0, tileNum*headInfo.width, SRCCOPY);
//SetDIBitsToDevice((HDC)destDC, pixelX, pixelY, headInfo.width, headInfo.width, 0, 0, 0, 32, &pixelData[tileNum*scanlineByteWidth*headInfo.width], bmInfo, DIB_RGB_COLORS);
return S_OK;
}
HRESULT CTileSet::SaveTileSet(StreamWriter *stream, enum TileSetSaveFormat saveFormat)
{
switch(saveFormat)
{
case Default:
SaveTileSet(stream);
break;
case Bitmap:
SaveBitmapFile(stream);
break;
default:
// Unsupported format
return E_INVALIDARG;
break;
}
return S_OK;
}
// Private functions
// *****************
// Constructors
// ************
CTileSet::CTileSet(int numTiles, int bitDepth, int width) : m_cRef(1)
{
// Initialize variables
memDC = NULL;
scanlineByteWidth = ((width*bitDepth + 31) & ~31) >> 3; // DWORD aligned scanline size
sizeOfPixelData = scanlineByteWidth * width * numTiles; // Note: tiles are square
numberOfTiles = numTiles;
headInfo.bitDepth = bitDepth;
headInfo.width = width;
headInfo.height = width*numTiles;
headInfo.flags = 8; // **TODO** Find out what these flags mean
miniMapColors = NULL; // **TODO** Remove
numZoomLevels = 0;
zoomPixelData = NULL;
// Allocate space for the bitmap info
bmInfo = (BITMAPINFO*)new char[sizeof(*bmInfo)+sizeof(RGBQUAD)*256];
if (bmInfo == NULL)
throw L"Out of memory";
// Clear bitmap info header
memset(bmInfo, 0, sizeof(bmInfo->bmiHeader)+sizeof(RGBQUAD)*256);
// Initialize fields
bmInfo->bmiHeader.biSize = sizeof(bmInfo->bmiHeader);
bmInfo->bmiHeader.biBitCount = bitDepth;
bmInfo->bmiHeader.biWidth = width;
bmInfo->bmiHeader.biHeight = -headInfo.height;
bmInfo->bmiHeader.biPlanes = 1;
if (bitDepth <= 8) bmInfo->bmiHeader.biClrUsed = 1 << bitDepth;
// Create the DIB section to hold the bitmap pixel data
tileSet = CreateDIBSection(NULL, bmInfo, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0);
if (tileSet == NULL)
{
// Release the bitmap info structure
delete [] bmInfo;
throw L"Could not create DIB section";
}
// Initialize the bitmap pixel data
GdiFlush();
memset(pixelData, 0, sizeOfPixelData);
Refresh(); // Update memory Device Context and reselect the DIB section
// Allocate space for zoomed pixel data // **TODO**
g_cLocks++;
}
CTileSet::CTileSet(StreamReader *stream) : m_cRef(1)
{
// Initialize variables
pixelData = NULL;
memDC = NULL;
sizeOfPixelData = 0;
scanlineByteWidth = 0;
tileSet = NULL;
miniMapColors = NULL;
numZoomLevels = 0;
zoomPixelData = NULL;
// Allocate space for bitmap info
bmInfo = (BITMAPINFO*) new char[sizeof(*bmInfo) + sizeof(RGBQUAD)*256];
// Load tile set from stream
if (LoadTileSet(stream) != 0)
{
// Error loading tile set from stream
FreeMemory();
throw L"CTileSet: Error loading tile set data."; // Return error
}
Refresh(); // Update memory Device Context and reselect the DIB section
g_cLocks++;
}
// Destructor
// **********
CTileSet::~CTileSet()
{
g_cLocks--;
FreeMemory();
}
// Cleanup Function
// ****************
void CTileSet::FreeMemory()
{
if (bmInfo != NULL)
delete [] (char*)bmInfo;
if (miniMapColors != NULL)
delete [] miniMapColors;
if (zoomPixelData != NULL)
delete [] zoomPixelData;
// Free drawing resources
if (memDC != 0)
{
// Restore the original bitmap that DC was created with
tileSet = (HBITMAP)SelectObject(memDC, originalBm);
DeleteObject(tileSet); // Delete the cached compatible bitmap
DeleteDC(memDC); // Free the memory DC
}
else if(tileSet != 0)
DeleteObject(tileSet); // Only the tileSet object existed
}
// TileSet Loading/Saving functions
// ********************************
// Returns 0 on success, and nonzero on failure
int CTileSet::LoadTileSet(StreamReader *stream)
{
int numSectionsLeft = -2;
int numSectionsLeftInner = -2;
int numBytesRead;
int status;
unsigned int i, temp;
SectionHeader sectHead;
// Initialize bitmap drawing structures
memset(&bmInfo->bmiHeader, 0, sizeof(bmInfo->bmiHeader));
bmInfo->bmiHeader.biSize = sizeof(bmInfo->bmiHeader);
bmInfo->bmiHeader.biPlanes = 1;
bmInfo->bmiHeader.biCompression = BI_RGB;
try
{
do
{
numSectionsLeft--;
// Read in a section tag
stream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
// Check for errors reading
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read section header."; // Failed. Error reading stream.
// Check for bitmap file header
if ((sectHead.tag & 0xFFFF) == 'MB') // BM
return LoadBitmapFile(stream);
// Determine how to process the following section
switch(sectHead.tag)
{
case 'PMBP': // PBMP
// No special processing. Ignore tag.
break;
case 'LAPP': // PPAL
// Second level processing
do
{
numSectionsLeftInner--;
// Read in a section tag
stream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
// Check for read errors
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read section header. (PPAL inner processing)"; // Failed. Read error.
// Determine how to process the following section
switch(sectHead.tag)
{
case 'LAPP': // PPAL
// No special processing
break;
case 'FFIR': // RIFF
// **TODO** implement
break;
case 'daeh': // head
// Check for format errors
if (sectHead.size != 4)
{
OutputDebugStringW(L"Format Error. Palette head section doesn't have size 4.");
// Format error. Section header following PPAL tag doesn't have size 4.
throw L"Format Error. Palette head section doesn't have size 4."; // Failed. Format error.
}
// Read number of sections left
stream->Read(4, (int)&numSectionsLeftInner, &numBytesRead);
// Check for read errors
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read number of sections left. (PPAL inner processing)"; // Failed. Read error.
break;
case 'atad': // data
// Check for format errors
// Check if palette data section already read
if (bmInfo->bmiHeader.biClrUsed != 0)
{
// **Warning** Format error. Only one data section for palette allowed
OutputDebugStringW(L"Format Error. Second palette data section found.");
}
// Check if palette data is the wrong size
if (sectHead.size > 4*256)
{
OutputDebugStringW(L"Format error. Palette data section is too large.");
throw L"Format Error. Palette data section is too large. (More than 256 entries)"; // Failed. Format error. Palette data should contain no more than 256 entries.
}
// Determine number of palette entries used (round down to RGBQUAD size)
bmInfo->bmiHeader.biClrUsed = sectHead.size >> 2;
// Read in the palette data
stream->Read(sectHead.size, (int)&bmInfo->bmiColors, &numBytesRead);
// Check for read errors
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read in palette data."; // Failed. Read error.
// Adjust palette color component positions (RGB <-> BGR)
for (i = 0; i < bmInfo->bmiHeader.biClrUsed; i++)
{
// Swap the Red and Blue components
temp = bmInfo->bmiColors[i].rgbRed;
bmInfo->bmiColors[i].rgbRed = bmInfo->bmiColors[i].rgbBlue;
bmInfo->bmiColors[i].rgbBlue = temp;
}
break;
case 'lpsp': // pspl
// **TODO** implement
break;
case 'lptp': // ptpl
// **TODO** implement
break;
default:
// Unknown tag. Ignore.
break;
}
} while (numSectionsLeftInner);
break;
case 'atad': // data
// Check for format errors
// Check for multiple pixel data sections
if (sizeOfPixelData != 0)
throw L"Format Error. More than one pixel data section found."; // Failed. More than one pixel data section was found.
// Check for a valid bitmap width
if (scanlineByteWidth == 0)
throw L"Format Error. No valid bitmap width was specified before pixel data was found."; // Failed. Format error. No valid bitmap width was specified before the pixel data.
// Check for non integral tile size multiples
if (sectHead.size != headInfo.height*scanlineByteWidth)
throw L"Format Error. Non integral tile size multiple."; // Failed. Format error. Pixel data size is not an integral multiple of the dimensions.
// Record size of pixel data
sizeOfPixelData = sectHead.size;
// Create the DIB section to hold the bitmap pixel data
tileSet = CreateDIBSection(NULL, bmInfo, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0);
// Check for errors
if (tileSet == NULL)
throw L"Error. Failed to create a DIB section to store bitmap.";
// Read in the pixel data
GdiFlush();
stream->Read(sectHead.size, (int)pixelData, &numBytesRead);
// Check for read errors
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read pixel data."; // Failed. Read error.
break;
case 'daeh': // head
// Check for format errors
if (sectHead.size != sizeof(headInfo)+4)
{
OutputDebugStringW(L"Format Error. PBMP head section has an invalid size.");
// Failed! Format error. Section header info wrong size, will overflow buffer if too big.
// Danger to Outpost2.exe. Possible exploit.
throw L"Format Error. PBMP head section size is invalid. **Possible Exploit**"; // Failed. Format error.
}
// Read the number of section remaining
stream->Read(4, (int)&numSectionsLeft, &numBytesRead);
// Check for read errors
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read number of sections left."; // Failed. Read error.
// Read in the header data
stream->Read(sectHead.size-4, (int)&headInfo, &numBytesRead);
// Check for read errors
stream->get_Status(&status);
if (status)
throw L"Read Error. Could not read pixel header data."; // Failed. Read error.
// Calculate the number of bytes in each scanline
scanlineByteWidth = ((headInfo.width * headInfo.bitDepth + 31) & ~31) >> 3;
// Update bitmap header info
bmInfo->bmiHeader.biBitCount = headInfo.bitDepth;
bmInfo->bmiHeader.biWidth = headInfo.width;
bmInfo->bmiHeader.biHeight = -headInfo.height;
break;
default:
// Unknown tag. Ignore.
break;
}
} while (numSectionsLeft); // Loop while sections are still expected
if (scanlineByteWidth*headInfo.width == 0)
throw L"Format Error. Invalid dimensions given.";
// Calculate number of tiles in tile set. Note: assumes tiles are square
numberOfTiles = sizeOfPixelData / (scanlineByteWidth*headInfo.width);
// **TODO** Update this, remove old code, add zoomPixelData code
// Allocate space for minimap colors
miniMapColors = new RGBQUAD[numberOfTiles];
// Calcaulate the minimap colors
CalcMiniMapColors(0, numberOfTiles-1);
}
catch(WCHAR *errorMsg)
{
PostErrorMsg(errorMsg);
return 1; // Error
}
catch(...)
{
return 1; // Error
}
return 0; // Success
}
int CTileSet::SaveTileSet(StreamWriter *stream)
{
SectionHeader sectHead;
int numBytesWritten;
int numSectionsLeft;
unsigned int i;
RGBQUAD tempPal[256];
RGBQUAD *srcPal, *destPal;
// Write the file header "PBMP" section
sectHead.tag = 'PMBP'; // PBMP tag
sectHead.size = sizeof(sectHead)*4 + sizeOfPixelData + sizeof(headInfo) + 8 +
bmInfo->bmiHeader.biClrUsed*sizeof(RGBQUAD);
numSectionsLeft = 2; // Number of sections (palette, and pixel data)
// Check if palette section is needed
if (bmInfo->bmiHeader.biClrUsed == 0)
{
numSectionsLeft = 1; // No palette section needed
// No headers for palette section needed
sectHead.size = sizeof(sectHead) + sizeOfPixelData + sizeof(headInfo) + 4;
}
stream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
// Write the "head" section of the "PBMP" section
sectHead.tag = 'daeh'; // head tag
sectHead.size = sizeof(headInfo) + 4;
stream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
stream->Write(4, (int)&numSectionsLeft, &numBytesWritten);
stream->Write(sizeof(headInfo), (int)&headInfo, &numBytesWritten);
// Check if a palette needs to be written
if (bmInfo->bmiHeader.biClrUsed != 0)
{
// Write the Palette section
sectHead.tag = 'LAPP'; // PPAL tag
sectHead.size = bmInfo->bmiHeader.biClrUsed*sizeof(RGBQUAD) +
sizeof(sectHead)*2 + 8;
stream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
// Write the "head" section of the "PPAL" section
sectHead.tag = 'daeh'; // head tag
sectHead.size = 4;
numSectionsLeft = 1;
stream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
stream->Write(4, (int)&numSectionsLeft, &numBytesWritten);
// Write the "data" section of the "PPAL" section
sectHead.tag = 'atad'; // data tag
sectHead.size = bmInfo->bmiHeader.biClrUsed*sizeof(RGBQUAD);
stream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
// Convert palette to format used for storage
for (i = 0; i < bmInfo->bmiHeader.biClrUsed; i++)
{
srcPal = &bmInfo->bmiColors[i];
destPal = &tempPal[i];
destPal->rgbRed = srcPal->rgbBlue;
destPal->rgbGreen = srcPal->rgbGreen;
destPal->rgbBlue = srcPal->rgbRed;
destPal->rgbReserved = srcPal->rgbReserved;
}
stream->Write(bmInfo->bmiHeader.biClrUsed*sizeof(RGBQUAD),
(int)&tempPal, &numBytesWritten);
}
// Write the "data" section of the "PBMP" section
sectHead.tag = 'atad'; // data tag
sectHead.size = sizeOfPixelData;
stream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
stream->Write(sizeOfPixelData, (int)pixelData, &numBytesWritten);
return 0; // Success
}
// Bitmap loading/saving functions
// *******************************
int CTileSet::LoadBitmapFile(StreamReader *stream)
{
BITMAPFILEHEADER bmFileHeader;
int numBytesRead;
// Skip over rest of the BITMAPFILEHEADER
// Note: First 8 bytes of file were already read
stream->Read(sizeof(bmFileHeader)-8, (int)&bmFileHeader+8, &numBytesRead);
// Read the BITMAPINFOHEADER
stream->Read(sizeof(bmInfo->bmiHeader), (int)&bmInfo->bmiHeader, &numBytesRead);
// Determine if a palette needs to be read in
if (bmInfo->bmiHeader.biBitCount <= 8)
{
if (bmInfo->bmiHeader.biClrUsed == 0)
bmInfo->bmiHeader.biClrUsed = 1 << bmInfo->bmiHeader.biBitCount;
// Read in the palette data
stream->Read(sizeof(RGBQUAD)*bmInfo->bmiHeader.biClrUsed, (int)&bmInfo->bmiColors[0], &numBytesRead);
}
// Update header info
headInfo.bitDepth = bmInfo->bmiHeader.biBitCount;
headInfo.width = bmInfo->bmiHeader.biWidth;
headInfo.height = bmInfo->bmiHeader.biHeight;
if (headInfo.height < 0)
headInfo.height = -headInfo.height;
// Calculate the number of bytes in each scanline
scanlineByteWidth = ((headInfo.width * headInfo.bitDepth + 31) & ~31) >> 3;
// Calculate total bitmap size
sizeOfPixelData = scanlineByteWidth * headInfo.height;
// Create the DIB section to hold the bitmap pixel data
tileSet = CreateDIBSection(NULL, bmInfo, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0);
// Read in the pixel data
stream->Read(sizeOfPixelData, (int)pixelData, &numBytesRead);
// Calculate number of tiles in tile set. Note: assumes tiles are square
numberOfTiles = sizeOfPixelData / (scanlineByteWidth*headInfo.width);
// Allocate space for minimap colors
miniMapColors = new RGBQUAD[numberOfTiles];
// Calcaulate the minimap colors
CalcMiniMapColors(0, numberOfTiles-1);
return 0; // Success
}
int CTileSet::SaveBitmapFile(StreamWriter *stream)
{
BITMAPFILEHEADER bmFileHeader;
int numBytesWritten;
// Preapre the bitmap file header
bmFileHeader.bfType = 'MB'; // "BM"
bmFileHeader.bfSize = sizeof(bmFileHeader) + sizeof(bmInfo->bmiHeader) +
sizeof(RGBQUAD)*bmInfo->bmiHeader.biClrUsed + sizeOfPixelData;
bmFileHeader.bfReserved1 = 0;
bmFileHeader.bfReserved2 = 0;
bmFileHeader.bfOffBits = bmFileHeader.bfSize - sizeOfPixelData;
// Write out the bitmap file header
stream->Write(sizeof(bmFileHeader), (int)&bmFileHeader, &numBytesWritten);
// Write out the BITMAPINFOHEADER
stream->Write(sizeof(bmInfo->bmiHeader), (int)&bmInfo->bmiHeader, &numBytesWritten);
// Write out the palette, if it exists
if (bmInfo->bmiHeader.biBitCount <= 8)
{
// Write out the palette data
stream->Write(sizeof(RGBQUAD)*bmInfo->bmiHeader.biClrUsed, (int)&bmInfo->bmiColors[0], &numBytesWritten);
}
// Write out the pixel data
stream->Write(sizeOfPixelData, (int)pixelData, &numBytesWritten);
return 0; // Success
}
// **TODO** Remove
void CTileSet::CalcMiniMapColors(int startTile, int endTile)
{
int tileByteSize = scanlineByteWidth*headInfo.width; // Note: assume square tiles
int tilePixelSize = headInfo.width*headInfo.width;
int pixelDataOffset;
RGBQUAD *rgbQuad;
int red, green, blue;
int tileNum, x, y;
int temp;
// Calculate minimap color of all tiles in given range
for (tileNum = startTile; tileNum <= endTile; tileNum++)
{
// Initialize color components
red = green = blue = 0;
// Calculate the minimap color of this tile (sum over all pixels in tile)
for (y = 0; y < headInfo.width; y++) // Note: assume square tiles
{
for (x = 0; x < headInfo.width; x++)
{
// Add the color components of this pixel
pixelDataOffset = tileNum*tileByteSize +
y*scanlineByteWidth +
((x*headInfo.bitDepth) >> 3);
switch(headInfo.bitDepth)
{
case 8:
temp = pixelData[pixelDataOffset];
rgbQuad = &bmInfo->bmiColors[temp];
// FIX: flip R and B colors around (they are stored backwards!)
//red += rgbQuad->rgbRed;
red += rgbQuad->rgbBlue;
green += rgbQuad->rgbGreen;
//blue += rgbQuad->rgbBlue;
blue += rgbQuad->rgbRed;
break;
case 16: // Assume 5/5/5 for RGB components **TODO** test this code
temp = *(short*)(pixelData+pixelDataOffset);
blue += (temp & 0x1F) << 3;
green += (temp & 0x3E0) >> 2;
red += (temp & 0x7C00) >> 7;
break;
default:
// Do nothing. Pixels will appear black
break;
}
}
}
// Scale color components by the number of pixels in the tile
red /= tilePixelSize;
green /= tilePixelSize;
blue /= tilePixelSize;
// Store the tile minimap color
rgbQuad = &miniMapColors[tileNum];
rgbQuad->rgbRed = red;
rgbQuad->rgbGreen = green;
rgbQuad->rgbBlue = blue;
rgbQuad->rgbReserved = 0;
}
}
// Update the drawing cache. This will refresh the memory DC to match the screen (in case
// a mode change has occured) and reselect the bitmap for drawing.
void CTileSet::Refresh()
{
// Check if a memory Device Context already exists
if (memDC)
{
// Delete the old Device Context
tileSet = (HBITMAP)SelectObject(memDC, originalBm);
DeleteDC(memDC);
}
// Create a new memory Device Context and select the bitmap
memDC = CreateCompatibleDC(NULL); // NULL - makes DC compatible with current screen
originalBm = (HBITMAP)SelectObject(memDC, tileSet);
}
int CTileSet::InitializeZoomBuffers()
{
int i;
int size;
// Calculate size of largest zoom buffer
numZoomLevels = LogBase2(headInfo.width);
size = (1 << (numZoomLevels << 1)) * 3;
// Allocate zoom buffer array
zoomPixelData = new char*[numZoomLevels];
if (zoomPixelData == NULL) return -1; // Error (Out of memory)
for (i = 0; i < numZoomLevels; i++)
{
// Allocate buffer space
zoomPixelData[i] = new char[size];
// Check for errors
if (zoomPixelData[i] == NULL)
{
// Failed to allocate memory. Release what we've already obtained and abort
for (i--; i >= 0; i--)
{
// Release the already obtained buffer
delete [] zoomPixelData[i];
}
// Release the array of buffer pointers
delete [] zoomPixelData;
zoomPixelData = NULL;
return -1; // Error (Out of memory)
}
// Adjust size to allocate for next iteration
size >>= 2;
}
// Initialize all the buffers
CalcZoomPixelData(0, numberOfTiles);
return 0; // Success
}
void CTileSet::CalcZoomPixelData(int startTile, int numTiles)
{
int i;
int startPixel;
int numPixels;
// Find the starting pixel to calculate zoom colors for
startPixel = startTile * headInfo.width * headInfo.width;
// Calculate the number of pixels we need to process at largest level
numPixels = numTiles * headInfo.width * headInfo.width;
// Copy data for the upper level
switch(headInfo.bitDepth)
{
case 8: // 8 bpp
for (i = startPixel; i < numPixels; i++)
{
// Lookup the palette index of the pixel
}
break;
default: // **TODO** Handle more cases
// Unhandled case. Abort.
return;
}
// Recurse for lower levels
}

View File

@ -0,0 +1,125 @@
#include "OP2Editor.h"
class CTileSet : public TileSet
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// ITileSet
// [propget]
HRESULT STDMETHODCALLTYPE get_NumTiles(
/* [retval][out] */ int __RPC_FAR *numTiles);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSize(
/* [retval][out] */ int __RPC_FAR *tileSize);
// [propget]
HRESULT STDMETHODCALLTYPE get_BitDepth(
/* [retval][out] */ int __RPC_FAR *bitDepth);
// [propget]
HRESULT STDMETHODCALLTYPE get_NumPaletteEntries(
/* [retval][out] */ int __RPC_FAR *numPaletteEntries);
// [propget]
HRESULT STDMETHODCALLTYPE get_PaletteEntry(
/* [in] */ int index,
/* [retval][out] */ int __RPC_FAR *palEntry);
// [propput]
HRESULT STDMETHODCALLTYPE put_PaletteEntry(
/* [in] */ int index,
/* [in] */ int palEntry);
HRESULT STDMETHODCALLTYPE SetNumTiles(
/* [in] */ int numTiles);
// Returns pixel data in native format (as stored in file)
// [local]
HRESULT STDMETHODCALLTYPE GetPixelData(
/* [in] */ int pBuffer,
/* [in] */ int startOffset,
/* [in] */ int numBytes);
// Sets pixel data in native format (as stored in file)
// [local]
HRESULT STDMETHODCALLTYPE SetPixelData(
/* [in] */ int pBuffer,
/* [in] */ int startOffset,
/* [in] */ int numBytes);
// [propget] // **TODO** Remove
HRESULT STDMETHODCALLTYPE get_MiniMapColors(
/* [in] */ int tileIndex,
/* [retval][out] */ int __RPC_FAR *color);
HRESULT STDMETHODCALLTYPE PasteTile(
/* [in] */ int destDC,
/* [in] */ int pixelX,
/* [in] */ int pixelY,
/* [in] */ int tileNum);
HRESULT STDMETHODCALLTYPE SaveTileSet(
/* [in] */ StreamWriter __RPC_FAR *stream,
/* [in] */ enum TileSetSaveFormat saveFormat);
// Class specific
CTileSet(int numTiles = 1, int bitDepth = 8, int width = 32); // Create a new empty tile set
CTileSet(StreamReader *stream); // Create a new tile set loaded from a stream
~CTileSet(); // Release tile set resources
private:
ULONG m_cRef; // COM object reference count
// Class specific structures
// *************************
#pragma pack(push, 1) // Make sure structures are byte aligned
// File section header tag
struct SectionHeader
{
int tag; // Section name: char tag[4];
int size; // Number of bytes in this section
};
// Header info loaded from tile set file
struct HeaderInfo
{
int width; // The width of the bitmap in pixels (Note: tiles are square)
int height; // Height of all tiles (stacked on top of each other)
int bitDepth; // Bit depth of the pixel data
int flags; // Tile set file flags
};
#pragma pack(pop)
// Class specific functions
// ************************
int LoadTileSet(StreamReader *stream);
int LoadBitmapFile(StreamReader *stream);
int SaveBitmapFile(StreamWriter *stream);
int SaveTileSet(StreamWriter *stream);
void CalcMiniMapColors(int startTile, int endTile); // **TODO** Remove
int InitializeZoomBuffers();
void CalcZoomPixelData(int startTile, int numTiles);
void Refresh();
void FreeMemory();
// Class specific data
// *******************
HeaderInfo headInfo;
int numberOfTiles;
int sizeOfPixelData;
int scanlineByteWidth;
unsigned char *pixelData;
RGBQUAD *miniMapColors; // **TODO** phase this out
BITMAPINFO zoomInfo; // Info describing the zoomed pixel data format
int numZoomLevels;
char **zoomPixelData;
BITMAPINFO *bmInfo;
HDC memDC;
HBITMAP tileSet;
HBITMAP originalBm;
};

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,340 @@
class CTileSetManager : public TileSetManager, public ISupportErrorInfo
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// ISupportErrorInfo
// *****************
HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(REFIID riid);
// TileSetManager
// **************
// [propget]
HRESULT STDMETHODCALLTYPE get_NumTileSets(
/* [retval][out] */ int __RPC_FAR *numTileSets);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSetName(
/* [in] */ int index,
/* [retval][out] */ BSTR __RPC_FAR *tileSetName);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSet(
/* [in] */ int index,
/* [retval][out] */ TileSet __RPC_FAR *__RPC_FAR *tileSet);
HRESULT STDMETHODCALLTYPE AddTileSet(
/* [in] */ BSTR tileSetName,
/* [retval][out] */ int __RPC_FAR *index);
HRESULT STDMETHODCALLTYPE RemoveTileSet(
/* [in] */ BSTR tileSetName,
/* [retval][out] */ int __RPC_FAR *index);
HRESULT STDMETHODCALLTYPE ReplaceTileSet(
/* [in] */ int index,
/* [in] */ BSTR tileSetName);
HRESULT STDMETHODCALLTYPE MapInTiles(
/* [in] */ int tileSetIndex,
/* [in] */ int startTile,
/* [in] */ int numTiles,
/* [retval][out] */ int __RPC_FAR *mappingIndex);
HRESULT STDMETHODCALLTYPE GetMappingIndex(
/* [in] */ int tileSetIndex,
/* [in] */ int tileIndex,
/* [in] */ int numTileReplacements,
/* [in] */ int cycleDelay,
/* [retval][out] */ int __RPC_FAR *mappingIndex);
// [propget]
HRESULT STDMETHODCALLTYPE get_NumMappings(
/* [retval][out] */ int __RPC_FAR *numMappings);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSetIndex(
/* [in] */ int mappingIndex,
/* [retval][out] */ int __RPC_FAR *tileSetIndex);
// [propput]
HRESULT STDMETHODCALLTYPE put_TileSetIndex(
/* [in] */ int mappingIndex,
/* [in] */ int tileSetIndex);
// [propget]
HRESULT STDMETHODCALLTYPE get_TileSetTileIndex(
/* [in] */ int mappingIndex,
/* [retval][out] */ int __RPC_FAR *tileSetTileIndex);
// [propput]
HRESULT STDMETHODCALLTYPE put_TileSetTileIndex(
/* [in] */ int mappingIndex,
/* [in] */ int tileSetTileIndex);
// [propget]
HRESULT STDMETHODCALLTYPE get_NumTileReplacements(
/* [in] */ int mappingIndex,
/* [retval][out] */ int __RPC_FAR *numTileReplacements);
// [propput]
HRESULT STDMETHODCALLTYPE put_NumTileReplacements(
/* [in] */ int mappingIndex,
/* [in] */ int numTileReplacements);
// [propget]
HRESULT STDMETHODCALLTYPE get_CycleDelay(
/* [in] */ int mappingIndex,
/* [retval][out] */ int __RPC_FAR *cycleDelay);
// [propput]
HRESULT STDMETHODCALLTYPE put_CycleDelay(
/* [in] */ int mappingIndex,
/* [in] */ int cycleDelay);
// [propget]
HRESULT STDMETHODCALLTYPE get_NumTerrains(
/* [retval][out] */ int __RPC_FAR *numTerrains);
HRESULT STDMETHODCALLTYPE SetNumTerrains(
/* [in] */ int numTerrains);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainStartTile(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *startMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainStartTile(
/* [in] */ int terrainIndex,
/* [in] */ int startMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainEndTile(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *endMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainEndTile(
/* [in] */ int terrainIndex,
/* [in] */ int endMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainDozed(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainDozed(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainRubble(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainRubble(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainTubeUnk(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainTubeUnk(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainLavaWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainLavaWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainMicrobeWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainMicrobeWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainNormalWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainNormalWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainDamagedWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainDamagedWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainRuinedWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainRuinedWall(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainLava(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainLava(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainFlat1(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainFlat1(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainFlat2(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainFlat2(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainFlat3(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainFlat3(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainTube(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainTube(
/* [in] */ int terrainIndex,
/* [in] */ enum TerrainTubeDirection direction,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainScorched(
/* [in] */ int terrainIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainScorched(
/* [in] */ int terrainIndex,
/* [in] */ int dataMapping);
// [propget]
HRESULT STDMETHODCALLTYPE get_TerrainUnknown(
/* [in] */ int terrainIndex,
/* [in] */ int unkIndex,
/* [retval][out] */ int __RPC_FAR *dataMapping);
// [propput]
HRESULT STDMETHODCALLTYPE put_TerrainUnknown(
/* [in] */ int terrainIndex,
/* [in] */ int unkIndex,
/* [in] */ int dataMapping);
// Class specific
// **************
CTileSetManager(TileSetSource *tileSetSource);
CTileSetManager(TileSetSource *tileSetSource, int numTileSets, StreamReader *inStream);
~CTileSetManager();
private:
ULONG m_cRef;
// Friend class for fast access to data needed to draw a view of the map
friend class CMapFile;
friend class CTileGroup;
#pragma pack(push, 1)
struct TileSetInfo
{
int numTiles; // Number of tiles in this tile set
int stringLength; // Length of the tileSetName string
char *tileSetName; // File name of the tile set, as Outpost2 sees it
BSTR wideTileSetName; // BSTR copy of the tile set name (cached for use with COM)
TileSet *tileSet; // A pointer to a tile set object
};
struct TileSetTileMapping
{
short tileSetIndex;
short tileIndex;
short numTileReplacements;
short cycleDelay;
};
struct TerrainTypeItemTable // Holds sets of related tiles
// LavaWalls/MicrobeWalls/NormalWalls/DamagedWalls/ReallyDamagedWalls/Tubes
{
short tile[0x10]; // tile for each direction facing
};
struct TerrainType
{
short firstTile; // First tile index in this terrain type class
short lastTile; // Last tile index in this terrain type class
short bulldozed; // Index of the bulldozed tile
short commonRubble; // Index of the common rubble tile (4 common rubble tiles, followed by 4 rare rubble tiles)
short tubeUnknown[6]; // **TODO** find out use of this (data is repeated below)
TerrainTypeItemTable wall[5]; // Wall groups
short lava;
short flat1;
short flat2;
short flat3;
TerrainTypeItemTable tube; // Tube group
short scorched; // Scorched tile index (from vehicle explosion)
short unknown[0x15]; // **TODO** find out
};
#pragma pack(pop)
// Private functions
// *****************
int Save(StreamWriter *stream);
int Load(StreamReader *stream);
void FreeMemory();
// Private variables
// *****************
TileSetSource *tileSource; // Used to load tile sets
int numTileSets; // Number of loaded tile sets
TileSetInfo *tileSetInfo; // List of loaded tile sets
int numMappings; // Number of tile mappings in the tile mapping array
TileSetTileMapping *mapping; // Tile set tile mapping array
int numTerrains; // Number of terrain types in the terrain type array
TerrainType *terrain; // Tarrain type array
// Private constant used for tile set loading/saving
static const char tagTileSet[];
};

View File

@ -0,0 +1,204 @@
#include "stdafx.h"
#include "CTileSetSource.h"
extern int g_cLocks;
ULONG __stdcall CTileSetSource::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CTileSetSource::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CTileSetSource::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_TileSetSource)
*ppv = (TileSetSource*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
CTileSetSource::CTileSetSource(IResourceManager *resourceManager) : m_cRef(1)
{
head = NULL; // Initialize linked list of loaded files to empty
resManager = resourceManager; // CTileSetSource is owned by IResourceManager
// so the reference count should not be incremented
// (Don't want circular references)
g_cLocks++;
}
CTileSetSource::~CTileSetSource()
{
LinkedListNode *current, *next;
g_cLocks--;
current = head;
// Traverse each node
while (current)
{
// Get the next node in the list
next = current->next;
// Free the tile set
current->tileSet->Release();
// Free the tile set name BSTR
SysFreeString(current->tileSetName);
// Delete the current node
delete current;
current = next;
}
}
// TileSetSource functions
// ***********************
HRESULT CTileSetSource::LoadTileSet(BSTR tileSetName, TileSet **tileSet)
{
LinkedListNode *current;
StreamReader *stream;
TileSet *newTileSet;
LinkedListNode *newNode;
BSTR tempName;
unsigned int lenString;
HRESULT hr;
*tileSet = NULL; // Initialize return pointer to NULL
// Cache string length
lenString = SysStringLen(tileSetName);
current = head;
// Search linked list for already loaded copy
while (current)
{
// Check if tile set names match
if ( (lenString == SysStringLen(current->tileSetName))
&& (memcmp(tileSetName, current->tileSetName, lenString*2) == 0) )
{
// Update the count
current->loadedCount++;
// Return a copy of the tile set
*tileSet = current->tileSet;
(*tileSet)->AddRef();
return S_OK;
}
// process next node in list
current = current->next;
}
// Add the ".bmp" extension
tempName = SysAllocStringLen(NULL, lenString+4);
memcpy(tempName, tileSetName, lenString*2);
memcpy((char*)tempName + lenString*2, L".bmp", 8);
// Tile set not found in list. Try to find the file
resManager->OpenStreamRead(tempName, &stream);
SysFreeString(tempName);
// Check if the resource could not be opened
if (stream == NULL)
return E_FAIL;
try
{
// Resource was found and opened. Read in the tile set
newTileSet = (TileSet*) new CTileSet(stream);
}
catch(...)
{
// Error loading tile set from stream
stream->Release();
return E_FAIL;
}
// Release the stream
stream->Release();
// Check if the object was constructed properly
if (newTileSet == NULL)
return E_OUTOFMEMORY;
// Create a new linked list node
newNode = new LinkedListNode;
if (newNode == NULL)
{
newTileSet->Release();
return E_OUTOFMEMORY;
}
hr = newTileSet->QueryInterface(IID_TileSet, (void**)&newNode->tileSet);
if (FAILED(hr))
{
delete newNode;
newTileSet->Release();
return hr;
}
newNode->loadedCount = 1;
newNode->tileSetName = SysAllocString(tileSetName);
// Add the tile set to the linked list
newNode->next = head;
head = newNode;
// Return a copy of the tile set
(*tileSet) = newNode->tileSet;
return hr;
}
HRESULT CTileSetSource::UnloadTileSet(BSTR tileSetName)
{
LinkedListNode *current;
// Find the node in the linked list
current = head;
while (current)
{
// Check if tile set names match
if ( (SysStringLen(tileSetName) == SysStringLen(current->tileSetName))
&& (memcmp(tileSetName, current->tileSetName, SysStringByteLen(tileSetName)) == 0) )
{
// Decrement the count
current->loadedCount--;
// Note: Don't free the tile set here since it may likely be loaded again soon
// **TODO** Handle this possible optimization
if (current->loadedCount == 0)
{
// Unload the tile set and remove the node from the linked list
//current->tileSet->Release();
}
return S_OK;
}
// process next node in list
current = current->next;
}
// Node not found. Ignore.
return S_OK;
}

View File

@ -0,0 +1,41 @@
#include "OP2Editor.h"
#include "CTileSet.h"
class CTileSetSource : public TileSetSource
{
public:
// IUnknown
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// TileSetSource
HRESULT STDMETHODCALLTYPE LoadTileSet(
/* [in] */ BSTR tileSetName,
/* [retval][out] */ TileSet __RPC_FAR *__RPC_FAR *tileSet);
HRESULT STDMETHODCALLTYPE UnloadTileSet(
/* [in] */ BSTR __RPC_FAR tileSetName);
// Class specific functions
CTileSetSource(IResourceManager *resourceManager);
~CTileSetSource();
private:
ULONG m_cRef; // COM object reference count
// Class internal structures
struct LinkedListNode
{
LinkedListNode *next;
TileSet *tileSet;
BSTR tileSetName;
int loadedCount;
};
// Class specific variables
LinkedListNode *head;
IResourceManager *resManager; // Resource manager used to find and open tile set files
};

View File

@ -0,0 +1,428 @@
#include "stdafx.h"
#include "CVolReader.h"
#include "CMemoryStreamReader.h"
#include "GlobalFunctions.h"
extern int g_cLocks;
ULONG __stdcall CVolReader::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CVolReader::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CVolReader::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_ArchiveReader)
*ppv = (ArchiveReader*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// ArchiveReader
// *************
HRESULT CVolReader::get_NumFiles(int *numFiles)
{
*numFiles = this->numFiles;
return S_OK;
}
HRESULT CVolReader::get_FileName(int index, BSTR *fileName)
{
char *string;
int stringLength;
// Cache string address
string = (char*)stringBuffer + indexTable[index].fileNameOffset;
stringLength = strlen(string);
// Allocate space for the string
SysReAllocStringLen(fileName, NULL, stringLength);
// Convert the string to Unicode
MultiByteToWideChar(CP_ACP, 0, string, stringLength,
*fileName, stringLength);
return S_OK;
}
HRESULT CVolReader::OpenStreamRead(BSTR fileName, StreamReader **stream)
{
int fileIndex;
HRESULT hr;
int bAttachToBuffer = 0;
LPVOID buffer;
// Initialize returned stream pointer to NULL
*stream = NULL;
// Lookup the filename in the index
fileIndex = GetFileIndex(fileName);
// Check if the file was not found
if (fileIndex == -1)
{
// File was not found
PostErrorMsg(L"File not found in archive.");
return E_INVALIDARG;
}
// Store a pointer to the data buffer
buffer = dataBuffer[fileIndex];
// Check if data is loaded into memory
if (buffer == NULL)
{
// Data is not loaded into memory.
// Check if attached stream does not exist
if (attachedStream == NULL)
{
// No data source. Failed.
PostErrorMsg(L"No data source.");
return E_FAIL;
}
// Load the data from the stream
// *****************************
SectionHeader sectHead;
int numBytesRead;
// Seek to begining of internal file data
attachedStream->Seek(streamStartOffset + indexTable[fileIndex].dataOffset);
// Read the "VBLK" section header
attachedStream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
if (sectHead.tag != 'KLBV') // "VBLK"
{
PostErrorMsg(L"Invalid format. VBLK not found.");
return E_FAIL; // Error. Format error.
}
//if (sectHead.sectionSize != indexTable[fileIndex].fileSize)
// return 1; // Error. Format error.
// Allocate space for the file data
buffer = new char[sectHead.sectionSize];
// Read the file data
attachedStream->Read(sectHead.sectionSize, (int)buffer, &numBytesRead);
// Mark the buffer as discardable
bAttachToBuffer = 1;
}
try
{
// Determine which type of stream reader to construct to read the file
switch(indexTable[fileIndex].encoding)
{
case 0: // Raw uncompressed data
// Copy the data into a memory stream
CMemoryStreamReader *rawStream;
rawStream = new CMemoryStreamReader(indexTable[fileIndex].fileSize,
(char*)buffer,
bAttachToBuffer);
if (rawStream == NULL)
{
if (bAttachToBuffer == 1)
delete [] buffer; // Delete discardable buffer
PostErrorMsg(L"Could not create memory stream reader. Out of memory.");
return E_OUTOFMEMORY;
}
hr = rawStream->QueryInterface(IID_StreamReader, (void**)stream);
rawStream->Release();
return hr;
break;
case 1: // Unknown **TODO** Find out
break;
case 2: // Unknown **TODO** Find out
break;
case 3: // AdaptiveHuffman+RepeatedBlocks
// **TODO** Implement
break;
default:
// **TODO** Implement
break;
}
}
catch(...)
{
// Failed to create a StreamReader object
// Check if buffer is discardable
if (bAttachToBuffer == 1)
delete [] buffer;
PostErrorMsg(L"Could not create memory stream reader.");
return E_FAIL;
}
// Failed to open the stream
if (bAttachToBuffer == 1)
delete [] buffer; // Release the discardable buffer
PostErrorMsg(L"Could not open stream.");
return E_FAIL;
}
// Class specific
// **************
CVolReader::CVolReader(SeekableStreamReader *inStream, int bAttachToStream) : m_cRef(1)
{
numFiles = 0;
stringBuffer = NULL;
indexTable = NULL;
dataBuffer = NULL;
streamStartOffset = 0;
// Check if stream is to be attached or loaded completely
if (bAttachToStream)
{
attachedStream = inStream; // Record attached stream
inStream->AddRef();
}
else
attachedStream = NULL; // No attached stream
if (LoadVol(inStream, bAttachToStream) != 0)
{
// Error loading file
FreeMemory();
throw 0; // Abort object construction
}
g_cLocks++;
}
CVolReader::~CVolReader()
{
FreeMemory();
g_cLocks--;
// Check if an attached stream exists
if (attachedStream)
{
// Release attached stream
attachedStream->Release();
}
}
void CVolReader::FreeMemory()
{
unsigned int i;
if (stringBuffer != NULL)
delete [] stringBuffer;
if (indexTable != NULL)
delete [] indexTable;
if (dataBuffer != NULL)
{
for (i = 0; i < numFiles; i++)
{
// Check if file data is buffered in memory
if (dataBuffer[i] != NULL)
delete [] dataBuffer[i]; // Delete buffered memory
}
// Delete list of memory buffers
delete [] dataBuffer;
}
// Reset variables
stringBuffer = NULL;
indexTable = NULL;
dataBuffer = NULL;
numFiles = 0;
}
// - Reads in VOL file data from the input stream.
// - Returns 0 if successful and nonzero if an error occured.
// - Memory cleanup after errors is not supported by this function
// so if an error is detected, FreeMemory should be called after
// this function returns. Note that this requires memory pointers
// to be initialized to NULL before calling LoadVol.
// - bAttachToStream will cause only the index to be read from the
// stream since the stream will later be available when loading
// internal archive file data.
int CVolReader::LoadVol(SeekableStreamReader *inStream, int bAttachToStream)
{
SectionHeader sectHead;
int numBytesRead;
unsigned int totalHeaderSize;
unsigned int stringTableSize;
unsigned int indexTableSize;
unsigned int maxOffset;
unsigned int i, j;
try{
// Record the starting stream position for later seeking
// (Note: This allows VOL contents to be part of a larger stream)
inStream->get_ReadOffset(&streamStartOffset);
// Read the "VOL " section
inStream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
if (sectHead.tag != ' LOV') // "Vol "
throw L"Format error. 'VOL ' tag not found.";
totalHeaderSize = sectHead.sectionSize;
// Read the "volh" section
inStream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
if (sectHead.tag != 'hlov') // "volh"
throw L"Format error. 'volh' tag not found";
if (sectHead.sectionSize != 0)
throw L"Format error. 'volh' section size is not 0.";
// Read the "vols" section
inStream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
if (sectHead.tag != 'slov') // "vols"
throw L"Format error. 'vols' section not found.";
stringTableSize = sectHead.sectionSize - 4;
// Read the actual size of the string data
inStream->Read(4, (int)&actualStringDataLen, &numBytesRead);
if (actualStringDataLen > stringTableSize)
throw L"Format error. String data exceeds string section size.";
// Allocate space for the string table
stringBuffer = new char[stringTableSize];
// Read the string table
inStream->Read(stringTableSize, (int)stringBuffer, &numBytesRead);
// Read the "voli" section
inStream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
if (sectHead.tag != 'ilov') // "voli"
throw L"Format error. 'voli' tag not found.";
indexTableSize = sectHead.sectionSize;
//if (totalHeaderSize != stringTableSize + 4 + indexTableSize + sizeof(sectHead)*3)
// return 1; // Error. Format error.
// Calculate number of index entries stored in Vol file (round up)
numIndexEntries = (sectHead.sectionSize + sizeof(IndexEntry) - 1) / sizeof(IndexEntry);
// Allocate space for the index table
indexTable = new IndexEntry[numIndexEntries];
// Read in the index table
inStream->Read(sectHead.sectionSize, (int)indexTable, &numBytesRead);
// Fnid the number of used entries
numFiles = sectHead.sectionSize / sizeof(IndexEntry);
while ((numFiles > 0) && (indexTable[numFiles-1].boolUsed != 1))
numFiles--;
// Allocate space for data buffer pointers
dataBuffer = new LPVOID[numFiles];
memset(dataBuffer, 0, numFiles*4);
// Read in file data blocks
for (i = 0; i < numFiles; i++)
{
// Seek to begining of internal file data
inStream->Seek(streamStartOffset + indexTable[i].dataOffset);
// Read the "VBLK" section header
inStream->Read(sizeof(sectHead), (int)&sectHead, &numBytesRead);
if (sectHead.tag != 'KLBV') // "VBLK"
throw L"Format error. 'VBLK' tag not found at data offset";
//if (sectHead.sectionSize != indexTable[i].fileSize)
// return 1; // Error. Format error.
if (!bAttachToStream)
{
// Allocate space for the file data
dataBuffer[i] = new char[sectHead.sectionSize];
// Read the file data
inStream->Read(sectHead.sectionSize, (int)dataBuffer[i], &numBytesRead);
}
}
// Determine maximum offset of VOL data
maxOffset = 0;
j = 0;
for (i = 0; i < numFiles; i++)
{
j = indexTable[i].dataOffset + indexTable[i].fileSize;
if (j > maxOffset)
maxOffset = j;
}
if (maxOffset < totalHeaderSize + sizeof(sectHead) + 1)
maxOffset = totalHeaderSize + sizeof(sectHead) + 1;
// Seek to end of VOL data
inStream->Seek(streamStartOffset + maxOffset);
}
catch(WCHAR *errorMsg)
{
PostErrorMsg(errorMsg);
return -1; // Error
}
catch(...)
{
return -1; // Error
}
return 0; // Success
}
int CVolReader::GetFileIndex(BSTR fileName)
{
int startIndex, endIndex, middleIndex;
int result;
int stringLength;
char *tempString;
// Allocate space for a temporary ASCII fileName string
stringLength = SysStringLen(fileName);
tempString = new char[stringLength+1];
tempString[stringLength] = 0; // NULL terminate it
// Convert the BSTR to ASCII
WideCharToMultiByte(CP_ACP, 0, fileName, stringLength, tempString, stringLength, 0, 0);
// Search index for file
startIndex = 0;
endIndex = numFiles - 1;
while (startIndex <= endIndex)
{
// Get the midpoint
middleIndex = (startIndex + endIndex) >> 1;
// Check if strings match
result = strncmp((char*)stringBuffer + indexTable[middleIndex].fileNameOffset,
tempString,
stringLength);
if (result == 0)
{
// String match
delete [] tempString;
return middleIndex;
}
if (result < 0)
{
// Search top half of index table
startIndex = middleIndex + 1;
}
else // result > 0
{
// Search bottom half of index table
endIndex = middleIndex - 1;
}
}
// File not found
delete [] tempString;
return -1;
}

View File

@ -0,0 +1,68 @@
#include "OP2Editor.h"
class CVolReader : public ArchiveReader
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// ArchiveReader
// *************
// [propget]
HRESULT STDMETHODCALLTYPE get_NumFiles(
/* [retval][out] */ int __RPC_FAR *numFiles);
// [propget]
HRESULT STDMETHODCALLTYPE get_FileName(
/* [in] */ int index,
/* [retval][out] */ BSTR __RPC_FAR *fileName);
HRESULT STDMETHODCALLTYPE OpenStreamRead(
/* [in] */ BSTR filename,
/* [retval][out] */ StreamReader __RPC_FAR *__RPC_FAR *stream);
// Class specific
// **************
CVolReader(SeekableStreamReader *inStream, int bAttachToStream);
~CVolReader();
private:
ULONG m_cRef;
void FreeMemory();
int LoadVol(SeekableStreamReader *inStream, int bAttachToStream);
int GetFileIndex(BSTR fileName);
#pragma pack(push, 1)
struct IndexEntry
{
int fileNameOffset; // Offset from the start of the string data
int dataOffset; // Offset from the start of the file to VBLK tag
int fileSize; // Size of packed data in archive
char encoding; // Form of compression used to store the file
char boolUsed; // Indicates if this index entry is used
};
struct SectionHeader
{
int tag;
int sectionSize:31;
int alignment:1;
};
#pragma pack(pop)
unsigned int numFiles; // Number of files stored in this Vol file
unsigned int numIndexEntries; // Number of index entries stored in Vol file (some may be empty)
unsigned int actualStringDataLen; // Actual used size of string section (up to and including last terminating NULL character)
LPVOID stringBuffer; // Buffer to hold all internal file names
IndexEntry *indexTable; // Pointer to index table array
LPVOID *dataBuffer; // Pointer to an array of pointers to data buffers
int streamStartOffset; // Start offset of vol data in stream
SeekableStreamReader *attachedStream; // Vol data input stream
};

View File

@ -0,0 +1,334 @@
#include "stdafx.h"
#include "CVolWriter.h"
extern int g_cLocks;
ULONG __stdcall CVolWriter::AddRef()
{
return ++m_cRef;
}
ULONG __stdcall CVolWriter::Release()
{
if (--m_cRef != 0)
return m_cRef;
delete this;
return 0;
}
HRESULT __stdcall CVolWriter::QueryInterface(REFIID riid, void** ppv)
{
if(riid == IID_IUnknown)
*ppv = (IUnknown*)this;
else if(riid == IID_ArchiveWriter)
*ppv = (ArchiveWriter*)this;
else
{
*ppv = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
// ArchiveWriter
// *************
HRESULT CVolWriter::AddToArchive(BSTR fileName, SeekableStreamReader *inStream, int reserved)
{
LinkedListNode *newNode;
int stringLength;
// Check for invalid parameters
if (fileName == NULL)
return E_INVALIDARG;
if (inStream == NULL)
return E_INVALIDARG;
if (reserved != 0)
return E_INVALIDARG;
// Create a new linked list node to hold the data
newNode = new LinkedListNode;
// Allocate space to store the filename
stringLength = SysStringLen(fileName);
newNode->fileNameLength = stringLength+1; // Store the string length
newNode->fileName = new char[stringLength+1]; // Allocate space for filename string
newNode->fileName[stringLength] = 0; // NULL terminate the string
// Convert the filename from UNICODE to ASCII
WideCharToMultiByte(CP_ACP, 0, fileName, stringLength, newNode->fileName, stringLength, 0, 0);
// Store the stream pointer
newNode->inStream = inStream;
inStream->AddRef();
// Store the encoding method
newNode->indexEntry.encoding = reserved;
newNode->indexEntry.bUsed = 1;
// Get the stream starting offset and size
inStream->get_ReadOffset(&newNode->startStreamOffset);
inStream->get_StreamSize(&newNode->indexEntry.fileSize);
newNode->indexEntry.fileSize -= newNode->startStreamOffset; // Adjust for unstored data
// Store the new node to the linked list
newNode->next = head;
head = newNode;
numNodes++;
// Update running counts of string table size and max buffer size
stringTableSize += stringLength+1;
if (newNode->indexEntry.fileSize > maxBufferSize)
maxBufferSize = newNode->indexEntry.fileSize;
return S_OK;
}
HRESULT CVolWriter::WriteArchive(StreamWriter *outStream)
{
SectionHeader sectHead;
int totalHeaderSize;
int stringSectionSize;
int indexSectionSize;
int temp = 0; // Used to write alignment bytes
int numBytesWritten;
int bufferSize;
char *buffer; // Write buffer
int offset;
LinkedListNode *current;
// Sort the index
head = SortIndex(head);
// Calculate section sizes and allocate buffer space
// *************************************************
stringSectionSize = (stringTableSize + 4 + 3) & ~3;
indexSectionSize = (numNodes*sizeof(IndexEntry) + 3) & ~3;
totalHeaderSize = stringSectionSize + indexSectionSize + 3*sizeof(SectionHeader);
// Calculate needed buffer size
bufferSize = maxBufferSize;
if (stringTableSize > bufferSize)
bufferSize = stringTableSize;
// Allocate space for the write buffer
buffer = new char[bufferSize];
// Prepare the string table
offset = 0;
current = head;
while (current)
{
current->indexEntry.fileNameOffset = offset; // Store filename offset
// Copy the filename to the string buffer
memcpy(&buffer[offset], current->fileName, current->fileNameLength);
offset += current->fileNameLength; // Update the string offset
current = current->next; // Process next node
}
// Begin writing the VOL file contents
// ***********************************
// "VOL " section
// **************
sectHead.tag = ' LOV'; // "VOL "
sectHead.sectionSize = totalHeaderSize;
sectHead.alignment = 1;
outStream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
// "volh" section
sectHead.tag = 'hlov'; // "volh"
sectHead.sectionSize = 0;
outStream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
// "vols" section
sectHead.tag = 'slov'; // "vols"
sectHead.sectionSize = stringSectionSize;
outStream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
outStream->Write(4, (int)&stringTableSize, &numBytesWritten);
// Write out the string table
outStream->Write(stringTableSize, (int)buffer, &numBytesWritten);
// Pad section with NULL bytes
outStream->Write(stringSectionSize - stringTableSize - 4, (int)&temp, &numBytesWritten);
// "voli" section
sectHead.tag = 'ilov'; // "voli"
sectHead.sectionSize = numNodes * sizeof(IndexEntry);
outStream->Write(sizeof(sectHead), (int)&sectHead, &numBytesWritten);
// Write out the index table
offset = totalHeaderSize + sizeof(SectionHeader);
current = head;
while (current)
{
// Store the data offset
current->indexEntry.dataOffset = offset;
// Update offset for next file
offset += sizeof(SectionHeader) + ((current->indexEntry.fileSize + 3) & ~3);
// Write out the index table
outStream->Write(sizeof(IndexEntry), (int)&current->indexEntry, &numBytesWritten);
current = current->next; // Process next node
}
// Pad the section with NULL bytes
outStream->Write(indexSectionSize - numNodes*sizeof(IndexEntry), (int)&temp, &numBytesWritten);
// Data section
// ************
sectHead.tag = 'KLBV'; // "VBLK"
current = head;
while (current)
{
// Write out the file data section header
sectHead.sectionSize = current->indexEntry.fileSize;
outStream->Write(sizeof(SectionHeader), (int)&sectHead, &numBytesWritten);
// Seek to the beginning of the file data
current->inStream->Seek(current->startStreamOffset);
// Read in the file data
current->inStream->Read(sectHead.sectionSize, (int)buffer, &numBytesWritten);
// Write out the file data to the archive
outStream->Write(sectHead.sectionSize, (int)buffer, &numBytesWritten);
// Pad the section with NULL bytes
outStream->Write(-sectHead.sectionSize & 3, (int)&temp, &numBytesWritten);
// Process next file
current = current->next;
}
// Release the write buffer
delete [] buffer;
return S_OK;
}
// Class specific
// **************
CVolWriter::CVolWriter() : m_cRef(1)
{
// Initialize variables
head = NULL;
numNodes = 0;
stringTableSize = 0;
maxBufferSize = 0;
g_cLocks++;
}
CVolWriter::~CVolWriter()
{
LinkedListNode *current, *next;
// Delete the linked list
current = head;
while(current)
{
next = current->next; // Read the pointer to the next node
delete [] current->fileName; // Release the filename memory for this node
current->inStream->Release(); // Release the input stream for this node
delete current; // Release this node
current = next; // Process next node
}
g_cLocks--;
}
// Performs a Merge Sort on the linked list
CVolWriter::LinkedListNode* CVolWriter::SortIndex(LinkedListNode *list)
{
struct Tape
{
LinkedListNode *head;
LinkedListNode *tail;
int count;
};
Tape tape[4];
LinkedListNode *current, *next;
int destTape, sourceTape;
int blockSize;
int blockCount[2];
// Initialize tapes
tape[0].head = NULL;
tape[0].tail = NULL;
tape[0].count = 0;
tape[1].head = NULL;
tape[1].tail = NULL;
tape[1].count = 0;
// Break list into two
destTape = 0;
for (current = list; current != NULL; destTape ^= 1)
{
// Cache the next node in the list
next = current->next;
// Add the node to the tape
if (tape[destTape].head == NULL)
tape[destTape].head = current;
else
tape[destTape].tail->next = current;
tape[destTape].tail = current;
tape[destTape].count++;
// Process next node
current = next;
}
// Note: The tail nodes will have invalid next pointers at this point
// Merge tapes using successively larger blocks in sorted order and split output
for (blockSize = 1; tape[1].count != 0; blockSize <<= 1)
{
// Initialize new tapes
tape[2].head = NULL;
tape[2].tail = NULL;
tape[2].count = 0;
tape[3].head = NULL;
tape[3].tail = NULL;
tape[3].count = 0;
// Merge all blocks on two tapes and split the output
for (destTape = 2; (tape[0].count != 0) || (tape[1].count != 0); destTape ^= 1)
{
// Merge a block from each tape
blockCount[0] = blockCount[1] = blockSize;
if (blockCount[0] > tape[0].count)
blockCount[0] = tape[0].count;
if (blockCount[1] > tape[1].count)
blockCount[1] = tape[1].count;
for ( ; blockCount[0] | blockCount[1]; )
{
// Check for empty tapes
if (blockCount[0] == 0)
sourceTape = 1; // Node must come from tape[1]
else if (blockCount[1] == 0)
sourceTape = 0; // Node must come from tape[0]
// Check for proper sorted order
else if (strcmp(tape[0].head->fileName, tape[1].head->fileName) < 0)
sourceTape = 0; // Node on tape[0] comes before
else
sourceTape = 1; // Node on tape[1] comes before
// Move the node from the source tape to the dest tape
// Extract the node from the source tape
blockCount[sourceTape]--;
next = tape[sourceTape].head;
tape[sourceTape].head = tape[sourceTape].head->next;
tape[sourceTape].count--;
// Add the node to the dest tape
if (tape[destTape].tail == NULL)
tape[destTape].head = next;
else
tape[destTape].tail->next = next;
tape[destTape].tail = next;
next->next = NULL;
tape[destTape].count++;
}
}
// Swap tapes for next round
tape[0] = tape[2];
tape[1] = tape[3];
}
// Return the first element of the sorted list
return tape[0].head;
}

View File

@ -0,0 +1,68 @@
#include "OP2Editor.h"
class CVolWriter : public ArchiveWriter
{
public:
// IUnknown
// ********
ULONG __stdcall AddRef();
ULONG __stdcall Release();
HRESULT __stdcall QueryInterface(REFIID riid, void** ppv);
// ArchiveWriter
// *************
HRESULT STDMETHODCALLTYPE AddToArchive(
/* [in] */ BSTR fileName,
/* [in] */ SeekableStreamReader __RPC_FAR *inStream,
/* [in] */ int reserved);
HRESULT STDMETHODCALLTYPE WriteArchive(
/* [in] */ StreamWriter __RPC_FAR *outStream);
// Class specific
// **************
CVolWriter();
~CVolWriter();
private:
ULONG m_cRef;
#pragma pack(push, 1)
struct SectionHeader
{
int tag; // Identifies this section with a 4 byte (ASCII) tag
int sectionSize:31; // Size of this section in bytes
int alignment:1; // Determines if section is to be treated as WORD or DWORD aligned
};
struct IndexEntry
{
int fileNameOffset; // Offset to filename in string table
int dataOffset; // Offset in VOL file of this file's data
int fileSize; // Size of this file
char encoding; // Compression used to store the file
char bUsed; // Indicates if this IndexEntry is used
};
#pragma pack(pop)
struct LinkedListNode
{
LinkedListNode *next; // Next node in the linked list
SeekableStreamReader *inStream; // Input stream object for file data
int startStreamOffset; // Starting offset of data in this stream to store
int fileNameLength; // Length of filename, including the NULL terminator
char *fileName; // Internal archive filename
IndexEntry indexEntry; // Index entry for this file
};
LinkedListNode* SortIndex(LinkedListNode *list);
// Linked list variables
LinkedListNode *head;
int numNodes;
int stringTableSize;
int maxBufferSize;
};

View File

@ -0,0 +1,74 @@
#include "stdafx.h"
#include "GlobalFunctions.h"
void PostErrorMsg(WCHAR *errorMsg)
{
// Provide rich error information
// Create generic error object.
ICreateErrorInfo* pCreateErrorInfo;
if (FAILED(CreateErrorInfo(&pCreateErrorInfo)))
return;
// Set rich error information.
pCreateErrorInfo->SetDescription(errorMsg);
//pCreateErrorInfo->SetGUID(IID_MapFile);
// Exchange ICreateErrorInfo for IErrorInfo.
IErrorInfo* pErrorInfo;
pCreateErrorInfo->QueryInterface(IID_IErrorInfo,
(void**)&pErrorInfo);
// Make the error information available to the client.
SetErrorInfo(NULL, pErrorInfo);
// Release the interface pointers.
pErrorInfo->Release();
pCreateErrorInfo->Release();
}
bool IsRelative(BSTR path)
{
// Check if the first character is a "\"
if (path[0] == L'\\')
return false; // Absolute path
// Check for embedded ":"
if (wcschr(path, L':') != NULL)
return false; // Absolute path
// Relative path
return true;
}
int RoundUpPowerOf2(int num)
{
num = num - 1;
num = num | (num >> 1);
num = num | (num >> 2);
num = num | (num >> 4);
num = num | (num >> 8);
num = num | (num >> 16);
num += 1;
return num;
}
int LogBase2(int num)
{
int log = 31;
int y;
y = num <<16; if (y != 0) {log = log -16; num = y;}
y = num << 8; if (y != 0) {log = log - 8; num = y;}
y = num << 4; if (y != 0) {log = log - 4; num = y;}
y = num << 2; if (y != 0) {log = log - 2; num = y;}
y = num << 1; if (y != 0) {log = log - 1;}
return log;
}

View File

@ -0,0 +1,8 @@
void PostErrorMsg(WCHAR *errorMsg);
bool IsRelative(BSTR path);
int RoundUpPowerOf2(int num);
int LogBase2(int num);

View File

@ -0,0 +1,23 @@
HKCR
{
OP2Editor.MapFile.1 = s 'MapFile Class'
{
CLSID = s '{03270D36-7780-450F-99B9-910C75A83A29}'
}
OP2Editor.MapFile = s 'MapFile Class'
{
CLSID = s '{03270D36-7780-450F-99B9-910C75A83A29}'
}
NoRemove CLSID
{
ForceRemove {03270D36-7780-450F-99B9-910C75A83A29} = s 'MapFile Class'
{
ProgID = s 'OP2Editor.MapFile.1'
VersionIndependentProgID = s 'OP2Editor.MapFile'
InprocServer32 = s '%MODULE%'
{
val ThreadingModel = s 'both'
}
}
}
}

View File

@ -0,0 +1,101 @@
// OP2Editor.cpp : Implementation of DLL Exports.
// Note: Proxy/Stub Information
// To build a separate proxy/stub DLL,
// run nmake -f OP2Editorps.mk in the project directory.
#include "stdafx.h"
#include "resource.h"
#include <initguid.h>
#include "OP2Editor.h"
#include "OP2Editor_i.c"
#include "CFileStreamReader.h"
#include "CFileStreamWriter.h"
#include "CResourceManager.h"
#include "CResourceManagerFactory.h"
int g_cLocks = 0;
HINSTANCE g_hInstance = NULL;
// DLL Entry Point
extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
g_hInstance = hInstance;
DisableThreadLibraryCalls(hInstance);
}
return TRUE; // ok
}
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
if (g_cLocks == 0)
return S_OK;
else
return S_FALSE;
}
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
if(rclsid != CLSID_ResourceManager)
return CLASS_E_CLASSNOTAVAILABLE;
CResourceManagerFactory *pFactory = new CResourceManagerFactory();
if(pFactory == NULL)
return E_OUTOFMEMORY;
// riid is probably IID_IClassFactory.
HRESULT hr = pFactory->QueryInterface(riid, ppv);
pFactory->Release(); // Just in case QueryInterface fails
return hr;
}
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
HKEY hSubKey;
TCHAR path[MAX_PATH];
DWORD creationDisposition;
int pathLen;
int retVal;
pathLen = GetModuleFileName(g_hInstance, path, MAX_PATH);
retVal = RegCreateKeyEx(HKEY_CLASSES_ROOT,
"CLSID\\{C8DE4CDE-4554-4fe9-8688-A90D91EBCA0B}\\InprocServer32",
0,
"",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hSubKey,
&creationDisposition);
if (retVal != ERROR_SUCCESS)
return HRESULT_FROM_WIN32(retVal);
retVal = RegSetValueEx(hSubKey, "", 0, REG_SZ, (BYTE*)path, pathLen);
RegCloseKey(hSubKey);
return HRESULT_FROM_WIN32(retVal);
}
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
int retVal;
retVal = RegDeleteKey(HKEY_CLASSES_ROOT,
"CLSID\\{C8DE4CDE-4554-4fe9-8688-A90D91EBCA0B}\\InprocServer32");
retVal = RegDeleteKey(HKEY_CLASSES_ROOT,
"CLSID\\{C8DE4CDE-4554-4fe9-8688-A90D91EBCA0B}");
return HRESULT_FROM_WIN32(retVal);
}

View File

@ -0,0 +1,9 @@
; OP2Editor.def : Declares the module parameters.
LIBRARY "OP2Editor.DLL"
EXPORTS
DllCanUnloadNow @1 PRIVATE
DllGetClassObject @2 PRIVATE
DllRegisterServer @3 PRIVATE
DllUnregisterServer @4 PRIVATE

View File

@ -0,0 +1,448 @@
# Microsoft Developer Studio Project File - Name="OP2Editor" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=OP2Editor - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "OP2Editor.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "OP2Editor.mak" CFG="OP2Editor - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "OP2Editor - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OP2Editor - Win32 Unicode Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OP2Editor - Win32 Release MinSize" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OP2Editor - Win32 Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OP2Editor - Win32 Unicode Release MinSize" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "OP2Editor - Win32 Unicode Release MinDependency" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "OP2Editor - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /FR /Yu"stdafx.h" /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# Begin Custom Build - Performing registration
OutDir=.\Debug
TargetPath=.\Debug\OP2Editor.dll
InputPath=.\Debug\OP2Editor.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
# End Custom Build
!ELSEIF "$(CFG)" == "OP2Editor - Win32 Unicode Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "DebugU"
# PROP BASE Intermediate_Dir "DebugU"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "DebugU"
# PROP Intermediate_Dir "DebugU"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /Yu"stdafx.h" /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /GZ /c
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /pdbtype:sept
# Begin Custom Build - Performing registration
OutDir=.\DebugU
TargetPath=.\DebugU\OP2Editor.dll
InputPath=.\DebugU\OP2Editor.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
if "%OS%"=="" goto NOTNT
if not "%OS%"=="Windows_NT" goto NOTNT
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
goto end
:NOTNT
echo Warning : Cannot register Unicode DLL on Windows 95
:end
# End Custom Build
!ELSEIF "$(CFG)" == "OP2Editor - Win32 Release MinSize"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ReleaseMinSize"
# PROP BASE Intermediate_Dir "ReleaseMinSize"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseMinSize"
# PROP Intermediate_Dir "ReleaseMinSize"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O1 /D "NDEBUG" /D "_MBCS" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# Begin Custom Build - Performing registration
OutDir=.\ReleaseMinSize
TargetPath=.\ReleaseMinSize\OP2Editor.dll
InputPath=.\ReleaseMinSize\OP2Editor.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
# End Custom Build
!ELSEIF "$(CFG)" == "OP2Editor - Win32 Release MinDependency"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ReleaseMinDependency"
# PROP BASE Intermediate_Dir "ReleaseMinDependency"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseMinDependency"
# PROP Intermediate_Dir "ReleaseMinDependency"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /O1 /D "NDEBUG" /D "_MBCS" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# Begin Custom Build - Performing registration
OutDir=.\ReleaseMinDependency
TargetPath=.\ReleaseMinDependency\OP2Editor.dll
InputPath=.\ReleaseMinDependency\OP2Editor.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
# End Custom Build
!ELSEIF "$(CFG)" == "OP2Editor - Win32 Unicode Release MinSize"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ReleaseUMinSize"
# PROP BASE Intermediate_Dir "ReleaseUMinSize"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseUMinSize"
# PROP Intermediate_Dir "ReleaseUMinSize"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "_ATL_DLL" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# Begin Custom Build - Performing registration
OutDir=.\ReleaseUMinSize
TargetPath=.\ReleaseUMinSize\OP2Editor.dll
InputPath=.\ReleaseUMinSize\OP2Editor.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
if "%OS%"=="" goto NOTNT
if not "%OS%"=="Windows_NT" goto NOTNT
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
goto end
:NOTNT
echo Warning : Cannot register Unicode DLL on Windows 95
:end
# End Custom Build
!ELSEIF "$(CFG)" == "OP2Editor - Win32 Unicode Release MinDependency"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "ReleaseUMinDependency"
# PROP BASE Intermediate_Dir "ReleaseUMinDependency"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "ReleaseUMinDependency"
# PROP Intermediate_Dir "ReleaseUMinDependency"
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_USRDLL" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /Yu"stdafx.h" /FD /c
# ADD CPP /nologo /MT /W3 /O1 /D "NDEBUG" /D "_UNICODE" /D "_ATL_STATIC_REGISTRY" /D "_ATL_MIN_CRT" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /Yu"stdafx.h" /FD /c
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
# Begin Custom Build - Performing registration
OutDir=.\ReleaseUMinDependency
TargetPath=.\ReleaseUMinDependency\OP2Editor.dll
InputPath=.\ReleaseUMinDependency\OP2Editor.dll
SOURCE="$(InputPath)"
"$(OutDir)\regsvr32.trg" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
if "%OS%"=="" goto NOTNT
if not "%OS%"=="Windows_NT" goto NOTNT
regsvr32 /s /c "$(TargetPath)"
echo regsvr32 exec. time > "$(OutDir)\regsvr32.trg"
goto end
:NOTNT
echo Warning : Cannot register Unicode DLL on Windows 95
:end
# End Custom Build
!ENDIF
# Begin Target
# Name "OP2Editor - Win32 Debug"
# Name "OP2Editor - Win32 Unicode Debug"
# Name "OP2Editor - Win32 Release MinSize"
# Name "OP2Editor - Win32 Release MinDependency"
# Name "OP2Editor - Win32 Unicode Release MinSize"
# Name "OP2Editor - Win32 Unicode Release MinDependency"
# Begin Group "Source Files"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\CMapFile.cpp
# End Source File
# Begin Source File
SOURCE=.\CResourceManager.cpp
# End Source File
# Begin Source File
SOURCE=.\CResourceManagerFactory.cpp
# End Source File
# Begin Source File
SOURCE=.\CTileGroup.cpp
# End Source File
# Begin Source File
SOURCE=.\GlobalFunctions.cpp
# End Source File
# Begin Source File
SOURCE=.\OP2Editor.cpp
# End Source File
# Begin Source File
SOURCE=.\OP2Editor.def
# End Source File
# Begin Source File
SOURCE=.\OP2Editor.rc
# End Source File
# Begin Source File
SOURCE=.\StdAfx.cpp
# ADD CPP /Yc"stdafx.h"
# End Source File
# End Group
# Begin Group "Header Files"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# Begin Source File
SOURCE=.\CMapFile.h
# End Source File
# Begin Source File
SOURCE=.\CResourceManager.h
# End Source File
# Begin Source File
SOURCE=.\CResourceManagerFactory.h
# End Source File
# Begin Source File
SOURCE=.\CTileGroup.h
# End Source File
# Begin Source File
SOURCE=.\GlobalFunctions.h
# End Source File
# Begin Source File
SOURCE=.\Resource.h
# End Source File
# Begin Source File
SOURCE=.\StdAfx.h
# End Source File
# End Group
# Begin Group "Resource Files"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# Begin Source File
SOURCE=.\MapFile.rgs
# End Source File
# End Group
# Begin Group "InputOutput"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\CClmReader.cpp
# End Source File
# Begin Source File
SOURCE=.\CClmReader.h
# End Source File
# Begin Source File
SOURCE=.\CClmWriter.cpp
# End Source File
# Begin Source File
SOURCE=.\CClmWriter.h
# End Source File
# Begin Source File
SOURCE=.\CFileStreamReader.cpp
# End Source File
# Begin Source File
SOURCE=.\CFileStreamReader.h
# End Source File
# Begin Source File
SOURCE=.\CFileStreamWriter.cpp
# End Source File
# Begin Source File
SOURCE=.\CFileStreamWriter.h
# End Source File
# Begin Source File
SOURCE=.\CMemoryStreamReader.cpp
# End Source File
# Begin Source File
SOURCE=.\CMemoryStreamReader.h
# End Source File
# Begin Source File
SOURCE=.\CVolReader.cpp
# End Source File
# Begin Source File
SOURCE=.\CVolReader.h
# End Source File
# Begin Source File
SOURCE=.\CVolWriter.cpp
# End Source File
# Begin Source File
SOURCE=.\CVolWriter.h
# End Source File
# End Group
# Begin Group "Interfaces"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\OP2Editor.idl
# ADD MTL /tlb ".\OP2Editor.tlb" /h "OP2Editor.h" /iid "OP2Editor_i.c" /Oicf
# End Source File
# End Group
# Begin Group "TileSets"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\CTileSet.cpp
# End Source File
# Begin Source File
SOURCE=.\CTileSet.h
# End Source File
# Begin Source File
SOURCE=.\CTileSetManager.cpp
# End Source File
# Begin Source File
SOURCE=.\CTileSetManager.h
# End Source File
# Begin Source File
SOURCE=.\CTileSetSource.cpp
# End Source File
# Begin Source File
SOURCE=.\CTileSetSource.h
# End Source File
# End Group
# End Target
# End Project

View File

@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
Project: "OP2Editor"=".\OP2Editor.dsp" - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,509 @@
// OP2Editor.idl : IDL source for OP2Editor.dll
//
// This file will be processed by the MIDL tool to
// produce the type library (OP2Editor.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
// Interfaces
// **********
// StreamReader
[
object, uuid(70AC9DEE-CE0F-4145-A140-6AE1BA658B1E), oleautomation, nonextensible,
helpstring("Stream Reader interface for reading in data. This allows both individual files and files stored in archives to be read with the same ease.")
]
interface StreamReader : IUnknown
{
[ local, helpstring("Read numBytes into a buffer specified by the pointer pBuffer.") ]
HRESULT Read([in] int numBytes, [in] int pBuffer, [out, retval] int *numBytesRead);
[ propget, helpstring("Returns a status code for the stream. A value of 0 denotes no errors. If an error occured, a nonzero error code is returned. A read past the end of the file is considered an error.") ]
HRESULT Status([out, retval] int *status);
}
// SeekableStreamReader
[
object, uuid(57B5FDD0-8E6E-4134-94DE-6949BD2EB3CB), oleautomation, nonextensible,
helpstring("Enhanced StreamReader interface to support seekable stream.")
]
interface SeekableStreamReader : StreamReader
{
[ propget, helpstring("Current offset into the stream of the read pointer.") ]
HRESULT ReadOffset([out, retval] int *readOffset);
[ propget, helpstring("Total number of bytes in this stream.") ]
HRESULT StreamSize([out, retval] int *streamSize);
[ helpstring("Sets the current read position for this stream.") ]
HRESULT Seek([in] int offset);
}
// StreamWriter
[
object, uuid(B83597A2-3471-48db-B9BC-EB4749BA1AAA), oleautomation, nonextensible,
helpstring("Stream Writer interface for writing out data. This allows both individual files and files stored in archives to be written with the same ease.")
]
interface StreamWriter : IUnknown
{
[ local, helpstring("Write numBytes to the stream from the specified buffer.") ]
HRESULT Write([in] int numBytes, [in] int pBuffer, [out, retval] int *numBytesWritten);
[ propget, helpstring("Returns a status code for the stream. A value of 0 denotes no errors. If an error occured, a nonzero error code is returned.") ]
HRESULT Status([out, retval] int *status);
}
// ArchiveReader
[
object, uuid(CE02B285-D2F4-4707-B6D3-39CB6697357C), oleautomation, nonextensible,
helpstring("Archive Reader interface for viewing and reading the contents of archives.")
]
interface ArchiveReader : IUnknown
{
[ propget, helpstring("Number of files stored in the archive.") ]
HRESULT NumFiles([out, retval] int *numFiles);
[ propget, helpstring("File name of a file stored in the archive.") ]
HRESULT FileName([in] int index, [out, retval] BSTR *fileName);
[ helpstring("Opens an internal file as a stream for reading.") ]
HRESULT OpenStreamRead([in] BSTR filename, [out, retval] StreamReader **stream);
}
// ArchiveWriter
[
object, uuid(98A6E750-10C7-4133-9A0E-17FB62EC6ADE), oleautomation, nonextensible,
helpstring("Archive Writer interface for saving streams as archive files.")
]
interface ArchiveWriter : IUnknown
{
[ helpstring("Adds a stream as an input source for the archive file data. The fileName specified is the internal archive file name.") ]
HRESULT AddToArchive([in] BSTR fileName, [in] SeekableStreamReader *inStream, [in] int reserved);
[ helpstring("Collects all input stream data into the output stream as an archive.") ]
HRESULT WriteArchive([in] StreamWriter *outStream);
}
// TileSet
[
object, uuid(C7F1E185-8079-4538-96CF-5950406AE1AA), oleautomation, nonextensible,
helpstring("Tile Set interface for managing tile sets used to display maps.")
]
interface TileSet : IUnknown
{
[ propget, helpstring("Returns the number of tiles stored in this tile set.") ]
HRESULT NumTiles([out, retval] int *numTiles);
[ propget, helpstring("Returns the size of the tiles in this tile set in pixels. Note: Both x and y sizes are the same.") ]
HRESULT TileSize([out, retval] int *tileSize);
[ propget, helpstring("Returns the bit depth of the pixel data for this tile set.") ]
HRESULT BitDepth([out, retval] int *bitDepth);
[ propget, helpstring("") ]
HRESULT NumPaletteEntries([out, retval] int *numPaletteEntries);
[ propget, helpstring("Returns an RGBQUAD structure (type casted as a 32 bit word) corresponding to that palette entry.") ]
HRESULT PaletteEntry([in] int index, [out, retval] int *palEntry);
[ propput, helpstring("Sets an RGBQUAD structure (type casted as a 32 bit word) into the corresponding palette entry.") ]
HRESULT PaletteEntry([in] int index, [in] int palEntry);
[ helpstring("Expands or contracts the internal buffer to hold the specified number of tiles. Previous tiles are copied into the new buffer.") ]
HRESULT SetNumTiles([in] int numTiles);
[ local, helpstring("Retrieves an array of pixel data.") ]
HRESULT GetPixelData([in] int pBuffer, [in] int startOffset, [in] int numBytes);
[ local, helpstring("Sets an array of pixel data") ]
HRESULT SetPixelData([in] int pBuffer, [in] int startOffset, [in] int numBytes);
// **TODO** Consider removing this, replace with PasteTile
[ propget, helpstring("Returns the minimap color for the given tile as a 32 bit color value.") ]
HRESULT MiniMapColors([in] int tileIndex, [out, retval] int *color);
// Allow for zoom option
// **TODO** Consider adding args for clipping
[ helpstring("Draws the specified tile to the given device context at the given location.") ]
HRESULT PasteTile([in] int destDC, [in] int pixelX, [in] int pixelY, [in] int tileNum);
[ v1_enum, helpstring("Enum used to control the format of the saved tile set.") ]
enum TileSetSaveFormat
{
Default = 0, // The normal custom OP2 format
Bitmap = 1, // Standard windows bitmap
};
[ helpstring("Save all the tile set data to a stream.") ]
HRESULT SaveTileSet([in] StreamWriter *stream, [in] enum TileSetSaveFormat saveFormat);
}
// TileSetSource
[
object, uuid(153BC780-0FF2-44e4-8448-5B3F46050475), oleautomation, nonextensible,
helpstring("Tile Set Manager interface used to load and share tile sets among multiple open map files.")
]
interface TileSetSource : IUnknown
{
HRESULT LoadTileSet([in] BSTR tileSetName, [out, retval] TileSet **tileSet);
HRESULT UnloadTileSet([in] BSTR tileSetName);
}
// TileSetManager
[
object, uuid(33A10A9E-A3B0-498f-A871-3ECC78B477FB), oleautomation, nonextensible,
helpstring("Manages a collection of tile sets and a mapping into them.")
]
interface TileSetManager : IUnknown
{
// Tile set info
[ propget, helpstring("Number of tile sets used by tiles in this group") ]
HRESULT NumTileSets([out, retval] int *numTileSets);
[ propget, helpstring("Gets the name of a loaded tile set.") ]
HRESULT TileSetName([in] int index, [out, retval] BSTR *tileSetName);
[ propget, helpstring("Returns one of the tile set objects referenced by this block of tiles.") ]
HRESULT TileSet([in] int index, [out, retval] TileSet **tileSet);
// Tile set management
[ helpstring("Adds a tile set to the tile set manager and returns its index.") ]
HRESULT AddTileSet([in] BSTR tileSetName, [out, retval] int *index);
[ helpstring("Removes a tile set from use and clears any mappings referencing the tile set.") ]
HRESULT RemoveTileSet([in] BSTR tileSetName, [out, retval] int *index);
[ helpstring("Replaces the tile set at the given index with the specified tile set.") ]
HRESULT ReplaceTileSet([in] int index, [in] BSTR tileSetName);
[ helpstring("Adds mapping entries to refer to desired tiles in the tile set.") ]
HRESULT MapInTiles([in] int tileSetIndex, [in] int startTile, [in] int numTiles, [out, retval] int *mappingIndex);
// Mapping lookup
[ helpstring("This function looks for a mapping entry with the given fields and returns the index. A value of -1 is returned is no match is found. Note: -1 can be used for numTileReplacements and cycleDelay as 'don't care' conditions.") ]
HRESULT GetMappingIndex([in] int tileSetIndex, [in] int tileIndex, [in] int numTileReplacements, [in] int cycleDelay, [out, retval] int *mappingIndex);
// Mapping count
[ propget, helpstring("Returns the number of mappings.") ]
HRESULT NumMappings([out, retval] int *numMappings);
// Tile mapping info
[ propget, helpstring("Index of the tile set that this mapping entry uses.") ]
HRESULT TileSetIndex([in] int mappingIndex, [out, retval] int *tileSetIndex);
[ propput, helpstring("Sets the index of the tile set that this mapping entry uses.") ]
HRESULT TileSetIndex([in] int mappingIndex, [in] int tileSetIndex);
[ propget, helpstring("Index of the tile in the tile set that this tile uses.") ]
HRESULT TileSetTileIndex([in] int mappingIndex, [out, retval] int *tileSetTileIndex);
[ propput, helpstring("Sets the index of the tile that this mapping entry uses.") ]
HRESULT TileSetTileIndex([in] int mappingIndex, [in] int tileSetTileIndex);
[ propget, helpstring("Number of consecutive tile mapping entries that can be used as a replacement for this entry in an animation sequence.") ]
HRESULT NumTileReplacements([in] int mappingIndex, [out, retval] int *numTileReplacements);
[ propput, helpstring("Sets the number of consecutive mapping entries that can be used as a replacement for this entry in an animation sequence.") ]
HRESULT NumTileReplacements([in] int mappingIndex, [in] int numTileReplacements);
[ propget, helpstring("Number of game cycles that elapse before this entry is replaced by another in the animation sequence.") ]
HRESULT CycleDelay([in] int mappingIndex, [out, retval] int *cycleDelay);
[ propput, helpstring("Sets the number of game cycles that elapse before this entry is replace by another in the animation sequence.") ]
HRESULT CycleDelay([in] int mappingIndex, [in] int cycleDelay);
// Terrain set count
[ propget, helpstring("Returns the number of terrain sets.") ]
HRESULT NumTerrains([out, retval] int *numTerrains);
[ helpstring("Expands or contracts the internal buffer to hold the specified number of terrains. Previous terrains are copied into the new buffer.") ]
HRESULT SetNumTerrains([in] int numTerrains);
// Terrain sets
[ v1_enum, helpstring("Enum used to control the direction for tube/wall terrain data.") ]
enum TerrainTubeDirection
{
DirLeftToRight = 0,
DirTopToBottom = 1,
DirLeftToBottom = 2,
DirRightToBottom = 3,
DirLeftToTop = 4,
DirRightToTop = 5,
DirLeftRightTop = 6,
DirLeftRightBottom = 7,
DirLeftRightTopBottom = 8,
DirLeftTopBottom = 9,
DirRightTopBottom = 10,
DirBottom = 11,
DirTop = 12,
DirRight = 13,
DirLeft = 14,
DirMiddleSectionOnly = 15
};
[ propget, helpstring("Starting mapping index for a given terrain set.") ]
HRESULT TerrainStartTile([in] int terrainIndex, [out, retval] int *startMapping);
[ propput, helpstring("Sets the starting mapping index for a given terrain set.") ]
HRESULT TerrainStartTile([in] int terrainIndex, [in] int startMapping);
[ propget, helpstring("Ending mapping index for a given terrain set.") ]
HRESULT TerrainEndTile([in] int terrainIndex, [out, retval] int *endMapping);
[ propput, helpstring("Sets the ending mapping index for a given terrain set.") ]
HRESULT TerrainEndTile([in] int terrainIndex, [in] int endMapping);
[ propget, helpstring("Bulldozed tile index for a given terrain set.") ]
HRESULT TerrainDozed([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the bulldozed tile index for a given terrain set.") ]
HRESULT TerrainDozed([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Rubble tile index for a given terrain set.") ]
HRESULT TerrainRubble([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the rubble tile index for a given terrain set.") ]
HRESULT TerrainRubble([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Tube (unknown) index for a given terrain set.") ]
HRESULT TerrainTubeUnk([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the tube (unknown) index for a given terrain set.") ]
HRESULT TerrainTubeUnk([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Lava wall index for a given terrain set.") ]
HRESULT TerrainLavaWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the lava wall index for a given terrain set.") ]
HRESULT TerrainLavaWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Microbe wall index for a given terrain set.") ]
HRESULT TerrainMicrobeWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the microbe wall index for a given terrain set.") ]
HRESULT TerrainMicrobeWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Normal wall index for a given terrain set.") ]
HRESULT TerrainNormalWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the normal wall index for a given terrain set.") ]
HRESULT TerrainNormalWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Normal (damaged) wall index for a given terrain set.") ]
HRESULT TerrainDamagedWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the normal (damaged) wall index for a given terrain set.") ]
HRESULT TerrainDamagedWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Normal (ruined) wall index for a given terrain set.") ]
HRESULT TerrainRuinedWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the normal (ruined) wall index for a given terrain set.") ]
HRESULT TerrainRuinedWall([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Lava index for a given terrain set.") ]
HRESULT TerrainLava([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the lava index for a given terrain set.") ]
HRESULT TerrainLava([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Flat (1) index for a given terrain set.") ]
HRESULT TerrainFlat1([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the flat (1) index for a given terrain set.") ]
HRESULT TerrainFlat1([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Flat (2) index for a given terrain set.") ]
HRESULT TerrainFlat2([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the flat (2) index for a given terrain set.") ]
HRESULT TerrainFlat2([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Flat (3) index for a given terrain set.") ]
HRESULT TerrainFlat3([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the flat (3) index for a given terrain set.") ]
HRESULT TerrainFlat3([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Tube index for a given terrain set.") ]
HRESULT TerrainTube([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the tube index for a given terrain set.") ]
HRESULT TerrainTube([in] int terrainIndex, [in] enum TerrainTubeDirection direction, [in] int dataMapping);
[ propget, helpstring("Scorched tile index for a given terrain set.") ]
HRESULT TerrainScorched([in] int terrainIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the scorched tile index for a given terrain set.") ]
HRESULT TerrainScorched([in] int terrainIndex, [in] int dataMapping);
[ propget, helpstring("Unknown tile index for a given terrain set.") ]
HRESULT TerrainUnknown([in] int terrainIndex, [in] int unkIndex, [out, retval] int *dataMapping);
[ propput, helpstring("Sets the unknown tile index for a given terrain set.") ]
HRESULT TerrainUnknown([in] int terrainIndex, [in] int unkIndex, [in] int dataMapping);
}
// TileGroup
// Note: TileGroups which are part of a map will have their TileSetManager point
// to the TileSetManager of the containing map. Free floating TileGroups
// will have their own TileSetManager object and can be used for copy and
// paste operations between maps.
[
object, uuid(8E43C614-715F-41df-B376-CB0B55F29090), oleautomation, nonextensible,
helpstring("Used to copy and paste tiles between maps and to define tile groups for commonly grouped tiles.")
]
interface TileGroup : IUnknown
{
// Tile block dimensions
[ propget, helpstring("Width of group in tiles.") ]
HRESULT TileWidth([out, retval] int *tileWidth);
[ propget, helpstring("Height of group in tiles.") ]
HRESULT TileHeight([out, retval] int *tileHeight);
// TileSetManager access
[ propget, helpstring("Returns a TileSetManager object used to control the loaded tile sets for this map.") ]
HRESULT TileSetManager([out, retval] TileSetManager **tileSetManager);
// Tile info
[ propget, helpstring("Index into the tile mapping array of this tile. This array is used to tranlate a map tile index to the right tile set and right tile index in that tile set.") ]
HRESULT MappingIndex([in] int tileX, [in] int tileY, [out, retval] int *tileMappingIndex);
[ propput, helpstring("Sets the index into the tile mapping array of this tile.") ]
HRESULT MappingIndex([in] int tileX, [in] int tileY, [in] int tileMappingIndex);
// Display
// **TODO** Include more parameters:
// Zoom,
// flags (Normal, Passable/CellType display, LavaPossible, Lava, Blight, Wall or Building, Expand, Display Units/Map only)
[ helpstring("Draws a section of the tile group to the given device context at the desired location.") ]
HRESULT Draw([in] int destDC, [in] int sourcePixelX, [in] int sourcePixelY, [in] int pixelWidth, [in] int pixelHeight);
}
// MapFile (derived from TileGroup)
[
object, uuid(E1C7751A-AA0C-40b7-95C4-1693C86784FC), oleautomation, nonextensible,
helpstring("Map File interface used to access and display map data.")
]
interface MapFile : TileGroup
{
// Determines if map is Around-The-World type of map. (Determined by width)
[ propget, helpstring("Returns 1 if the map is set to Around-The-World mode and 0 otherwise.") ]
HRESULT AroundTheWorld([out, retval] int *bAroundTheWorld);
// Remove this? **TODO**
[ propget, helpstring("Returns 32-bit packed tile data at the specified location.") ]
HRESULT TileData([in] int tileX, [in] int tileY, [out, retval] int *tile);
[ propput, helpstring("Sets new 32-bit packed tile data at the specified location.") ]
HRESULT TileData([in] int tileX, [in] int tileY, [in] int newTile);
// Bit fields
[ propget, helpstring("Gets the CellType of the given tile. This controls the movement rate of units.") ]
HRESULT CellType([in] int tileX, [in] int tileY, [out, retval] int *cellType);
[ propput, helpstring("Sets the CellType of the given tile. This controls the movement rate of units.") ]
HRESULT CellType([in] int tileX, [in] int tileY, [in] int newCellType);
[ propget, helpstring("Gets the UnitIndex of the unit on this tile.") ]
HRESULT UnitIndex([in] int tileX, [in] int tileY, [out, retval] int *unitIndex);
[ propput, helpstring("Sets the UnitIndex of the unit on this tile.") ]
HRESULT UnitIndex([in] int tileX, [in] int tileY, [in] int newUnitIndex);
// Flags
[ propget, helpstring("Get the bit flag that determines if lava occupies this tile.") ]
HRESULT Lava([in] int tileX, [in] int tileY, [out, retval] int *lava);
[ propput, helpstring("Set the bit flag that determines if lava occupies this tile.") ]
HRESULT Lava([in] int tileX, [in] int tileY, [in] int lava);
[ propget, helpstring("Get the bit flag that determines if lava can occupy this tile.") ]
HRESULT LavaPossible([in] int tileX, [in] int tileY, [out, retval] int *lavaPossible);
[ propput, helpstring("Set the bit flag that determines if lava can occupy this tile.") ]
HRESULT LavaPossible([in] int tileX, [in] int tileY, [in] int lavaPossible);
[ propget, helpstring("Get the bit flag that determines if lava or microbe is expanding to this tile.") ]
HRESULT Expand([in] int tileX, [in] int tileY, [out, retval] int *expand);
[ propput, helpstring("Set the bit flag that determines if lava or microbe is expanding to this tile.") ]
HRESULT Expand([in] int tileX, [in] int tileY, [in] int expand);
[ propget, helpstring("Get the bit flag that determines if microbe (the Blight) occupies this tile.") ]
HRESULT Microbe([in] int tileX, [in] int tileY, [out, retval] int *microbe);
[ propput, helpstring("Set the bit flag that determines if micrboe (the Blight) occupies this tile.") ]
HRESULT Microbe([in] int tileX, [in] int tileY, [in] int microbe);
[ propget, helpstring("Get the bit flag that determines if a Wall or Building occupies this tile. (Non-moveable tile).") ]
HRESULT WallOrBuilding([in] int tileX, [in] int tileY, [out, retval] int *wallOrBuilding);
[ propput, helpstring("Set the bit flag that determines if a Wall or Building occupies this tile. (Non-moveable tile).") ]
HRESULT WallOrBuilding([in] int tileX, [in] int tileY, [in] int wallOrBuilding);
// Copy and paste tiles
[ helpstring("Copies a block of tiles from the map into a tile group.") ]
HRESULT Copy([in] int tileX1, [in] int tileY1, [in] int tileX2, [in] int tileY2, [out, retval] TileGroup **tileGroup);
[ helpstring("Pastes the given tile group to the given location of the map.") ]
HRESULT Paste([in] int tileX, [in] int tileY, [in] TileGroup *tileGroup);
// TileGroup access
[ propget, helpstring("Returns the number of tile groups stored with this map file.") ]
HRESULT NumTileGroups([out, retval] int *numTileGroups);
[ propget, helpstring("Returns the desired tile group stored with the map data.") ]
HRESULT TileGroup([in] int tileGroupIndex, [out, retval] TileGroup **tileGroup);
[ propget, helpstring("Tile group text tag.") ]
HRESULT TileGroupName([in] int tileGroupIndex, [out, retval] BSTR *tileGroupName);
[ propput, helpstring("Sets the tile group's text tag.") ]
HRESULT TileGroupName([in] int tileGroupIndex, [in] BSTR tileGroupName);
[ helpstring("Adds a tile group association to this map.") ]
HRESULT AddTileGroup([in] TileGroup *newTileGroup);
[ helpstring("Removes a tile group association with this map.") ]
HRESULT RemoveTileGroup([in] int tileGroupIndex);
[ v1_enum, helpstring("Enum used to control loading and saving of maps and saved games.") ]
enum MapLoadSaveFormat
{
MapOnly = 0, // Only map data that Outpost2.exe reads
TileGroups = 1, // All map data that Outpost2.exe reads, plus tile group info from end of map file
Units = 2, // All map data and unit data
SavedGameHeader = 4, // All map data and saved game header data
};
// Map data saving
[ helpstring("Save the Map data to an output stream.") ]
HRESULT SaveMap([in] StreamWriter *stream, [in] enum MapLoadSaveFormat saveFlags, [out, retval] int *status);
}
// ResourceManager
[
object, uuid(2A73E1A3-5FAA-4ac8-AC58-D28C77E780F0), oleautomation, nonextensible,
helpstring("Resource Manager interface used to locate and open resources.")
]
interface IResourceManager : IUnknown
{
[ propget, helpstring("Returns the root path of the game directory from which all resources are searched for.") ]
HRESULT RootPath([out, retval] BSTR *path);
[ propput, helpstring("Sets the root path to the game directory so all relative file names will be searched for from here.") ]
HRESULT RootPath([in] BSTR path);
[ helpstring("Opens the specified resource (a file and optionally a path) and returns a stream opened for reading. Note: If the file resides in an archive, the archive name can be specified as a directory in the file's path.") ]
HRESULT OpenStreamRead([in] BSTR fileName, [out, retval] StreamReader **stream);
[ helpstring("Opens the specified resource (a file and optionally a path) and returns a stream opened for writing. Note: If the file resides in an archive, the archive name can be specified as a directory in the file's path.") ]
HRESULT OpenStreamWrite([in] BSTR fileName, [out, retval] StreamWriter **stream);
[ helpstring("Loads a map from a given file.") ]
HRESULT LoadMapFile([in] BSTR fileName, [in] enum MapLoadSaveFormat loadFlags, [out, retval] MapFile **mapFile);
[ helpstring("Loads a map using data from the given input stream.") ]
HRESULT LoadMap([in] StreamReader *inStream, [in] enum MapLoadSaveFormat loadFlags, [out, retval] MapFile **mapFile);
[ helpstring("Creates a new map based on the specified parameters.") ]
HRESULT CreateNewMap([in] int width, [in] int height, [out, retval] MapFile **newMap);
[ helpstring("Loads a tile set from a given file.") ]
HRESULT LoadTileSetFile([in] BSTR fileName, [out, retval] TileSet **tileSet);
[ helpstring("Loads a tile set using data from the given input stream.") ]
HRESULT LoadTileSet([in] StreamReader *inStream, [out, retval] TileSet **tileSet);
[ helpstring("Creates a new tile set based on the specified parameters.") ]
HRESULT CreateTileSet([in] int numTiles, [in] int bitDepth, [in] int width, [out, retval] TileSet **newTileSet);
[ helpstring("Loads Vol data from a given file.") ]
HRESULT LoadVolFile([in] BSTR fileName, [in] int bAttachToStream, [out, retval] ArchiveReader **volReader);
[ helpstring("Loads Vol data from a given stream.") ]
HRESULT LoadVol([in] SeekableStreamReader *inStream, [in] int bAttachToStream, [out, retval] ArchiveReader **volReader);
[ helpstring("Creates a new VOL file saving the output to the given output stream.") ]
HRESULT CreateVolFile([out, retval] ArchiveWriter **volWriter);
[ helpstring("Loads Clm data from a given file.") ]
HRESULT LoadClmFile([in] BSTR fileName, [in] int bAttachToStream, [out, retval] ArchiveReader **clmReader);
[ helpstring("Loads Clm data from a given stream.") ]
HRESULT LoadClm([in] SeekableStreamReader *inStream, [in] int bAttachToStream, [out, retval] ArchiveReader **clmReader);
[ helpstring("Create a new CLM file saving the output to the given output stream.") ]
HRESULT CreateClmFile([out, retval] ArchiveWriter **clmWriter);
[ helpstring("Adds an archive's contents to the resource search path. Archives are searched in the order added.") ]
HRESULT AddArchiveToSearch([in] ArchiveReader *archiveReader);
[ helpstring("Removes all archives from the resource search path.") ]
HRESULT ClearSearchPath();
}
// ************
// Type Library
// ************
[
uuid(53FFC417-DCC3-44C1-BEF2-ACD5D3FD7412),
// **TODO** Update version number and helpstring
version(1.00),
helpstring("OP2Editor 1.00 Type Library."),
]
library OP2Editor
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[ uuid(C8DE4CDE-4554-4fe9-8688-A90D91EBCA0B) ]
coclass ResourceManager
{
[default] interface IResourceManager;
}
};

View File

@ -0,0 +1,125 @@
//Microsoft Developer Studio generated resource script.
//
#include "resource.h"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE DISCARDABLE
BEGIN
"1 TYPELIB ""OP2Editor.tlb""\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
#ifndef _MAC
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,1
PRODUCTVERSION 1,0,0,1
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
#else
FILEFLAGS 0x0L
#endif
FILEOS 0x4L
FILETYPE 0x2L
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "OP2Editor Module\0"
VALUE "FileVersion", "1, 0, 0, 1\0"
VALUE "InternalName", "OP2Editor\0"
VALUE "LegalCopyright", "Copyright 2004\0"
VALUE "OriginalFilename", "OP2Editor.DLL\0"
VALUE "ProductName", "OP2Editor Module\0"
VALUE "ProductVersion", "1, 0, 0, 1\0"
VALUE "OLESelfRegister", "\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END
#endif // !_MAC
/////////////////////////////////////////////////////////////////////////////
//
// REGISTRY
//
IDR_MapFile REGISTRY DISCARDABLE "MapFile.rgs"
/////////////////////////////////////////////////////////////////////////////
//
// String Table
//
STRINGTABLE DISCARDABLE
BEGIN
IDS_PROJNAME "OP2Editor"
IDS_MAPFILE_DESC "MapFile Class"
END
#endif // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
1 TYPELIB "OP2Editor.tlb"
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

Binary file not shown.

View File

@ -0,0 +1,80 @@
/* this file contains the actual definitions of */
/* the IIDs and CLSIDs */
/* link this file in with the server and any clients */
/* File created by MIDL compiler version 5.01.0164 */
/* at Fri Nov 11 16:06:01 2005
*/
/* Compiler settings for E:\op2\OP2Editor\OP2Editor.idl:
Oicf (OptLev=i2), W1, Zp8, env=Win32, ms_ext, c_ext
error checks: allocation ref bounds_check enum stub_data
*/
//@@MIDL_FILE_HEADING( )
#ifdef __cplusplus
extern "C"{
#endif
#ifndef __IID_DEFINED__
#define __IID_DEFINED__
typedef struct _IID
{
unsigned long x;
unsigned short s1;
unsigned short s2;
unsigned char c[8];
} IID;
#endif // __IID_DEFINED__
#ifndef CLSID_DEFINED
#define CLSID_DEFINED
typedef IID CLSID;
#endif // CLSID_DEFINED
const IID IID_StreamReader = {0x70AC9DEE,0xCE0F,0x4145,{0xA1,0x40,0x6A,0xE1,0xBA,0x65,0x8B,0x1E}};
const IID IID_SeekableStreamReader = {0x57B5FDD0,0x8E6E,0x4134,{0x94,0xDE,0x69,0x49,0xBD,0x2E,0xB3,0xCB}};
const IID IID_StreamWriter = {0xB83597A2,0x3471,0x48db,{0xB9,0xBC,0xEB,0x47,0x49,0xBA,0x1A,0xAA}};
const IID IID_ArchiveReader = {0xCE02B285,0xD2F4,0x4707,{0xB6,0xD3,0x39,0xCB,0x66,0x97,0x35,0x7C}};
const IID IID_ArchiveWriter = {0x98A6E750,0x10C7,0x4133,{0x9A,0x0E,0x17,0xFB,0x62,0xEC,0x6A,0xDE}};
const IID IID_TileSet = {0xC7F1E185,0x8079,0x4538,{0x96,0xCF,0x59,0x50,0x40,0x6A,0xE1,0xAA}};
const IID IID_TileSetSource = {0x153BC780,0x0FF2,0x44e4,{0x84,0x48,0x5B,0x3F,0x46,0x05,0x04,0x75}};
const IID IID_TileSetManager = {0x33A10A9E,0xA3B0,0x498f,{0xA8,0x71,0x3E,0xCC,0x78,0xB4,0x77,0xFB}};
const IID IID_TileGroup = {0x8E43C614,0x715F,0x41df,{0xB3,0x76,0xCB,0x0B,0x55,0xF2,0x90,0x90}};
const IID IID_MapFile = {0xE1C7751A,0xAA0C,0x40b7,{0x95,0xC4,0x16,0x93,0xC8,0x67,0x84,0xFC}};
const IID IID_IResourceManager = {0x2A73E1A3,0x5FAA,0x4ac8,{0xAC,0x58,0xD2,0x8C,0x77,0xE7,0x80,0xF0}};
const IID LIBID_OP2Editor = {0x53FFC417,0xDCC3,0x44C1,{0xBE,0xF2,0xAC,0xD5,0xD3,0xFD,0x74,0x12}};
const CLSID CLSID_ResourceManager = {0xC8DE4CDE,0x4554,0x4fe9,{0x86,0x88,0xA9,0x0D,0x91,0xEB,0xCA,0x0B}};
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
LIBRARY "OP2EditorPS"
DESCRIPTION 'Proxy/Stub DLL'
EXPORTS
DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
GetProxyDllInfo @3 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE

View File

@ -0,0 +1,16 @@
OP2Editorps.dll: dlldata.obj OP2Editor_p.obj OP2Editor_i.obj
link /dll /out:OP2Editorps.dll /def:OP2Editorps.def /entry:DllMain dlldata.obj OP2Editor_p.obj OP2Editor_i.obj \
kernel32.lib rpcndr.lib rpcns4.lib rpcrt4.lib oleaut32.lib uuid.lib \
.c.obj:
cl /c /Ox /DWIN32 /D_WIN32_WINNT=0x0400 /DREGISTER_PROXY_DLL \
$<
clean:
@del OP2Editorps.dll
@del OP2Editorps.lib
@del OP2Editorps.exp
@del dlldata.obj
@del OP2Editor_p.obj
@del OP2Editor_i.obj

View File

@ -0,0 +1,17 @@
// stdafx.cpp : source file that includes just the standard includes
// stdafx.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information
#include "stdafx.h"
#ifdef _ATL_STATIC_REGISTRY
#include <statreg.h>
#include <statreg.cpp>
#endif
#include <atlimpl.cpp>

View File

@ -0,0 +1,28 @@
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently,
// but are changed infrequently
#if !defined(AFX_STDAFX_H__58D1AFA0_FBD8_4350_BBD7_78E711596A7F__INCLUDED_)
#define AFX_STDAFX_H__58D1AFA0_FBD8_4350_BBD7_78E711596A7F__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#define STRICT
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0400
#endif
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
//You may derive a class from CComModule and use it if you want to override
//something, but do not change the name of _Module
extern CComModule _Module;
#include <atlcom.h>
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_STDAFX_H__58D1AFA0_FBD8_4350_BBD7_78E711596A7F__INCLUDED)

View File

@ -0,0 +1,37 @@
/*********************************************************
DllData file -- generated by MIDL compiler
DO NOT ALTER THIS FILE
This file is regenerated by MIDL on every IDL file compile.
To completely reconstruct this file, delete it and rerun MIDL
on all the IDL files in this DLL, specifying this file for the
/dlldata command line option
*********************************************************/
#include <rpcproxy.h>
#ifdef __cplusplus
extern "C" {
#endif
EXTERN_PROXY_FILE( OP2Editor )
PROXYFILE_LIST_START
/* Start of list */
REFERENCE_PROXY_FILE( OP2Editor ),
/* End of list */
PROXYFILE_LIST_END
DLLDATA_ROUTINES( aProxyFileList, GET_DLL_CLSID )
#ifdef __cplusplus
} /*extern "C" */
#endif
/* end of generated dlldata file */

View File

@ -0,0 +1,18 @@
//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by OP2Editor.rc
//
#define IDS_PROJNAME 100
#define IDS_MAPFILE_DESC 101
#define IDR_MapFile 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 201
#define _APS_NEXT_COMMAND_VALUE 32768
#define _APS_NEXT_CONTROL_VALUE 201
#define _APS_NEXT_SYMED_VALUE 103
#endif
#endif