mirror of
				https://github.com/isledecomp/isle.git
				synced 2025-10-25 09:24:17 +00:00 
			
		
		
		
	 494a556f8e
			
		
	
	494a556f8e
	
	
	
		
			
			* Adjustments to "decomp" language * Fix a comment * Fix accidental clang-formatting * Fix order * Fix order * Remove junk * Fix OFFSET * Adjustments based on new suggestions * Annotate globals * Globals in ISLE * More globals * Merge from parser2 branch * Allow prepending space for exact marker match * To eliminate noise, require the 0x prefix on offset for marker match * fix test from previous * Count tab stops for indented functions to reduce MISSED_END_OF_FUNCTION noise * FUNCTION to SYNTHETIC where needed * Missed marker conversion on SetAtomId * pylint cleanup, remove unused code * Fix unexpected function end, add more unit tests * Be more strict about synthetic name syntax * Revert "Missed marker conversion on SetAtomId" This reverts commitd87d665127. * Revert "FUNCTION to SYNTHETIC where needed" This reverts commit8c815418d2. * Implicit lookup by name for functions * Fix VTABLE SYNTHETIC and other decomp markers * Get vtable class name * Vtable marker should identify struct * No colon for SIZE comment * Update README.md * Update README.md * Update CONTRIBUTING.md * Update README.md * Update README.md * Update CONTRIBUTING.md * Update README.md * Update CONTRIBUTING.md * Fix destructor/annotation * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md --------- Co-authored-by: disinvite <disinvite@users.noreply.github.com>
		
			
				
	
	
		
			461 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			461 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "mxioinfo.h"
 | |
| 
 | |
| #include "decomp.h"
 | |
| 
 | |
| // This class should be 72 bytes in size, same as the MMIOINFO struct.
 | |
| // The current implementation has MMIOINFO as the only member of the class,
 | |
| // but this assert will enforce the size if we decide to change that.
 | |
| DECOMP_SIZE_ASSERT(MXIOINFO, sizeof(MMIOINFO));
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cc800
 | |
| MXIOINFO::MXIOINFO()
 | |
