Add OP2Editor project for the map editor backend (DLL).
git-svn-id: https://svn.outpostuniverse.org:8443/svn/outpost2@1051 7b3b2116-5498-11dd-abe4-fb2d8bf8a5a8master
parent
0124737576
commit
96c4c93763
|
@ -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
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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)¤t->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;
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
@ -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--;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
||||
};
|
|
@ -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--;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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--;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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)§Head, &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)§Head, &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)§Head, &numBytesWritten);
|
||||
// Write the "head" section of the "PBMP" section
|
||||
sectHead.tag = 'daeh'; // head tag
|
||||
sectHead.size = sizeof(headInfo) + 4;
|
||||
stream->Write(sizeof(sectHead), (int)§Head, &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)§Head, &numBytesWritten);
|
||||
// Write the "head" section of the "PPAL" section
|
||||
sectHead.tag = 'daeh'; // head tag
|
||||
sectHead.size = 4;
|
||||
numSectionsLeft = 1;
|
||||
stream->Write(sizeof(sectHead), (int)§Head, &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)§Head, &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)§Head, &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
|
||||
}
|
|
@ -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
|
@ -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[];
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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)§Head, &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)§Head, &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)§Head, &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)§Head, &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)§Head, &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)§Head, &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;
|
||||
}
|
|
@ -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
|
||||
};
|
|
@ -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)§Head, &numBytesWritten);
|
||||
|
||||
// "volh" section
|
||||
sectHead.tag = 'hlov'; // "volh"
|
||||
sectHead.sectionSize = 0;
|
||||
outStream->Write(sizeof(sectHead), (int)§Head, &numBytesWritten);
|
||||
|
||||
// "vols" section
|
||||
sectHead.tag = 'slov'; // "vols"
|
||||
sectHead.sectionSize = stringSectionSize;
|
||||
outStream->Write(sizeof(sectHead), (int)§Head, &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)§Head, &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)¤t->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)§Head, &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;
|
||||
}
|
|
@ -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;
|
||||
};
|
|
@ -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;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
|
||||
|
||||
|
||||
void PostErrorMsg(WCHAR *errorMsg);
|
||||
bool IsRelative(BSTR path);
|
||||
int RoundUpPowerOf2(int num);
|
||||
int LogBase2(int num);
|
|
@ -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'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
@ -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;
|
||||
}
|
||||
};
|
|
@ -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.
|
@ -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
|
@ -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
|
|
@ -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
|
|
@ -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>
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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)
|
||||
|
|
@ -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 */
|
|
@ -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
|
Loading…
Reference in New Issue