diff --git a/LEGO1/mxioinfo.cpp b/LEGO1/mxioinfo.cpp index ebe2a480..09b5f194 100644 --- a/LEGO1/mxioinfo.cpp +++ b/LEGO1/mxioinfo.cpp @@ -1,4 +1,5 @@ #include "mxioinfo.h" +#include "ddraw.h" // OFFSET: LEGO1 0x100cc800 MXIOINFO::MXIOINFO() @@ -12,38 +13,331 @@ MXIOINFO::~MXIOINFO() Close(0); } +// OFFSET: LEGO1 0x100cc8e0 +unsigned short MXIOINFO::Close(long arg) +{ + short result = 0; + if (m_info.hmmio != NULL) + { + result = Flush(0); + + _lclose((HFILE)m_info.hmmio); + m_info.hmmio = NULL; + + if (m_info.dwFlags & MMIO_ALLOCBUF) + free(m_info.pchBuffer); + + m_info.pchEndWrite = NULL; + m_info.pchEndRead = NULL; + m_info.pchBuffer = NULL; + m_info.dwFlags = 0; + } + return result; +} + // OFFSET: LEGO1 0x100cc830 unsigned short MXIOINFO::Open(const char *filename, DWORD fdwOpen) { - return 0; -} - -// OFFSET: LEGO1 0x100cc8e0 -void MXIOINFO::Close(long arg) -{ - + _OFSTRUCT lpReOpenBuff; + unsigned short result = 0; + + m_info.lBufOffset = 0; + m_info.lDiskOffset = 0; + m_info.hmmio = (HMMIO)OpenFile(filename, &lpReOpenBuff, (unsigned short)fdwOpen); + + if (m_info.hmmio != (HMMIO)HFILE_ERROR) + { + m_info.dwFlags = fdwOpen; + if (m_info.dwFlags & MMIO_ALLOCBUF) + { + long currentLength = m_info.cchBuffer != 0 ? m_info.cchBuffer : 0x2000; + + char* buffer = (char*)malloc(currentLength); + if (buffer == NULL) + { + m_info.cchBuffer = 0; + m_info.dwFlags &= ~MMIO_ALLOCBUF; + m_info.pchBuffer = NULL; + result = MMIOERR_OUTOFMEMORY; + } + else + { + m_info.cchBuffer = currentLength; + m_info.pchBuffer = buffer; + } + m_info.pchEndRead = m_info.pchBuffer; + m_info.pchNext = m_info.pchBuffer; + m_info.pchEndWrite = m_info.pchBuffer + m_info.cchBuffer; + } + } + else + { + result = MMIOERR_CANNOTOPEN; + } + return result; } +// Not close to a match yet. // OFFSET: LEGO1 0x100cc930 unsigned long MXIOINFO::Read(HPSTR pch, LONG cch) { - return 0; + long result = 0; + if (m_info.pchBuffer != NULL) + { + LONG toRead = m_info.pchEndRead - m_info.pchNext; + unsigned long remaining = cch; + do + { + if (toRead > 0) { + if (toRead > remaining) { + toRead = remaining; + } + remaining -= toRead; + memcpy(pch, m_info.pchNext, toRead); + m_info.pchNext += toRead; + } + } while (remaining && !Something(0) && m_info.pchEndRead - m_info.pchNext >= 1); + } + else + { + if (m_info.hmmio != NULL && cch > 0) { + result = _hread((HFILE)m_info.hmmio, pch, cch); + if (result == -1) { + result = 0; + m_info.lDiskOffset = GetCurrentOffset(); + } + else + { + m_info.lDiskOffset += result; + } + } + } + + return result; } +// First attemp, not particularly close, see some sensible logic of what the +// function is trying to do. // OFFSET: LEGO1 0x100cca00 LONG MXIOINFO::Seek(LONG lOffset, int iOrigin) { - return 0; + LONG result = -1; + if (m_info.pchBuffer != NULL) + { + // Convert to SEEK_SET + if (iOrigin == SEEK_CUR) { + if (lOffset == 0) { + // Nothing to do + return (LONG)(m_info.pchNext + m_info.lBufOffset - m_info.pchBuffer); + } else { + iOrigin = 0; + lOffset = (LONG)(m_info.pchNext + lOffset + m_info.lBufOffset - m_info.pchBuffer); + } + } else if (iOrigin == SEEK_END) { + // Not implemented + return -1; + } + + // Seek distance is already within the buffer + if ((m_info.lBufOffset <= lOffset) && (lOffset < m_info.cchBuffer + m_info.lBufOffset)) { + m_info.pchNext = m_info.pchBuffer + lOffset - m_info.lBufOffset; + return lOffset; + } + + // Do SEEK_CUR on the underlying file handle + if (m_info.hmmio != NULL) { + short result = Flush(0); + if (result == 0) { + LONG newOffset = _llseek((HFILE)m_info.hmmio, lOffset, iOrigin); + m_info.lDiskOffset = newOffset; + if (newOffset == -1) { + m_info.lDiskOffset = GetCurrentOffset(); + return -1; + } + LONG wholeBlockOffset = lOffset - (int)(lOffset % m_info.cchBuffer); + m_info.lBufOffset = wholeBlockOffset; + if (lOffset != wholeBlockOffset) { + LONG newOffset2 = _llseek((HFILE)m_info.hmmio, wholeBlockOffset, 0); + m_info.lDiskOffset = newOffset2; + if (newOffset2 == -1) { + m_info.lDiskOffset = GetCurrentOffset(); + } + } + if (m_info.lDiskOffset == m_info.lBufOffset) { + DWORD rw = m_info.dwFlags & MMIO_RWMODE; + if (rw != MMIO_READ && rw != MMIO_READWRITE) { + m_info.pchNext = m_info.pchBuffer + lOffset - m_info.lBufOffset; + return lOffset; + } + LONG bytesRead = _hread((HFILE)m_info.hmmio, m_info.pchBuffer, m_info.cchBuffer); + if (bytesRead == -1) { + m_info.lDiskOffset = GetCurrentOffset(); + return -1; + } + m_info.lDiskOffset += bytesRead; + m_info.pchNext = m_info.pchBuffer + lOffset - m_info.lBufOffset; + m_info.pchEndRead = m_info.pchBuffer + bytesRead; + if (m_info.pchNext < m_info.pchEndRead) { + return lOffset; + } + } + } + } + } + else + { + if (m_info.hmmio != NULL) { + if ((iOrigin == SEEK_CUR) && (lOffset == 0)) { + return m_info.lDiskOffset; + } + result = _llseek((HFILE)m_info.hmmio, lOffset, iOrigin); + m_info.lDiskOffset = result; + if (result == HFILE_ERROR) { + m_info.lDiskOffset = GetCurrentOffset(); + } + } + } + return result; } +// Matching except for swap of EAX and ECX // OFFSET: LEGO1 0x100ccbc0 -void MXIOINFO::SetBuffer(LPSTR pchBuffer, LONG cchBuffer, LONG unk) +unsigned short MXIOINFO::SetBuffer(LPSTR pchBuffer, LONG cchBuffer, UINT fuBuffer) { - + unsigned short ret = Flush(0); + if (m_info.dwFlags & MMIO_ALLOCBUF) + { + m_info.dwFlags &= ~MMIO_ALLOCBUF; + free(m_info.pchBuffer); + } + m_info.pchBuffer = pchBuffer; + m_info.cchBuffer = cchBuffer; + m_info.pchEndRead = pchBuffer; + m_info.pchEndWrite = pchBuffer + cchBuffer; + return ret; } // OFFSET: LEGO1 0x100cce60 unsigned short MXIOINFO::Descend(LPMMCKINFO pmmcki, const MMCKINFO *pmmckiParent, UINT fuDescend) { return 0; +} + +// Not a close match, but the behavior looks reasonable. +// OFFSET: LEGO1 0x100ccc10 +unsigned short MXIOINFO::Flush(int arg) +{ + unsigned short result = 0; + if (m_info.dwFlags & MMIO_DIRTY) + { + if (m_info.pchBuffer == NULL) + { + result = MMIOERR_UNBUFFERED; + } + else + { + if (m_info.hmmio == NULL || (m_info.dwFlags & MMIO_RWMODE) == 0) + { + return MMIOERR_CANNOTWRITE; + } + if (m_info.cchBuffer > 0) + { + if (m_info.lDiskOffset != m_info.lBufOffset) + { + m_info.lDiskOffset = _llseek((HFILE)m_info.hmmio, m_info.lBufOffset, 0); + } + if (m_info.lBufOffset == m_info.lDiskOffset) + { + long written = _hwrite((HFILE)m_info.hmmio, m_info.pchBuffer, m_info.cchBuffer); + if (written != -1 && m_info.cchBuffer == written) + { + m_info.lDiskOffset += written; + m_info.dwFlags &= ~MMIO_DIRTY; + m_info.pchNext = m_info.pchBuffer; + return 0; + } + m_info.lDiskOffset = GetCurrentOffset(); + return MMIOERR_CANNOTWRITE; + } + m_info.lDiskOffset = GetCurrentOffset(); + return MMIOERR_CANNOTSEEK; + } + } + } + return result; +} + +// 97% Match, just two locations have the order of an == comparison swapped. +// I suspect this isn't how the code was originally written, because I have to +// include an empty if branch to get the code almost matching, though it is a +// place where you logically could have an empty block. +// OFFSET: LEGO1 0x100ccd00 +unsigned short MXIOINFO::Something(UINT flags) +{ + short result = 0; + DWORD rwState = m_info.dwFlags & MMIO_RWMODE; + if (m_info.pchBuffer != NULL) + { + LONG cchBuffer = m_info.cchBuffer; + if (((rwState == MMIO_WRITE) || (rwState == MMIO_READWRITE)) && (m_info.dwFlags & MMIO_DIRTY)) + { + if (((flags & MMIO_WRITE) || (rwState == MMIO_READWRITE)) && (cchBuffer > 0)) + { + if (m_info.lDiskOffset != m_info.lBufOffset) { + m_info.lDiskOffset = _llseek((HFILE)m_info.hmmio, m_info.lBufOffset, 0); + } + if (m_info.lDiskOffset != m_info.lBufOffset) + { + result = MMIOERR_CANNOTSEEK; + m_info.lDiskOffset = GetCurrentOffset(); + } + else + { + LONG bytesWritten = _hwrite((HFILE)m_info.hmmio, m_info.pchBuffer, cchBuffer); + if ((bytesWritten != -1) && (cchBuffer == bytesWritten)) { + m_info.lDiskOffset += bytesWritten; + m_info.dwFlags = m_info.dwFlags & ~MMIO_DIRTY; + m_info.pchNext = m_info.pchBuffer; + m_info.pchEndRead = m_info.pchBuffer; + } + else + { + result = MMIOERR_CANNOTWRITE; + m_info.lDiskOffset = GetCurrentOffset(); + } + } + } + } + + m_info.lBufOffset = m_info.lBufOffset + cchBuffer; + if (((rwState != MMIO_READ) && (rwState != MMIO_READWRITE)) || cchBuffer <= 0) { + // Nothing to do + } + else + { + if (m_info.lDiskOffset != m_info.lBufOffset) { + m_info.lDiskOffset = _llseek((HFILE)m_info.hmmio, m_info.lBufOffset, 0); + } + if (m_info.lDiskOffset != m_info.lBufOffset) { + result = MMIOERR_CANNOTSEEK; + m_info.lDiskOffset = GetCurrentOffset(); + } else { + LONG bytesRead = _hread((HFILE)m_info.hmmio, m_info.pchBuffer, cchBuffer); + if (bytesRead == -1) { + result = MMIOERR_CANNOTREAD; + m_info.lDiskOffset = GetCurrentOffset(); + } else { + m_info.lDiskOffset += bytesRead; + m_info.pchNext = m_info.pchBuffer; + m_info.pchEndRead = m_info.pchBuffer + bytesRead; + return result; + } + } + } + } + else + { + result = MMIOERR_UNBUFFERED; + } + return result; } \ No newline at end of file diff --git a/LEGO1/mxioinfo.h b/LEGO1/mxioinfo.h index c88a55b9..32d161a1 100644 --- a/LEGO1/mxioinfo.h +++ b/LEGO1/mxioinfo.h @@ -12,11 +12,15 @@ class MXIOINFO __declspec(dllexport) ~MXIOINFO(); unsigned short Open(const char *filename, DWORD fdwOpen); - void Close(long arg); + unsigned short Close(long arg); LONG Seek(LONG lOffset, int iOrigin); unsigned long Read(HPSTR pch, LONG cch); - void SetBuffer(LPSTR pchBuffer, LONG cchBuffer, LONG unk); + unsigned short SetBuffer(LPSTR pchBuffer, LONG cchBuffer, UINT fuBuffer); unsigned short Descend(LPMMCKINFO pmmcki, const MMCKINFO *pmmckiParent, UINT fuDescend); + unsigned short Flush(int arg); + unsigned short Something(UINT flags); + + inline LONG GetCurrentOffset() { return _llseek((HFILE)m_info.hmmio, 0, SEEK_CUR); } MMIOINFO m_info; };