| {
 | |
| 	memset(&m_info, 0, sizeof(m_info));
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cc820
 | |
| MXIOINFO::~MXIOINFO()
 | |
| {
 | |
| 	Close(0);
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cc830
 | |
| MxU16 MXIOINFO::Open(const char* p_filename, MxULong p_flags)
 | |
| {
 | |
| 	OFSTRUCT _unused;
 | |
| 	MxU16 result = 0;
 | |
| 
 | |
| 	m_info.lBufOffset = 0;
 | |
| 	m_info.lDiskOffset = 0;
 | |
| 
 | |
| 	// DECOMP: Cast of p_flags to u16 forces the `movzx` instruction
 | |
| 	m_info.hmmio = (HMMIO) OpenFile(p_filename, &_unused, (MxU16) p_flags);
 | |
| 
 | |
| 	if ((HFILE) m_info.hmmio != HFILE_ERROR) {
 | |
| 		m_info.dwFlags = p_flags;
 | |
| 		if (p_flags & MMIO_ALLOCBUF) {
 | |
| 
 | |
| 			// Default buffer length of 8k if none specified
 | |
| 			MxLong len = m_info.cchBuffer ? m_info.cchBuffer : 8192;
 | |
| 			HPSTR buf = new char[len];
 | |
| 
 | |
| 			if (!buf) {
 | |
| 				result = MMIOERR_OUTOFMEMORY;
 | |
| 				m_info.cchBuffer = 0;
 | |
| 				m_info.dwFlags &= ~MMIO_ALLOCBUF;
 | |
| 				m_info.pchBuffer = 0;
 | |
| 			}
 | |
| 			else {
 | |
| 				m_info.pchBuffer = buf;
 | |
| 				m_info.cchBuffer = len;
 | |
| 			}
 | |
| 
 | |
| 			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;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cc8e0
 | |
| MxU16 MXIOINFO::Close(MxLong p_unused)
 | |
| {
 | |
| 	MxU16 result = 0;
 | |
| 
 | |
| 	if (m_info.hmmio) {
 | |
| 		result = Flush(0);
 | |
| 		_lclose((HFILE) m_info.hmmio);
 | |
| 		m_info.hmmio = 0;
 | |
| 
 | |
| 		if (m_info.dwFlags & MMIO_ALLOCBUF)
 | |
| 			delete[] m_info.pchBuffer;
 | |
| 
 | |
| 		m_info.pchEndWrite = 0;
 | |
| 		m_info.pchEndRead = 0;
 | |
| 		m_info.pchBuffer = 0;
 | |
| 		m_info.dwFlags = 0;
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cc930
 | |
| MxLong MXIOINFO::Read(void* p_buf, MxLong p_len)
 | |
| {
 | |
| 	MxLong bytes_read = 0;
 | |
| 
 | |
| 	if (m_info.pchBuffer) {
 | |
| 
 | |
| 		MxLong bytes_left = m_info.pchEndRead - m_info.pchNext;
 | |
| 		while (p_len > 0) {
 | |
| 
 | |
| 			if (bytes_left > 0) {
 | |
| 				if (p_len < bytes_left)
 | |
| 					bytes_left = p_len;
 | |
| 
 | |
| 				memcpy(p_buf, m_info.pchNext, bytes_left);
 | |
| 				p_len -= bytes_left;
 | |
| 
 | |
| 				m_info.pchNext += bytes_left;
 | |
| 				bytes_read += bytes_left;
 | |
| 			}
 | |
| 
 | |
| 			if (p_len <= 0 || Advance(0))
 | |
| 				break;
 | |
| 
 | |
| 			bytes_left = m_info.pchEndRead - m_info.pchNext;
 | |
| 			if (bytes_left <= 0)
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 	else if (m_info.hmmio && p_len > 0) {
 | |
| 		bytes_read = _hread((HFILE) m_info.hmmio, p_buf, p_len);
 | |
| 
 | |
| 		if (bytes_read == -1) {
 | |
| 			bytes_read = 0;
 | |
| 			m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 		}
 | |
| 		else {
 | |
| 			m_info.lDiskOffset += bytes_read;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return bytes_read;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cca00
 | |
| MxLong MXIOINFO::Seek(MxLong p_offset, MxLong p_origin)
 | |
| {
 | |
| 	MxLong result = -1;
 | |
| 
 | |
| 	// If buffered I/O
 | |
| 	if (m_info.pchBuffer) {
 | |
| 		if (p_origin == SEEK_CUR) {
 | |
| 			if (!p_offset) {
 | |
| 				// don't seek at all and just return where we are.
 | |
| 				return m_info.lBufOffset + (m_info.pchNext - m_info.pchBuffer);
 | |
| 			}
 | |
| 			else {
 | |
| 				// With SEEK_CUR, p_offset is a relative offset.
 | |
| 				// Get the absolute position instead and use SEEK_SET.
 | |
| 				p_offset += m_info.lBufOffset + (m_info.pchNext - m_info.pchBuffer);
 | |
| 				p_origin = SEEK_SET;
 | |
| 			}
 | |
| 		}
 | |
| 		else if (p_origin == SEEK_END) {
 | |
| 			// not possible with buffered I/O
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		// else p_origin == SEEK_SET.
 | |
| 
 | |
| 		// is p_offset between the start and end of the buffer?
 | |
| 		// i.e. can we do the seek without reading more from disk?
 | |
| 		if (p_offset >= m_info.lBufOffset && p_offset < m_info.lBufOffset + m_info.cchBuffer) {
 | |
| 			m_info.pchNext = m_info.pchBuffer + (p_offset - m_info.lBufOffset);
 | |
| 			result = p_offset;
 | |
| 		}
 | |
| 		else {
 | |
| 			// we have to read another chunk from disk.
 | |
| 			if (m_info.hmmio && !Flush(0)) {
 | |
| 				m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, p_offset, p_origin);
 | |
| 
 | |
| 				if (m_info.lDiskOffset == -1) {
 | |
| 					m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 				}
 | |
| 				else {
 | |
| 
 | |
| 					// align offset to buffer size
 | |
| 					MxLong new_offset = p_offset - (p_offset % m_info.cchBuffer);
 | |
| 					m_info.lBufOffset = new_offset;
 | |
| 
 | |
| 					// do we need to seek again?
 | |
| 					// (i.e. are we already aligned to buffer size?)
 | |
| 					if (p_offset != new_offset) {
 | |
| 						m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, new_offset, SEEK_SET);
 | |
| 
 | |
| 						if (m_info.lDiskOffset == -1) {
 | |
| 							m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 						}
 | |
| 					}
 | |
| 
 | |
| 					if (m_info.lBufOffset == m_info.lDiskOffset) {
 | |
| 						// is the file open for writing only?
 | |
| 						if ((m_info.dwFlags & MMIO_RWMODE) && ((m_info.dwFlags & MMIO_RWMODE) != MMIO_READWRITE)) {
 | |
| 
 | |
| 							m_info.pchNext = m_info.pchBuffer - m_info.lBufOffset + p_offset;
 | |
| 
 | |
| 							result = p_offset;
 | |
| 						}
 | |
| 						else {
 | |
| 							// We can read from the file. Fill the buffer.
 | |
| 							MxLong bytes_read = _hread((HFILE) m_info.hmmio, m_info.pchBuffer, m_info.cchBuffer);
 | |
| 
 | |
| 							if (bytes_read == -1) {
 | |
| 								m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 							}
 | |
| 							else {
 | |
| 								m_info.lDiskOffset += bytes_read;
 | |
| 								m_info.pchNext = p_offset - m_info.lBufOffset + m_info.pchBuffer;
 | |
| 								m_info.pchEndRead = m_info.pchBuffer + bytes_read;
 | |
| 
 | |
| 								if (m_info.pchNext < m_info.pchEndRead) {
 | |
| 									result = p_offset;
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		// No buffer so just seek the file directly (if we have a valid handle)
 | |
| 		if (m_info.hmmio) {
 | |
| 			// i.e. if we just want to get the current file position
 | |
| 			if (p_origin == SEEK_CUR && p_offset == 0) {
 | |
| 				return m_info.lDiskOffset;
 | |
| 			}
 | |
| 			else {
 | |
| 				m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, p_offset, p_origin);
 | |
| 
 | |
| 				result = m_info.lDiskOffset;
 | |
| 
 | |
| 				if (result == -1) {
 | |
| 					m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100ccbc0
 | |
| MxU16 MXIOINFO::SetBuffer(char* p_buf, MxLong p_len, MxLong p_unused)
 | |
| {
 | |
| 	MxU16 result = Flush(0);
 | |
| 
 | |
| 	if (m_info.dwFlags & MMIO_ALLOCBUF) {
 | |
| 		m_info.dwFlags &= ~MMIO_ALLOCBUF;
 | |
| 		delete[] m_info.pchBuffer;
 | |
| 	}
 | |
| 
 | |
| 	m_info.pchBuffer = p_buf;
 | |
| 	m_info.cchBuffer = p_len;
 | |
| 	m_info.pchEndWrite = m_info.pchBuffer + m_info.cchBuffer;
 | |
| 	m_info.pchEndRead = m_info.pchBuffer;
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100ccc10
 | |
| MxU16 MXIOINFO::Flush(MxU16 p_unused)
 | |
| {
 | |
| 	MxU16 result = 0;
 | |
| 
 | |
| 	// if buffer is dirty
 | |
| 	if (m_info.dwFlags & MMIO_DIRTY) {
 | |
| 		// if we have allocated an IO buffer
 | |
| 		if (m_info.pchBuffer) {
 | |
| 			// if we have a file open for writing
 | |
| 			if (m_info.hmmio && (m_info.dwFlags & MMIO_RWMODE)) {
 | |
| 				// DECOMP: pulling this value out into a variable forces it into EBX
 | |
| 				MxLong cchBuffer = m_info.cchBuffer;
 | |
| 				if (cchBuffer > 0) {
 | |
| 					if (m_info.lBufOffset != m_info.lDiskOffset) {
 | |
| 						m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET);
 | |
| 					}
 | |
| 
 | |
| 					// Was the previous seek (if required) successful?
 | |
| 					if (m_info.lBufOffset != m_info.lDiskOffset) {
 | |
| 						result = MMIOERR_CANNOTSEEK;
 | |
| 						m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 					}
 | |
| 					else {
 | |
| 						MxLong bytes_written = _hwrite((HFILE) m_info.hmmio, m_info.pchBuffer, cchBuffer);
 | |
| 
 | |
| 						if (bytes_written != -1 && bytes_written == cchBuffer) {
 | |
| 							m_info.lDiskOffset += bytes_written;
 | |
| 							m_info.pchNext = m_info.pchBuffer;
 | |
| 							m_info.dwFlags &= ~MMIO_DIRTY;
 | |
| 						}
 | |
| 						else {
 | |
| 							result = MMIOERR_CANNOTWRITE;
 | |
| 							m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			else {
 | |
| 				result = MMIOERR_CANNOTWRITE;
 | |
| 			}
 | |
| 		}
 | |
| 		else {
 | |
| 			result = MMIOERR_UNBUFFERED;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100ccd00
 | |
| MxU16 MXIOINFO::Advance(MxU16 p_option)
 | |
| {
 | |
| 	MxU16 result = 0;
 | |
| 	MxULong rwmode = m_info.dwFlags & MMIO_RWMODE;
 | |
| 
 | |
| 	if (m_info.pchBuffer) {
 | |
| 		MxLong cch = m_info.cchBuffer;
 | |
| 
 | |
| 		// If we can and should write to the file,
 | |
| 		// if we are being asked to write to the file,
 | |
| 		// and if there is a buffer *to* write:
 | |
| 		if ((rwmode == MMIO_WRITE || rwmode == MMIO_READWRITE) && (m_info.dwFlags & MMIO_DIRTY) &&
 | |
| 			((p_option & MMIO_WRITE) || (rwmode == MMIO_READWRITE)) && cch > 0) {
 | |
| 
 | |
| 			if (m_info.lBufOffset != m_info.lDiskOffset) {
 | |
| 				m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET);
 | |
| 			}
 | |
| 
 | |
| 			if (m_info.lBufOffset != m_info.lDiskOffset) {
 | |
| 				result = MMIOERR_CANNOTSEEK;
 | |
| 			}
 | |
| 			else {
 | |
| 				MxLong bytes_written = _hwrite((HFILE) m_info.hmmio, m_info.pchBuffer, cch);
 | |
| 
 | |
| 				if (bytes_written != -1 && bytes_written == cch) {
 | |
| 					m_info.lDiskOffset += bytes_written;
 | |
| 					m_info.pchNext = m_info.pchBuffer;
 | |
| 					m_info.pchEndRead = m_info.pchBuffer;
 | |
| 					m_info.dwFlags &= ~MMIO_DIRTY;
 | |
| 				}
 | |
| 				else {
 | |
| 					result = MMIOERR_CANNOTWRITE;
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 		}
 | |
| 
 | |
| 		m_info.lBufOffset += cch;
 | |
| 		if ((!rwmode || rwmode == MMIO_READWRITE) && cch > 0) {
 | |
| 			if (m_info.lBufOffset != m_info.lDiskOffset) {
 | |
| 				m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, m_info.lBufOffset, SEEK_SET);
 | |
| 			}
 | |
| 
 | |
| 			// if previous seek failed
 | |
| 			if (m_info.lBufOffset != m_info.lDiskOffset) {
 | |
| 				result = MMIOERR_CANNOTSEEK;
 | |
| 				m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 			}
 | |
| 			else {
 | |
| 				MxLong bytes_read = _hread((HFILE) m_info.hmmio, m_info.pchBuffer, cch);
 | |
| 
 | |
| 				if (bytes_read == -1) {
 | |
| 					result = MMIOERR_CANNOTREAD;
 | |
| 					m_info.lDiskOffset = _llseek((HFILE) m_info.hmmio, 0, SEEK_CUR);
 | |
| 				}
 | |
| 				else {
 | |
| 					m_info.lDiskOffset += bytes_read;
 | |
| 					m_info.pchNext = m_info.pchBuffer;
 | |
| 					m_info.pchEndRead = m_info.pchBuffer + bytes_read;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		result = MMIOERR_UNBUFFERED;
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| // FUNCTION: LEGO1 0x100cce60
 | |
| MxU16 MXIOINFO::Descend(MMCKINFO* p_chunkInfo, const MMCKINFO* p_parentInfo, MxU16 p_descend)
 | |
| {
 | |
| 	MxU16 result = 0;
 | |
| 
 | |
| 	if (!p_chunkInfo)
 | |
| 		return MMIOERR_BASE; // ?
 | |
| 
 | |
| 	if (!p_descend) {
 | |
| 		p_chunkInfo->dwFlags = 0;
 | |
| 		if (Read(p_chunkInfo, 8) != 8) {
 | |
| 			result = MMIOERR_CANNOTREAD;
 | |
| 		}
 | |
| 		else {
 | |
| 			if (m_info.pchBuffer) {
 | |
| 				p_chunkInfo->dwDataOffset = m_info.pchNext - m_info.pchBuffer + m_info.lBufOffset;
 | |
| 			}
 | |
| 			else {
 | |
| 				p_chunkInfo->dwDataOffset = m_info.lDiskOffset;
 | |
| 			}
 | |
| 
 | |
| 			if ((p_chunkInfo->ckid == FOURCC_RIFF || p_chunkInfo->ckid == FOURCC_LIST) &&
 | |
| 				Read(&p_chunkInfo->fccType, 4) != 4) {
 | |
| 				result = MMIOERR_CANNOTREAD;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	else {
 | |
| 		MxULong ofs = MAXLONG;
 | |
| 
 | |
| 		if (p_parentInfo)
 | |
| 			ofs = p_parentInfo->cksize + p_parentInfo->dwDataOffset;
 | |
| 
 | |
| 		BOOL running = TRUE;
 | |
| 		BOOL read_ok = FALSE;
 | |
| 		MMCKINFO tmp;
 | |
| 		tmp.dwFlags = 0;
 | |
| 
 | |
| 		while (running) {
 | |
| 			if (Read(&tmp, 8) != 8) {
 | |
| 				// If the first read fails, report read error. Else EOF.
 | |
| 				result = read_ok ? MMIOERR_CHUNKNOTFOUND : MMIOERR_CANNOTREAD;
 | |
| 				running = FALSE;
 | |
| 			}
 | |
| 			else {
 | |
| 				read_ok = TRUE;
 | |
| 				if (m_info.pchBuffer) {
 | |
| 					tmp.dwDataOffset = m_info.pchNext - m_info.pchBuffer + m_info.lBufOffset;
 | |
| 				}
 | |
| 				else {
 | |
| 					tmp.dwDataOffset = m_info.lDiskOffset;
 | |
| 				}
 | |
| 
 | |
| 				if (ofs < tmp.dwDataOffset) {
 | |
| 					result = MMIOERR_CHUNKNOTFOUND;
 | |
| 					running = FALSE;
 | |
| 				}
 | |
| 				else if ((p_descend == MMIO_FINDLIST && tmp.ckid == FOURCC_LIST) || (p_descend == MMIO_FINDRIFF && tmp.ckid == FOURCC_RIFF)) {
 | |
| 					if (Read(&tmp.fccType, 4) != 4) {
 | |
| 						result = MMIOERR_CANNOTREAD;
 | |
| 						running = FALSE;
 | |
| 					}
 | |
| 					else if (p_chunkInfo->fccType == tmp.fccType) {
 | |
| 						running = FALSE;
 | |
| 					}
 | |
| 				}
 | |
| 				else if (p_chunkInfo->ckid == tmp.ckid) {
 | |
| 					running = FALSE;
 | |
| 				}
 | |
| 				else if (Seek((tmp.cksize & 1) + tmp.cksize, SEEK_CUR) == -1) {
 | |
| 					result = MMIOERR_CANNOTSEEK;
 | |
| 					running = FALSE;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		if (!result)
 | |
| 			memcpy(p_chunkInfo, &tmp, sizeof(MMCKINFO));
 | |
| 	}
 | |
| 
 | |
| 	return result;
 | |
| }
 |