From f707af34dbc707d4cfc769a8ce59e65689a8b46a Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Wed, 12 Jul 2023 14:12:03 -0700 Subject: [PATCH 01/10] move `override` macro to `compat.h` --- LEGO1/compat.h | 9 ++++++++- LEGO1/legostream.h | 3 ++- LEGO1/mxcore.h | 5 +++-- LEGO1/mxthread.h | 3 ++- LEGO1/mxtypes.h | 4 ---- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/LEGO1/compat.h b/LEGO1/compat.h index 496fa4db..7d76dfd0 100644 --- a/LEGO1/compat.h +++ b/LEGO1/compat.h @@ -11,4 +11,11 @@ #define COMPAT_CONST #endif -#endif // ISLECOMPAT_H \ No newline at end of file +// We use `override` so newer compilers can tell us our vtables are valid, +// however this keyword was added in C++11, so we define it as empty for +// compatibility with older compilers. +#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 corresponds to VC6.0 but "override" was probably added even later +#define override +#endif + +#endif // ISLECOMPAT_H diff --git a/LEGO1/legostream.h b/LEGO1/legostream.h index a505cd54..ca110f01 100644 --- a/LEGO1/legostream.h +++ b/LEGO1/legostream.h @@ -1,6 +1,7 @@ #ifndef LEGOSTREAM_H #define LEGOSTREAM_H +#include "compat.h" #include "decomp.h" #include "mxtypes.h" @@ -70,4 +71,4 @@ class LegoMemoryStream : public LegoStream MxU32 m_offset; }; -#endif // LEGOSTREAM_H \ No newline at end of file +#endif // LEGOSTREAM_H diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index 5e6586ba..9fb3e689 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -3,6 +3,7 @@ #include +#include "compat.h" #include "mxtypes.h" class MxParam; @@ -14,8 +15,8 @@ class MxCore public: __declspec(dllexport) MxCore(); __declspec(dllexport) virtual ~MxCore(); // vtable+00 - __declspec(dllexport) virtual MxLong Notify(MxParam &p); // vtable+04 - virtual MxLong Tickle(); // vtable+08 + __declspec(dllexport) virtual MxResult Notify(MxParam &p); // vtable+04 + virtual MxResult Tickle(); // vtable+08 // OFFSET: LEGO1 0x100144c0 inline virtual const char *ClassName() const // vtable+0c diff --git a/LEGO1/mxthread.h b/LEGO1/mxthread.h index 6ac96b59..4537dc14 100644 --- a/LEGO1/mxthread.h +++ b/LEGO1/mxthread.h @@ -1,6 +1,7 @@ #ifndef MXTHREAD_H #define MXTHREAD_H +#include "compat.h" #include "mxtypes.h" #include "mxsemaphore.h" @@ -54,4 +55,4 @@ class MxTickleThread : public MxThread MxS32 m_frequencyMS; }; -#endif // MXTHREAD_H \ No newline at end of file +#endif // MXTHREAD_H diff --git a/LEGO1/mxtypes.h b/LEGO1/mxtypes.h index 8a7d5026..d17ac09a 100644 --- a/LEGO1/mxtypes.h +++ b/LEGO1/mxtypes.h @@ -39,8 +39,4 @@ typedef MxU8 MxBool; #define FALSE 0 #endif -#if defined(_MSC_VER) && _MSC_VER <= 1200 // 1200 corresponds to VC6.0 but "override" was probably added even later -#define override -#endif - #endif // MXTYPE_H From f8b1995a8350a3b80530b362119fcb05425b16e8 Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Sun, 16 Jul 2023 01:51:24 -0400 Subject: [PATCH 02/10] LEGO1: MxPalette (#56) * MxPalette - add missing member variables, Detach function * mb * MxPalette: give bob the builder his constructor * push progress, gn * avoid hexadecimal Co-authored-by: Anonymous Maarten * fix MxPalette::GetDefaultPalette Co-authored-by: Anonymous Maarten * aaaaaaaaaaaaaa * Revert "fix MxPalette::GetDefaultPalette" This reverts commit 63f2215737d3bcd286f67dcf1a04fdf8a234d41b. * Implement MxPalette::Clone (doesn't match) * fix MxPalette structure and match ctor/dtor * Matching progress for MxPalette::GetDefaultPalette * Implement ApplySystemEntriesToPalette except the memcpy calls * implement SetSkyColor (doesn't match) * Use MxTypes instead of generics * prefer decimal values than hex for m_entries * Update mxpalette.cpp * Push MxPalette progress - read comments in code. * improved MxPalette::operator==, will be 100% when MSVC feels like making it so * improved MxPalette::SetSkyColor, will be 100% when MSVC feels like making it so * improved MxPalette::Clone, will be 100% when MSVC feels like making it so * Fixes - reordered the functions in order of where they are in the hex because recmp.py sometimes kept saying it couldn't find the symbol (??) - clone returns a pointer, not a ref - worked a bit on setpalette/applysysentriestopalette * Match GetDefaultPalette a bit more * fix: MxPalette::GetDefaultPalette is now 100% matching * fix: MxPalette::ApplySystemEntriesToPalette is now 100% matching * tidy: rename `DC` var in GetDefaultPalette to `hdc` * fix: MxPalette::SetPalette is now functionally matching Not assembly matching yet because of MSVC weirdness. At some point it will probably start matching, because the structure seems to be accurate. * fix: MxPalette rgbquad ctor functionally matches Not quite ASM matching yet because of weird register allocation mismatches. * fix: I forgot to commit mxpalette.h... * tidy: use Mx* primitives instead of builtins * refactor: remove MxPalette::FromBitmapPalette * fix: call ApplySystemEntriesToPalette from MxPalette(const RGBQUAD *) * rename MxPalette::SetPalette to MxPalette::SetEntries * fix: I once again forgot to commit mxpalette.h... * feat: add/match MxPalette::Reset [0x100BF490] * fix: add MVideoManager() to mxomni header * refactor: change unk50 in MxVideoManager to LPDIRECTDRAW * feat: add/match MxPalette::CreateNativePalette [0x100BF000] * fix: MxPalette::SetSkyColor is 100% matching * Annotate MxPalette members' offsets * Annotate the global default aplette * use hex size * remove unnecessary variable offset listing * Update LEGO1/mxpalette.cpp --------- Co-authored-by: Anonymous Maarten Co-authored-by: Christian Semmler Co-authored-by: ktkaufman03 Co-authored-by: MattKC <34096995+itsmattkc@users.noreply.github.com> --- LEGO1/mxomni.h | 1 + LEGO1/mxpalette.cpp | 476 ++++++++++++++++++++++++++++++++++++++- LEGO1/mxpalette.h | 19 +- LEGO1/mxvideomanager.cpp | 2 +- LEGO1/mxvideomanager.h | 4 +- 5 files changed, 491 insertions(+), 11 deletions(-) diff --git a/LEGO1/mxomni.h b/LEGO1/mxomni.h index f3f1ee9a..b09d11ad 100644 --- a/LEGO1/mxomni.h +++ b/LEGO1/mxomni.h @@ -77,5 +77,6 @@ __declspec(dllexport) MxVariableTable * VariableTable(); __declspec(dllexport) MxMusicManager * MusicManager(); __declspec(dllexport) MxEventManager * EventManager(); __declspec(dllexport) MxNotificationManager * NotificationManager(); +MxVideoManager * MVideoManager(); #endif // MXOMNI_H diff --git a/LEGO1/mxpalette.cpp b/LEGO1/mxpalette.cpp index 546dddf9..7fb02f4f 100644 --- a/LEGO1/mxpalette.cpp +++ b/LEGO1/mxpalette.cpp @@ -1,4 +1,349 @@ #include "mxpalette.h" +#include "mxomni.h" + +// GLOBAL: LEGO1 0x10102188 0x400 +PALETTEENTRY g_defaultPaletteEntries[256] = +{ + { 0u, 0u, 0u, 0u }, + { 128u, 0u, 0u, 0u }, + { 0u, 128u, 0u, 0u }, + { 128u, 128u, 0u, 0u }, + { 0u, 0u, 128u, 0u }, + { 128u, 0u, 128u, 0u }, + { 0u, 128u, 128u, 0u }, + { 128u, 128u, 128u, 0u }, + { 192u, 220u, 192u, 0u }, + { 166u, 202u, 240u, 0u }, + { 255u, 255u, 255u, 0u }, + { 250u, 250u, 250u, 0u }, + { 239u, 239u, 239u, 0u }, + { 228u, 228u, 228u, 0u }, + { 217u, 217u, 217u, 0u }, + { 206u, 206u, 206u, 0u }, + { 195u, 195u, 195u, 0u }, + { 185u, 185u, 185u, 0u }, + { 174u, 174u, 174u, 0u }, + { 163u, 163u, 163u, 0u }, + { 152u, 152u, 152u, 0u }, + { 141u, 141u, 141u, 0u }, + { 130u, 130u, 130u, 0u }, + { 123u, 123u, 123u, 0u }, + { 115u, 115u, 115u, 0u }, + { 108u, 108u, 108u, 0u }, + { 101u, 101u, 101u, 0u }, + { 93u, 93u, 93u, 0u }, + { 86u, 86u, 86u, 0u }, + { 79u, 79u, 79u, 0u }, + { 71u, 71u, 71u, 0u }, + { 64u, 64u, 64u, 0u }, + { 54u, 54u, 54u, 0u }, + { 43u, 43u, 43u, 0u }, + { 33u, 33u, 33u, 0u }, + { 22u, 22u, 22u, 0u }, + { 12u, 12u, 12u, 0u }, + { 8u, 8u, 8u, 0u }, + { 4u, 4u, 4u, 0u }, + { 0u, 0u, 0u, 0u }, + { 225u, 218u, 217u, 0u }, + { 195u, 182u, 179u, 0u }, + { 165u, 145u, 141u, 0u }, + { 134u, 108u, 102u, 0u }, + { 104u, 72u, 64u, 0u }, + { 74u, 35u, 26u, 0u }, + { 59u, 28u, 21u, 0u }, + { 44u, 21u, 16u, 0u }, + { 30u, 14u, 10u, 0u }, + { 15u, 7u, 5u, 0u }, + { 250u, 231u, 232u, 0u }, + { 240u, 185u, 189u, 0u }, + { 233u, 154u, 160u, 0u }, + { 226u, 124u, 131u, 0u }, + { 219u, 93u, 102u, 0u }, + { 213u, 62u, 73u, 0u }, + { 203u, 18u, 32u, 0u }, + { 172u, 15u, 27u, 0u }, + { 159u, 14u, 25u, 0u }, + { 146u, 13u, 23u, 0u }, + { 133u, 12u, 21u, 0u }, + { 120u, 11u, 19u, 0u }, + { 107u, 10u, 17u, 0u }, + { 94u, 8u, 15u, 0u }, + { 81u, 7u, 13u, 0u }, + { 68u, 6u, 11u, 0u }, + { 55u, 5u, 9u, 0u }, + { 42u, 4u, 7u, 0u }, + { 29u, 3u, 5u, 0u }, + { 10u, 1u, 2u, 0u }, + { 227u, 236u, 242u, 0u }, + { 178u, 203u, 220u, 0u }, + { 145u, 181u, 205u, 0u }, + { 112u, 159u, 191u, 0u }, + { 79u, 137u, 176u, 0u }, + { 30u, 104u, 154u, 0u }, + { 0u, 84u, 140u, 0u }, + { 0u, 79u, 132u, 0u }, + { 0u, 72u, 119u, 0u }, + { 0u, 66u, 110u, 0u }, + { 0u, 61u, 101u, 0u }, + { 0u, 55u, 92u, 0u }, + { 0u, 47u, 78u, 0u }, + { 0u, 39u, 65u, 0u }, + { 0u, 34u, 56u, 0u }, + { 0u, 28u, 47u, 0u }, + { 0u, 23u, 38u, 0u }, + { 0u, 18u, 29u, 0u }, + { 0u, 12u, 20u, 0u }, + { 0u, 4u, 7u, 0u }, + { 230u, 242u, 234u, 0u }, + { 180u, 215u, 193u, 0u }, + { 147u, 198u, 166u, 0u }, + { 113u, 180u, 138u, 0u }, + { 80u, 162u, 111u, 0u }, + { 30u, 136u, 70u, 0u }, + { 0u, 120u, 45u, 0u }, + { 0u, 114u, 43u, 0u }, + { 0u, 102u, 38u, 0u }, + { 0u, 95u, 35u, 0u }, + { 0u, 83u, 31u, 0u }, + { 0u, 72u, 27u, 0u }, + { 0u, 63u, 24u, 0u }, + { 0u, 56u, 21u, 0u }, + { 0u, 48u, 18u, 0u }, + { 0u, 36u, 14u, 0u }, + { 0u, 25u, 9u, 0u }, + { 0u, 17u, 6u, 0u }, + { 0u, 9u, 3u, 0u }, + { 0u, 1u, 1u, 0u }, + { 254u, 244u, 220u, 0u }, + { 255u, 239u, 181u, 0u }, + { 255u, 231u, 156u, 0u }, + { 255u, 222u, 132u, 0u }, + { 255u, 222u, 115u, 0u }, + { 255u, 214u, 99u, 0u }, + { 255u, 206u, 66u, 0u }, + { 255u, 198u, 41u, 0u }, + { 255u, 185u, 0u, 0u }, + { 255u, 189u, 8u, 0u }, + { 247u, 181u, 0u, 0u }, + { 222u, 156u, 0u, 0u }, + { 189u, 140u, 0u, 0u }, + { 173u, 123u, 0u, 0u }, + { 148u, 107u, 0u, 0u }, + { 132u, 90u, 0u, 0u }, + { 107u, 74u, 0u, 0u }, + { 74u, 49u, 0u, 0u }, + { 57u, 41u, 0u, 0u }, + { 33u, 24u, 0u, 0u }, + { 117u, 52u, 87u, 0u }, + { 176u, 158u, 50u, 0u }, + { 122u, 165u, 29u, 0u }, + { 242u, 142u, 8u, 0u }, + { 164u, 43u, 36u, 0u }, + { 113u, 67u, 20u, 0u }, + { 255u, 0u, 255u, 0u }, + { 255u, 0u, 255u, 0u }, + { 255u, 0u, 255u, 0u }, + { 255u, 0u, 255u, 0u }, + { 255u, 0u, 255u, 0u }, + { 57u, 163u, 217u, 0u }, + { 255u, 255u, 255u, 0u }, + { 254u, 255u, 247u, 0u }, + { 253u, 253u, 239u, 0u }, + { 248u, 247u, 247u, 0u }, + { 248u, 247u, 231u, 0u }, + { 240u, 240u, 240u, 0u }, + { 239u, 239u, 218u, 0u }, + { 227u, 232u, 236u, 0u }, + { 224u, 221u, 209u, 0u }, + { 215u, 222u, 215u, 0u }, + { 213u, 214u, 215u, 0u }, + { 214u, 214u, 203u, 0u }, + { 255u, 219u, 57u, 0u }, + { 206u, 206u, 206u, 0u }, + { 206u, 206u, 198u, 0u }, + { 255u, 214u, 18u, 0u }, + { 207u, 203u, 186u, 0u }, + { 197u, 199u, 199u, 0u }, + { 255u, 206u, 0u, 0u }, + { 207u, 198u, 159u, 0u }, + { 247u, 204u, 0u, 0u }, + { 189u, 198u, 189u, 0u }, + { 189u, 189u, 189u, 0u }, + { 238u, 199u, 0u, 0u }, + { 189u, 189u, 181u, 0u }, + { 238u, 190u, 24u, 0u }, + { 181u, 189u, 184u, 0u }, + { 161u, 186u, 224u, 0u }, + { 181u, 181u, 181u, 0u }, + { 231u, 189u, 0u, 0u }, + { 173u, 182u, 173u, 0u }, + { 222u, 181u, 0u, 0u }, + { 173u, 173u, 173u, 0u }, + { 213u, 182u, 0u, 0u }, + { 172u, 173u, 160u, 0u }, + { 214u, 173u, 0u, 0u }, + { 165u, 165u, 165u, 0u }, + { 206u, 173u, 0u, 0u }, + { 160u, 168u, 151u, 0u }, + { 206u, 164u, 0u, 0u }, + { 198u, 165u, 0u, 0u }, + { 157u, 156u, 156u, 0u }, + { 134u, 156u, 200u, 0u }, + { 153u, 156u, 144u, 0u }, + { 142u, 156u, 161u, 0u }, + { 189u, 156u, 0u, 0u }, + { 148u, 148u, 148u, 0u }, + { 146u, 148u, 138u, 0u }, + { 133u, 143u, 161u, 0u }, + { 189u, 143u, 0u, 0u }, + { 140u, 140u, 140u, 0u }, + { 177u, 147u, 0u, 0u }, + { 131u, 140u, 136u, 0u }, + { 146u, 130u, 126u, 0u }, + { 170u, 137u, 0u, 0u }, + { 132u, 132u, 130u, 0u }, + { 123u, 125u, 125u, 0u }, + { 123u, 123u, 133u, 0u }, + { 153u, 126u, 0u, 0u }, + { 114u, 116u, 118u, 0u }, + { 110u, 112u, 108u, 0u }, + { 97u, 109u, 136u, 0u }, + { 127u, 108u, 6u, 0u }, + { 0u, 173u, 0u, 0u }, + { 100u, 99u, 101u, 0u }, + { 176u, 71u, 41u, 0u }, + { 36u, 142u, 33u, 0u }, + { 98u, 91u, 75u, 0u }, + { 80u, 88u, 104u, 0u }, + { 252u, 0u, 0u, 0u }, + { 78u, 71u, 73u, 0u }, + { 73u, 71u, 78u, 0u }, + { 62u, 63u, 61u, 0u }, + { 0u, 66u, 211u, 0u }, + { 99u, 51u, 14u, 0u }, + { 198u, 0u, 0u, 0u }, + { 189u, 0u, 0u, 0u }, + { 0u, 57u, 206u, 0u }, + { 181u, 0u, 0u, 0u }, + { 0u, 56u, 185u, 0u }, + { 173u, 0u, 0u, 0u }, + { 165u, 0u, 0u, 0u }, + { 49u, 49u, 49u, 0u }, + { 0u, 49u, 165u, 0u }, + { 156u, 0u, 0u, 0u }, + { 42u, 45u, 60u, 0u }, + { 148u, 0u, 0u, 0u }, + { 140u, 0u, 0u, 0u }, + { 41u, 41u, 41u, 0u }, + { 0u, 41u, 144u, 0u }, + { 132u, 0u, 0u, 0u }, + { 123u, 0u, 0u, 0u }, + { 7u, 35u, 114u, 0u }, + { 34u, 36u, 32u, 0u }, + { 115u, 0u, 0u, 0u }, + { 107u, 0u, 0u, 0u }, + { 90u, 0u, 0u, 0u }, + { 23u, 24u, 27u, 0u }, + { 74u, 0u, 0u, 0u }, + { 15u, 15u, 16u, 0u }, + { 49u, 0u, 0u, 0u }, + { 16u, 12u, 4u, 0u }, + { 7u, 8u, 8u, 0u }, + { 0u, 0u, 8u, 0u }, + { 255u, 251u, 240u, 0u }, + { 160u, 160u, 164u, 0u }, + { 128u, 128u, 128u, 0u }, + { 255u, 0u, 0u, 0u }, + { 0u, 255u, 0u, 0u }, + { 255u, 255u, 0u, 0u }, + { 0u, 0u, 255u, 0u }, + { 255u, 0u, 255u, 0u }, + { 0u, 255u, 255u, 0u }, + { 255u, 255u, 255u, 0u } +}; + + +// OFFSET: LEGO1 0x100bee30 +MxPalette::MxPalette() +{ + this->m_overrideSkyColor = FALSE; + this->m_palette = NULL; + GetDefaultPalette(this->m_entries); + this->m_skyColor = this->m_entries[141]; +} + +// OFFSET: LEGO1 0x100BEED0 +MxPalette::MxPalette(const RGBQUAD *p_colors) +{ + this->m_overrideSkyColor = FALSE; + this->m_palette = NULL; + ApplySystemEntriesToPalette(this->m_entries); + + for ( MxS32 i = 10; i < 246; i++ ) + { + this->m_entries[i].peRed = p_colors[i].rgbRed; + this->m_entries[i].peGreen = p_colors[i].rgbGreen; + this->m_entries[i].peBlue = p_colors[i].rgbBlue; + this->m_entries[i].peFlags = 0; + } + + this->m_skyColor = this->m_entries[141]; +} + +// OFFSET: LEGO1 100bef90 +MxPalette::~MxPalette() +{ + if (m_palette) { + m_palette->Release(); + } +} + +// OFFSET: LEGO1 0x100bf390 +void MxPalette::ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries) +{ + HDC hdc; + + hdc = GetDC(0); + if ( (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256 ) + { + GetSystemPaletteEntries(hdc, 0, 10, p_entries); + GetSystemPaletteEntries(hdc, 246, 10, &p_entries[246]); + } + else + { + memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 10); + memcpy(&p_entries[246], &g_defaultPaletteEntries[246], sizeof(PALETTEENTRY) * 10); + } + ReleaseDC(0, hdc); +} + +// OFFSET: LEGO1 0x100bf0b0 +MxPalette* MxPalette::Clone() +{ + MxPalette *result = new MxPalette; + this->GetEntries(result->m_entries); + result->m_overrideSkyColor = this->m_overrideSkyColor; + return result; +} + +// OFFSET: LEGO1 0x100bf420 +void MxPalette::GetDefaultPalette(LPPALETTEENTRY p_entries) +{ + HDC hdc; + + hdc = GetDC(0); + if ( (GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE) != 0 && GetDeviceCaps(hdc, SIZEPALETTE) == 256 ) + { + GetSystemPaletteEntries(hdc, 0, 256, p_entries); + memcpy(&p_entries[10], &g_defaultPaletteEntries[10], sizeof(PALETTEENTRY) * 236); + } + else + { + memcpy(p_entries, g_defaultPaletteEntries, sizeof(PALETTEENTRY) * 256); + } + + ReleaseDC(0, hdc); +} // OFFSET: LEGO1 0x100bf150 MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries) @@ -8,14 +353,137 @@ MxResult MxPalette::GetEntries(LPPALETTEENTRY p_entries) } // OFFSET: LEGO1 0x100bf340 -MxBool MxPalette::operator==(MxPalette &) +MxBool MxPalette::operator==(MxPalette &other) { - // TODO - return FALSE; + for (MxS32 i = 0; i < 256; i++) + { + if (this->m_entries[i].peRed != other.m_entries[i].peRed) + return FALSE; + if (this->m_entries[i].peGreen != other.m_entries[i].peGreen) + return FALSE; + if (this->m_entries[i].peBlue != other.m_entries[i].peBlue) + return FALSE; + } + return TRUE; } // OFFSET: LEGO1 0x100bf330 void MxPalette::Detach() { - // TODO + this->m_palette = NULL; +} + +// OFFSET: LEGO1 0x100bf170 +MxResult MxPalette::SetEntries(LPPALETTEENTRY p_entries) +{ + MxS32 i; + MxResult status = 0; + + if ( this->m_palette ) + { + for ( i = 0; i < 10; i++ ) + this->m_entries[i].peFlags = 0x80; + for ( i = 10; i < 136; i++ ) + { + this->m_entries[i].peFlags = 68; + this->m_entries[i].peRed = p_entries[i].peRed; + this->m_entries[i].peGreen = p_entries[i].peGreen; + this->m_entries[i].peBlue = p_entries[i].peBlue; + } + for ( i = 136; i < 140; i++ ) + { + this->m_entries[i].peFlags = 132; + this->m_entries[i].peRed = p_entries[i].peRed; + this->m_entries[i].peGreen = p_entries[i].peGreen; + this->m_entries[i].peBlue = p_entries[i].peBlue; + } + if ( !this->m_overrideSkyColor ) + { + this->m_entries[140].peFlags = 0x44; + this->m_entries[140].peRed = p_entries[140].peRed; + this->m_entries[140].peGreen = p_entries[140].peGreen; + this->m_entries[140].peBlue = p_entries[140].peBlue; + this->m_entries[141].peFlags = 0x84; + this->m_entries[141].peRed = p_entries[141].peRed; + this->m_entries[141].peGreen = p_entries[141].peGreen; + this->m_entries[141].peBlue = p_entries[141].peBlue; + } + + for ( i = 142; i < 246; i++ ) + { + this->m_entries[i].peFlags = 132; + this->m_entries[i].peRed = p_entries[i].peRed; + this->m_entries[i].peGreen = p_entries[i].peGreen; + this->m_entries[i].peBlue = p_entries[i].peBlue; + } + + for ( i = 246; i < 256; i++ ) + this->m_entries[i].peFlags = 0x80; + + if ( this->m_palette->SetEntries(0, 0, 256, this->m_entries) ) + status = -1; + } + + return status; +} + +// OFFSET: LEGO1 0x100bf2d0 +MxResult MxPalette::SetSkyColor(LPPALETTEENTRY p_sky_color) +{ + MxResult status = 0; + if ( this->m_palette != NULL ) + { + this->m_entries[141].peRed = p_sky_color->peRed; + this->m_entries[141].peGreen = p_sky_color->peGreen; + this->m_entries[141].peBlue = p_sky_color->peBlue; + this->m_skyColor = this->m_entries[141]; + if ( this->m_palette->SetEntries(0, 141, 1, &this->m_skyColor) ) + { + status = -1; + } + } + return status; +} + +// OFFSET: LEGO1 0x100BF490 +void MxPalette::Reset(MxBool p_ignoreSkyColor) +{ + if ( this->m_palette != NULL ) + { + GetDefaultPalette(this->m_entries); + if ( !p_ignoreSkyColor ) + { + this->m_entries[140] = this->m_entries[141] = this->m_skyColor; + } + SetEntries(this->m_entries); + this->m_palette->SetEntries(0, 0, 256, this->m_entries); + } +} + +// OFFSET: LEGO1 0x100BF000 +LPDIRECTDRAWPALETTE MxPalette::CreateNativePalette() +{ + MxS32 i; + if ( this->m_palette == NULL ) + { + for (i = 0; i < 10; i++) + this->m_entries[i].peFlags = 0x80; + for (i = 10; i < 136; i++) + this->m_entries[i].peFlags = 0x44; + for (i = 136; i < 140; i++) + this->m_entries[i].peFlags = 0x84; + this->m_entries[140].peFlags = 0x84; + this->m_entries[141].peFlags = 0x44; + for (i = 142; i < 246; i++) + this->m_entries[i].peFlags = 0x84; + for (i = 246; i < 256; i++) + this->m_entries[i].peFlags = 0x80; + + if (MVideoManager() && MVideoManager()->GetDirectDraw()) + { + MVideoManager()->GetDirectDraw()->CreatePalette(4, this->m_entries, &this->m_palette, NULL); + } + } + + return this->m_palette; } diff --git a/LEGO1/mxpalette.h b/LEGO1/mxpalette.h index 7f4a4299..b024330a 100644 --- a/LEGO1/mxpalette.h +++ b/LEGO1/mxpalette.h @@ -14,12 +14,23 @@ class MxPalette : public MxCore __declspec(dllexport) MxBool operator==(MxPalette &); __declspec(dllexport) void Detach(); - MxResult GetEntries(LPPALETTEENTRY p_entries); + MxPalette(); + MxPalette(const RGBQUAD *); + virtual ~MxPalette(); + void ApplySystemEntriesToPalette(LPPALETTEENTRY p_entries); + MxPalette* Clone(); + void GetDefaultPalette(LPPALETTEENTRY p_entries); + MxResult GetEntries(LPPALETTEENTRY p_entries); + MxResult SetEntries(LPPALETTEENTRY p_palette); + MxResult SetSkyColor(LPPALETTEENTRY p_sky_color); + void Reset(MxBool p_ignoreSkyColor); + LPDIRECTDRAWPALETTE CreateNativePalette(); private: - LPDIRECTDRAWPALETTE m_pDirectDrawPalette; - PALETTEENTRY m_entries[256]; - // there's a bit more here + LPDIRECTDRAWPALETTE m_palette; + PALETTEENTRY m_entries[256]; // 0xc + MxBool m_overrideSkyColor; // 0x40c + PALETTEENTRY m_skyColor; // 0x40d }; #endif // MXPALETTE_H diff --git a/LEGO1/mxvideomanager.cpp b/LEGO1/mxvideomanager.cpp index 543f4136..af4995ae 100644 --- a/LEGO1/mxvideomanager.cpp +++ b/LEGO1/mxvideomanager.cpp @@ -23,7 +23,7 @@ MxVideoManager::MxVideoManager() // OFFSET: LEGO1 0x100be320 int MxVideoManager::Init() { - this->m_unk50 = 0; + this->m_pDirectDraw = NULL; this->m_unk54 = NULL; this->m_unk58 = NULL; this->m_unk5c = 0; diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h index f70bf06e..2061ec6b 100644 --- a/LEGO1/mxvideomanager.h +++ b/LEGO1/mxvideomanager.h @@ -21,10 +21,10 @@ class MxVideoManager : public MxUnknown100dc6b0 int Init(); inline MxVideoParam& GetVideoParam() { return this->m_videoParam; } - + inline LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; } private: MxVideoParam m_videoParam; - int m_unk50; + LPDIRECTDRAW m_pDirectDraw; LPDIRECTDRAWSURFACE m_unk54; void* m_unk58; int m_unk5c; From f247e10b7e73c700e9a4e71fed1fa5cfe28ea486 Mon Sep 17 00:00:00 2001 From: Mark Langen Date: Sat, 15 Jul 2023 23:13:34 -0700 Subject: [PATCH 03/10] reccmp.py improvements (#82) * Rather than using as a replacement for all offsets in a function, label the offsets as , , etc. Doing this will avoid false-positive 100% matches resulting from the same function being called in two times where a different on should have been called or vice versa. And the same for globals. I already encountered one case of this in the wild. * When a 100% match initially fails, try to make the functions match by swapping register allocations. This makes it possible to get a 100% match where the generated machine code differs only in register allocation. * Only apply the above when it is possible to reach a 100% match in that way. Otherwise show the developer the unadultrated diff to avoid complicating decompilation. * In the result listing, show the functions which are "effective matches" in this way as "100%*" instead of "100%". --- tools/reccmp/reccmp.py | 124 ++++++++++++++++++++++++++++++++----- tools/reccmp/template.html | 4 +- 2 files changed, 113 insertions(+), 15 deletions(-) diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index 226be15d..69779872 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -10,6 +10,7 @@ import os import sys import colorama +import re parser = argparse.ArgumentParser(allow_abbrev=False, description='Recompilation Compare: compare an original EXE with a recompiled EXE + PDB.') @@ -248,9 +249,21 @@ def get_recompiled_address(self, filename, line): md = Cs(CS_ARCH_X86, CS_MODE_32) -def sanitize(file, mnemonic, op_str): - offsetplaceholder = '' +class OffsetPlaceholderGenerator: + def __init__(self): + self.counter = 0 + self.replacements = {} + def get(self, addr): + if addr in self.replacements: + return self.replacements[addr] + else: + self.counter += 1 + replacement = '' % self.counter + self.replacements[addr] = replacement + return replacement + +def sanitize(file, placeholderGenerator, mnemonic, op_str): op_str_is_number = False try: int(op_str, 16) @@ -262,7 +275,7 @@ def sanitize(file, mnemonic, op_str): # Filter out "calls" because the offsets we're not currently trying to # match offsets. As long as there's a call in the right place, it's # probably accurate. - op_str = offsetplaceholder + op_str = placeholderGenerator.get(int(op_str, 16)) else: def filter_out_ptr(ptype, op_str): try: @@ -273,7 +286,7 @@ def filter_out_ptr(ptype, op_str): # This will throw ValueError if not hex inttest = int(op_str[start:end], 16) - return op_str[0:start] + offsetplaceholder + op_str[end:] + return op_str[0:start] + placeholderGenerator.get(inttest) + op_str[end:] except ValueError: return op_str @@ -288,7 +301,7 @@ def filter_out_ptr(ptype, op_str): try: inttest = int(word, 16) if inttest >= file.imagebase + file.textvirt: - words[i] = offsetplaceholder + words[i] = placeholderGenerator.get(inttest) except ValueError: pass op_str = ' '.join(words) @@ -298,18 +311,76 @@ def filter_out_ptr(ptype, op_str): def parse_asm(file, addr, size): asm = [] data = file.read(addr, size) + placeholderGenerator = OffsetPlaceholderGenerator() for i in md.disasm(data, 0): # Use heuristics to disregard some differences that aren't representative # of the accuracy of a function (e.g. global offsets) - mnemonic, op_str = sanitize(file, i.mnemonic, i.op_str) + mnemonic, op_str = sanitize(file, placeholderGenerator, i.mnemonic, i.op_str) if op_str is None: asm.append(mnemonic) else: asm.append("%s %s" % (mnemonic, op_str)) return asm +REGISTER_LIST = set([ + 'eax', 'ebx', 'ecx', 'edx', 'edi', 'esi', 'ebp', 'esp', + 'ax', 'bx', 'cx', 'dx', 'di', 'si', 'bp', 'sp', +]) +WORDS = re.compile(r'\w+') + +def get_registers(line: str): + to_replace = [] + # use words regex to find all matching positions: + for match in WORDS.finditer(line): + reg = match.group(0) + if reg in REGISTER_LIST: + to_replace.append((reg, match.start())) + return to_replace + +def replace_register(lines: list[str], start_line: int, reg: str, replacement: str): + for i in range(start_line, len(lines)): + lines[i] = lines[i].replace(reg, replacement) + +# Is it possible to make new_asm the same as original_asm by swapping registers? +def can_resolve_register_differences(original_asm, new_asm): + # Swapping ain't gonna help if the lengths are different + if len(original_asm) != len(new_asm): + return False + + # Make copies so we don't modify the original + original_asm = original_asm.copy() + new_asm = new_asm.copy() + + # Look for the mismatching lines + for i in range(len(original_asm)): + new_line = new_asm[i] + original_line = original_asm[i] + if new_line != original_line: + # Find all the registers to replace + to_replace = get_registers(original_line) + + for j in range(len(to_replace)): + (reg, reg_index) = to_replace[j] + replacing_reg = new_line[reg_index:reg_index + len(reg)] + if replacing_reg in REGISTER_LIST: + if replacing_reg != reg: + # Do a three-way swap replacing in all the subsequent lines + temp_reg = "&" * len(reg) + replace_register(new_asm, i, replacing_reg, temp_reg) + replace_register(new_asm, i, reg, replacing_reg) + replace_register(new_asm, i, temp_reg, reg) + else: + # No replacement to do, different code, bail out + return False + # Check if the lines are now the same + for i in range(len(original_asm)): + if new_asm[i] != original_asm[i]: + return False + return True + function_count = 0 total_accuracy = 0 +total_effective_accuracy = 0 htmlinsert = [] # Generate basename of original file, used in locating OFFSET lines @@ -356,24 +427,41 @@ def parse_asm(file, addr, size): if not recinfo: continue + # The effective_ratio is the ratio when ignoring differing register + # allocation vs the ratio is the true ratio. + ratio = 0.0 + effective_ratio = 0.0 if recinfo.size: origasm = parse_asm(origfile, addr + recinfo.start, recinfo.size) recompasm = parse_asm(recompfile, recinfo.addr + recinfo.start, recinfo.size) diff = difflib.SequenceMatcher(None, origasm, recompasm) ratio = diff.ratio() + effective_ratio = ratio + + if ratio != 1.0: + # Check whether we can resolve register swaps which are actually + # perfect matches modulo compiler entropy. + if can_resolve_register_differences(origasm, recompasm): + effective_ratio = 1.0 else: ratio = 0 - percenttext = "%.2f%%" % (ratio * 100) + percenttext = "%.2f%%" % (effective_ratio * 100) if not plain: - if ratio == 1.0: + if effective_ratio == 1.0: percenttext = colorama.Fore.GREEN + percenttext + colorama.Style.RESET_ALL - elif ratio > 0.8: + elif effective_ratio > 0.8: percenttext = colorama.Fore.YELLOW + percenttext + colorama.Style.RESET_ALL else: percenttext = colorama.Fore.RED + percenttext + colorama.Style.RESET_ALL + if effective_ratio == 1.0 and ratio != 1.0: + if plain: + percenttext += "*" + else: + percenttext += colorama.Fore.RED + "*" + colorama.Style.RESET_ALL + if not verbose: if args.print_rec_addr: addrs = '%s / %s' % (hex(addr), hex(recinfo.addr)) @@ -383,14 +471,21 @@ def parse_asm(file, addr, size): function_count += 1 total_accuracy += ratio + total_effective_accuracy += effective_ratio if recinfo.size: udiff = difflib.unified_diff(origasm, recompasm, n=10) # If verbose, print the diff for that funciton to the output if verbose: - if ratio == 1.0: - print("%s: %s 100%% match.\n\nOK!" % (hex(addr), recinfo.name)) + if effective_ratio == 1.0: + ok_text = "OK!" if plain else (colorama.Fore.GREEN + "✨ OK! ✨" + colorama.Style.RESET_ALL) + if ratio == 1.0: + print("%s: %s 100%% match.\n\n%s\n\n" % + (hex(addr), recinfo.name, ok_text)) + else: + print("%s: %s Effective 100%% match. (Differs in register allocation only)\n\n%s (still differs in register allocation)\n\n" % + (hex(addr), recinfo.name, ok_text)) else: for line in udiff: if line.startswith("++") or line.startswith("@@") or line.startswith("--"): @@ -416,7 +511,7 @@ def parse_asm(file, addr, size): # If html, record the diffs to an HTML file if html: escaped = '\\n'.join(udiff).replace('"', '\\"').replace('\n', '\\n').replace('<', '<').replace('>', '>') - htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), recinfo.name, str(ratio), escaped)) + htmlinsert.append('{address: "%s", name: "%s", matching: %s, diff: "%s"}' % (hex(addr), recinfo.name, str(effective_ratio), escaped)) except UnicodeDecodeError: break @@ -496,7 +591,8 @@ def gen_svg(svg, name, icon, implemented_funcs, total_funcs, raw_accuracy): function_count = int(args.total) if function_count > 0: - print('\nTotal accuracy %.2f%% across %i functions' % (total_accuracy / function_count * 100, function_count)) + print('\nTotal effective accuracy %.2f%% across %i functions (%.2f%% actual accuracy)' % + (total_effective_accuracy / function_count * 100, function_count, total_accuracy / function_count * 100)) if svg: - gen_svg(svg, os.path.basename(original), args.svg_icon, implemented_funcs, function_count, total_accuracy) + gen_svg(svg, os.path.basename(original), args.svg_icon, implemented_funcs, function_count, total_effective_accuracy) diff --git a/tools/reccmp/template.html b/tools/reccmp/template.html index 9b03e4ec..f3087688 100644 --- a/tools/reccmp/template.html +++ b/tools/reccmp/template.html @@ -221,7 +221,9 @@ addrCel.innerHTML = addrCel.dataset.value = element.address; nameCel.innerHTML = nameCel.dataset.value = element.name; - matchCel.innerHTML = (element.matching * 100).toFixed(2) + '%'; + + var effectiveNote = (element.matching == 1 && element.diff != '') ? '*' : ''; + matchCel.innerHTML = (element.matching * 100).toFixed(2) + '%' + effectiveNote; matchCel.dataset.value = element.matching; row.classList.add('funcrow'); From 2ffe227d82916ae37b4916cbd8a714f4ef627f78 Mon Sep 17 00:00:00 2001 From: MattKC <34096995+itsmattkc@users.noreply.github.com> Date: Sat, 15 Jul 2023 23:18:21 -0700 Subject: [PATCH 04/10] Add SmartHeap (#83) * add smartheap * cmake: bump even further * this seemed to be necessary but now it isn't? ok * cmake: force include smrtheap.hpp Co-authored-by: Anonymous Maarten * cmake: force include smrtheap.hpp 2 Co-authored-by: Anonymous Maarten * remove compiler defs - unnecessary if force-including anyway * cmake: use interface for cleaner code --------- Co-authored-by: Anonymous Maarten --- .github/workflows/build.yml | 2 +- 3rdparty/smartheap/SHLW32MT.LIB | Bin 0 -> 106886 bytes 3rdparty/smartheap/SHMALLOC.H | 63 +++ 3rdparty/smartheap/SHMFC4M.LIB | Bin 0 -> 3206 bytes 3rdparty/smartheap/SMRTHEAP.H | 656 ++++++++++++++++++++++++++++++++ 3rdparty/smartheap/SMRTHEAP.HPP | 159 ++++++++ CMakeLists.txt | 17 +- 7 files changed, 895 insertions(+), 2 deletions(-) create mode 100644 3rdparty/smartheap/SHLW32MT.LIB create mode 100644 3rdparty/smartheap/SHMALLOC.H create mode 100644 3rdparty/smartheap/SHMFC4M.LIB create mode 100644 3rdparty/smartheap/SMRTHEAP.H create mode 100644 3rdparty/smartheap/SMRTHEAP.HPP diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index af1dac3b..c846a9f9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: uses: jwlawson/actions-setup-cmake@v1.13 with: # Use minimum supported version - cmake-version: '3.0.x' + cmake-version: '3.13.x' - name: Build shell: cmd diff --git a/3rdparty/smartheap/SHLW32MT.LIB b/3rdparty/smartheap/SHLW32MT.LIB new file mode 100644 index 0000000000000000000000000000000000000000..732aedf81e8fa402cb197f1a72a1966e3705d432 GIT binary patch literal 106886 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 aOWw*zl9QwVgJhh~`Y|eNCZ)L5W%4KBGcqOs literal 0 HcmV?d00001 diff --git a/3rdparty/smartheap/SMRTHEAP.H b/3rdparty/smartheap/SMRTHEAP.H new file mode 100644 index 00000000..aab58b84 --- /dev/null +++ b/3rdparty/smartheap/SMRTHEAP.H @@ -0,0 +1,656 @@ +/* smrtheap.h -- SmartHeap (tm) public C header file + * Professional Memory Management Library + * + * Copyright (C) 1991-1997 by Arthur D. Applegate. All Rights Reserved. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the author. + * + */ + +#if !defined(_SMARTHEAP_H) +#define _SMARTHEAP_H + +#include +#include + +#if !defined(macintosh) && !defined(THINK_C) && !defined(__MWERKS__) \ + && !defined(SHANSI) && UINT_MAX == 0xFFFFu \ + && (defined(_Windows) || defined(_WINDOWS) || defined(__WINDOWS__)) + #define MEM_WIN16 +#endif + +#if (UINT_MAX == 0xFFFFu) && (defined(MEM_WIN16) \ + || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__)) + /* 16-bit X86 */ + #if defined(SYS_DLL) + #if defined(_MSC_VER) && _MSC_VER <= 600 + #define MEM_ENTRY _export _loadds far pascal + #else + #define MEM_ENTRY _export far pascal + #endif + #else + #define MEM_ENTRY far pascal + #endif + #ifdef __WATCOMC__ + #define MEM_ENTRY_ANSI __far + #else + #define MEM_ENTRY_ANSI far cdecl + #endif + #define MEM_FAR far + #if defined(MEM_WIN16) + #define MEM_ENTRY2 _export far pascal + #elif defined(DOS16M) || defined(DOSX286) + #define MEM_ENTRY2 _export _loadds far pascal + #endif + +#else /* not 16-bit X86 */ + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) \ + || defined(__WIN32__) || defined(__NT__) + #define MEM_WIN32 + #if defined(_MSC_VER) + #if defined(_SHI_Pool) && defined(SYS_DLL) + #define MEM_ENTRY1 __declspec(dllexport) + #define MEM_ENTRY4 __declspec(dllexport) extern + #elif !defined(_SHI_Pool) && (defined(MEM_DEBUG) || defined(MEM_DLL)) + #define MEM_ENTRY1 __declspec(dllimport) + #if defined(_M_IX86) || defined(_X86_) + #define MemDefaultPool shi_MemDefaultPool + #define MEM_ENTRY4 __declspec(dllimport) + #endif + #endif + #endif + #if !defined(_MSC_VER) || defined(_M_IX86) || defined(_X86_) + #define MEM_ENTRY __stdcall + #else + #define MEM_ENTRY __cdecl /* for NT/RISC */ + #endif + #ifndef __WATCOMC__ + #define MEM_ENTRY_ANSI __cdecl + #endif + +#elif defined(__OS2__) + #if defined(__BORLANDC__) || defined(__WATCOMC__) + #if defined(SYS_DLL) + #define MEM_ENTRY __export __syscall + #else + #define MEM_ENTRY __syscall + #endif /* SYS_DLL */ + #ifdef __BORLANDC__ + #define MEM_ENTRY_ANSI __stdcall + #endif + #elif defined(__IBMC__) || defined(__IBMCPP__) + #if defined(SYS_DLL) && 0 + #define MEM_ENTRY _Export _System + #else + #define MEM_ENTRY _System + #endif + #define MEM_ENTRY_ANSI _Optlink + #define MEM_ENTRY3 MEM_ENTRY + #define MEM_CALLBACK MEM_ENTRY3 + #define MEM_ENTRY2 + #endif +#endif /* __OS2__ */ + +#if defined(__WATCOMC__) && defined(__SW_3S) + /* Watcom stack calling convention */ +#ifndef __OS2__ +#ifdef __WINDOWS_386__ + #pragma aux syscall "*_" parm routine [eax ebx ecx edx fs gs] modify [eax]; +#else + #pragma aux syscall "*_" parm routine [eax ebx ecx edx] modify [eax]; +#endif +#ifndef MEM_ENTRY + #define MEM_ENTRY __syscall +#endif /* MEM_ENTRY */ +#endif +#endif /* Watcom stack calling convention */ + +#endif /* end of system-specific declarations */ + +#ifndef MEM_ENTRY + #define MEM_ENTRY +#endif +#ifndef MEM_ENTRY1 + #define MEM_ENTRY1 +#endif +#ifndef MEM_ENTRY2 + #define MEM_ENTRY2 MEM_ENTRY +#endif +#ifndef MEM_ENTRY3 + #define MEM_ENTRY3 +#endif +#ifndef MEM_ENTRY4 + #define MEM_ENTRY4 extern +#endif +#ifndef MEM_CALLBACK +#define MEM_CALLBACK MEM_ENTRY2 +#endif +#ifndef MEM_ENTRY_ANSI + #define MEM_ENTRY_ANSI +#endif +#ifndef MEM_FAR + #define MEM_FAR +#endif + +#ifdef applec +/* Macintosh: Apple MPW C/C++ passes char/short parms as longs (4 bytes), + * whereas Symantec C/C++ for MPW passes these as words (2 bytes); + * therefore, canonicalize all integer parms as 'int' for this platform. + */ + #define MEM_USHORT unsigned + #define MEM_UCHAR unsigned +#else + #define MEM_USHORT unsigned short + #define MEM_UCHAR unsigned char +#endif /* applec */ + +#ifdef MEM_DEBUG +#include "heapagnt.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*** Types ***/ + +#ifndef MEM_BOOL_DEFINED +#define MEM_BOOL_DEFINED +typedef int MEM_BOOL; +#endif + +/* Version Masks */ +typedef unsigned MEM_VERSION; +#define MEM_MAJOR_VERSION(v) (((v) & 0xF000u) >> 12) +#define MEM_MINOR_VERSION(v) (((v) & 0x0F00u) >> 8) +#define MEM_UPDATE_VERSION(v) ((v) & 0x00FFu) + +/* Note: these types are struct's rather than integral types to facilitate + * compile-time type-checking. MEM_POOL and MEM_HANDLE should be regarded + * as black boxes, and treated just like handles. + * You should not have any type casts to or from MEM_POOL or MEM_HANDLE; + * nor should you dereference variables of type MEM_POOL or MEM_HANDLE + * (unless you are using SmartHeap to replace NewHandle on the Mac, and + * you have existing code that dereferences handles). + */ +#ifndef MEM_POOL_DEFINED +#define MEM_POOL_DEFINED +#ifdef _SHI_Pool + typedef struct _SHI_Pool MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle MEM_FAR *MEM_HANDLE; +#else + #ifdef THINK_C + typedef void *MEM_POOL; + typedef void **MEM_HANDLE; + #else + typedef struct _SHI_Pool { int reserved; } MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle { int reserved; } MEM_FAR *MEM_HANDLE; + #endif +#endif +#endif /* MEM_POOL_DEFINED */ + + +#if !defined(MEM_DEBUG) || !(defined(MEM_WIN16) || defined(MEM_WIN32)) +#define SHI_MAJOR_VERSION 3 +#define SHI_MINOR_VERSION 3 +#define SHI_UPDATE_LEVEL 0 +#endif /* !WINDOWS */ + +#ifndef MEM_DEBUG + +/* Error codes: errorCode field of MEM_ERROR_INFO */ +#ifndef MEM_ERROR_CODE_DEFINED +#define MEM_ERROR_CODE_DEFINED +typedef enum +{ + MEM_NO_ERROR=0, + MEM_INTERNAL_ERROR, + MEM_OUT_OF_MEMORY, + MEM_BLOCK_TOO_BIG, + MEM_ALLOC_ZERO, + MEM_RESIZE_FAILED, + MEM_LOCK_ERROR, + MEM_EXCEEDED_CEILING, + MEM_TOO_MANY_PAGES, + MEM_TOO_MANY_TASKS, + MEM_BAD_MEM_POOL, + MEM_BAD_BLOCK, + MEM_BAD_FREE_BLOCK, + MEM_BAD_HANDLE, + MEM_BAD_POINTER, + MEM_WRONG_TASK, + MEM_NOT_FIXED_SIZE, + MEM_BAD_FLAGS, + MEM_ERROR_CODE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_ERROR_CODE; +#endif /* MEM_ERROR_CODE_DEFINED */ + + +/* ### we should have packing pragma around these structure decls in case + * ### user is compiling with non-default packing directive (only needed + * ### if user is packing more strictly than native int size *and* if + * ### native int size is != native long and ptr sizes) + */ + +/* Error info, passed to error-handling callback routine */ +#ifndef MEM_ERROR_INFO_DEFINED +#define MEM_ERROR_INFO_DEFINED +typedef struct _MEM_ERROR_INFO +{ + MEM_ERROR_CODE errorCode; /* error code identifying type of error */ + MEM_POOL pool; /* pool in which error occurred, if known */ +} MEM_ERROR_INFO; + +/* Error handling callback function */ +typedef MEM_BOOL (MEM_ENTRY2 * MEM_ENTRY3 MEM_ERROR_FN) + (MEM_ERROR_INFO MEM_FAR *); + +#endif /* MEM_ERROR_INFO_DEFINED */ + +#endif /* MEM_DEBUG */ + + +#ifndef MEM_BLOCK_TYPE_DEFINED +#define MEM_BLOCK_TYPE_DEFINED +/* Block Type: field of MEM_POOL_ENTRY, field of MEM_POOL_INFO, + * parameter to MemPoolPreAllocate + */ +typedef enum +{ + MEM_FS_BLOCK = 0x0001u, + MEM_VAR_MOVEABLE_BLOCK = 0x0002u, + MEM_VAR_FIXED_BLOCK = 0x0004u, + MEM_EXTERNAL_BLOCK = 0x0008u, + MEM_BLOCK_TYPE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_BLOCK_TYPE; +#endif /* MEM_BLOCK_TYPE_DEFINED */ + +#ifndef MEM_POOL_ENTRY_DEFINED +#define MEM_POOL_ENTRY_DEFINED +/* Pool Entry: parameter to MemPoolWalk */ +typedef struct +{ + void MEM_FAR *entry; + MEM_POOL pool; + MEM_BLOCK_TYPE type; + MEM_BOOL isInUse; + unsigned long size; + MEM_HANDLE handle; + unsigned lockCount; + void MEM_FAR *reserved_ptr; +} MEM_POOL_ENTRY; +#endif /* MEM_POOL_ENTRY_DEFINED */ + +#ifndef MEM_POOL_STATUS_DEFINED +#define MEM_POOL_STATUS_DEFINED +/* Pool Status: returned by MemPoolWalk, MemPoolFirst, MemPoolNext */ +typedef enum +{ + MEM_POOL_OK = 1, + MEM_POOL_CORRUPT = -1, + MEM_POOL_CORRUPT_FATAL = -2, + MEM_POOL_END = 0, + MEM_POOL_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POOL_STATUS; +#endif /* MEM_POOL_STATUS_DEFINED */ + +#ifndef MEM_POINTER_STATUS_DEFINED +#define MEM_POINTER_STATUS_DEFINED +/* Pointer Status: returned by MemCheckPtr */ +typedef enum +{ + MEM_POINTER_OK = 1, + MEM_POINTER_WILD = 0, + MEM_POINTER_FREE = -1, + MEM_POINTER_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POINTER_STATUS; +#endif /* MEM_POINTER_STATUS_DEFINED */ + +/* Pool Info: parameter to MemPoolInfo, MemPoolFirst, MemPoolNext */ +typedef struct +{ + MEM_POOL pool; + MEM_BLOCK_TYPE type; /* disjunctive combination of block type flags */ + unsigned short blockSizeFS; + unsigned short smallBlockSize; + unsigned pageSize; + unsigned long floor; + unsigned long ceiling; + unsigned flags; + MEM_ERROR_FN errorFn; +} MEM_POOL_INFO; + +/* Flags passed to MemAlloc, MemAllocPtr, MemReAlloc, MemReAllocPtr */ +#define MEM_FIXED 0x0000u /* fixed handle-based block */ +#define MEM_ZEROINIT 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_MOVEABLE 0x0002u /* moveable handle-based block */ +#define MEM_RESIZEABLE 0x0004u /* reserve space above block */ +#define MEM_RESIZE_IN_PLACE 0x0008u /* do not move block (realloc) */ +#define MEM_NOGROW 0x0010u /* do not grow heap to satisfy request */ +#define MEM_NOEXTERNAL 0x0020u /* reserved for internal use */ +#define MEM_NOCOMPACT 0x0040u /* do not compact to satisfy request */ +#define MEM_NO_SERIALIZE 0x0080u /* do not serialize this request */ +#define MEM_HANDLEBASED 0x4000u /* for internal use */ +#define MEM_RESERVED 0x8000u /* for internal use */ + +#define MEM_UNLOCK_FAILED USHRT_MAX + +/* Flags passed to MemPoolInit, MemPoolInitFS */ +#ifndef MEM_POOL_SHARED +#define MEM_POOL_SHARED 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_POOL_SERIALIZE 0x0002u /* pool used in more than one thread */ +#define MEM_POOL_VIRTUAL_LOCK 0x0004u /* pool is locked in physical memory */ +#define MEM_POOL_ZEROINIT 0x0008u /* malloc/new from pool zero-inits */ +#define MEM_POOL_REGION 0x0010u /* store pool in user-supplied region*/ +#define MEM_POOL_DEFAULT 0x8000u /* pool with default characteristics */ +#endif /* MEM_POOL_SHARED */ + +MEM_ENTRY4 MEM_POOL MemDefaultPool; + +/* Default memory pool for C malloc, C++ new (for backwards compatibility) */ +#define MEM_DEFAULT_POOL MemDefaultPool + +/* define and initialize these variables at file scope to change defaults */ +extern unsigned short MemDefaultPoolBlockSizeFS; +extern unsigned MemDefaultPoolPageSize; +extern unsigned MemDefaultPoolFlags; + +/* define SmartHeap_malloc at file scope if you + * are intentionally _NOT_ linking in the SmartHeap malloc definition + * ditto for SmartHeap operator new, and fmalloc et al. + */ +extern int SmartHeap_malloc; +extern int SmartHeap_far_malloc; +extern int SmartHeap_new; + +#define MEM_ERROR_RET ULONG_MAX + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_H) */ + + +/*** Function Prototypes ***/ + +#ifndef _SMARTHEAP_PROT +#define _SMARTHEAP_PROT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _shAPI + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY _dbg ## name + #else + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY name + #endif +#endif + +#ifndef _dbgARGS + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _dbgARGS1 const char MEM_FAR *, int + #define _dbgARGS , _dbgARGS1 + #else + #define _dbgARGS1 void + #define _dbgARGS + #endif +#endif + + +/**** HOW TO READ SmartHeap PROTOTYPES **** + * prototypes below have the follow syntax in order to support both debug + * and non-debug APIs with single-source: + * + * _shiAPI(, )([] _dbgARGS); + * + * the above translates to a C prototype as follows: + * + * ([]); + */ + +/* Library Version */ +MEM_ENTRY1 MEM_VERSION MEM_ENTRY MemVersion(void); + +/* Library Registration */ +_shAPI(MEM_BOOL, MemRegisterTask)(_dbgARGS1); +_shAPI(MEM_BOOL, MemUnregisterTask)(_dbgARGS1); + +/* Memory Pool Functions */ +_shAPI(MEM_POOL, MemPoolInit)(unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitFS)(MEM_USHORT, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitRegion)(void MEM_FAR *, + unsigned long size, unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedShared)(const char MEM_FAR *, + unsigned long size,unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedSharedEx)(void MEM_FAR *addr, + unsigned pidCount, unsigned long MEM_FAR *pids, void MEM_FAR *security, + const char MEM_FAR *name, unsigned long size, unsigned flags _dbgARGS); +_shAPI(MEM_POOL, MemPoolAttachShared)(MEM_POOL, const char MEM_FAR * _dbgARGS); +_shAPI(MEM_BOOL, MemPoolFree)(MEM_POOL _dbgARGS); +MEM_POOL MEM_ENTRY MemInitDefaultPool(void); +MEM_BOOL MEM_ENTRY MemFreeDefaultPool(void); +_shAPI(unsigned, MemPoolSetPageSize)(MEM_POOL, unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetBlockSizeFS)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetSmallBlockSize)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(unsigned long, MemPoolSetFloor)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolSetCeiling)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocate)(MEM_POOL, unsigned long, + MEM_BLOCK_TYPE _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocateHandles)(MEM_POOL, + unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolShrink)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolSize)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolCount)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolInfo)(MEM_POOL, void MEM_FAR *, + MEM_POOL_INFO MEM_FAR* _dbgARGS); +_shAPI(MEM_POOL_STATUS, MemPoolFirst)(MEM_POOL_INFO MEM_FAR *, + MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolNext)(MEM_POOL_INFO MEM_FAR*,MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolWalk)(MEM_POOL,MEM_POOL_ENTRY MEM_FAR*_dbgARGS); +_shAPI(MEM_BOOL, MemPoolCheck)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolLock)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolUnlock)(MEM_POOL _dbgARGS); + +/* Handle-based API for moveable memory within heap. */ +_shAPI(MEM_HANDLE, MemAlloc)(MEM_POOL, unsigned, unsigned long _dbgARGS); +_shAPI(MEM_HANDLE, MemReAlloc)(MEM_HANDLE,unsigned long,unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFree)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemLock)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnlock)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemFix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnfix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemLockCount)(MEM_HANDLE _dbgARGS); +#ifndef MemFlags +#define MemFlags(mem) MemLockCount(mem) +#endif +_shAPI(MEM_BOOL, MemIsMoveable)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSize)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSizeRequested)(MEM_HANDLE _dbgARGS); +_shAPI(MEM_HANDLE, MemHandle)(void MEM_FAR * _dbgARGS); +#ifndef MEM_REFERENCE + #ifdef MEM_DEBUG + MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemReference(MEM_HANDLE, + const char MEM_FAR *, int); + #define MEM_REFERENCE(handle) \ + _dbgMemReference(handle, __FILE__, __LINE__) + #else + #define MEM_REFERENCE(handle) (*(void MEM_FAR * MEM_FAR *)handle) + #endif +#endif + +/* General Heap Allocator (returns direct pointer to memory) */ +_shAPI(void MEM_FAR*,MemAllocPtr)(MEM_POOL,unsigned long,unsigned _dbgARGS); +_shAPI(void MEM_FAR *, MemReAllocPtr)(void MEM_FAR *, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFreePtr)(void MEM_FAR * _dbgARGS); +_shAPI(unsigned long, MemSizePtr)(void MEM_FAR * _dbgARGS); +_shAPI(MEM_POINTER_STATUS, MemCheckPtr)(MEM_POOL, void MEM_FAR * _dbgARGS); + +/* Fixed-Size Allocator */ +_shAPI(void MEM_FAR *, MemAllocFS)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemFreeFS)(void MEM_FAR * _dbgARGS); + +/* Error Handling Functions */ +MEM_ENTRY1 MEM_ERROR_FN MEM_ENTRY MemSetErrorHandler(MEM_ERROR_FN); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY MemDefaultErrorHandler(MEM_ERROR_INFO MEM_FAR*); +MEM_ENTRY1 void MEM_ENTRY MemErrorUnwind(void); + +#ifdef MEM_WIN32 +/* patching control */ + +#ifndef MEM_PATCHING_DEFINED +#define MEM_PATCHING_DEFINED +typedef enum +{ + MEM_PATCH_ALL = 0, + MEM_SKIP_PATCHING_THIS_DLL = 1, + MEM_DISABLE_SYSTEM_HEAP_PATCHING = 2, + MEM_DISABLE_ALL_PATCHING = 4|2|1, + MEM_PATCHING_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_PATCHING; +#endif /* MEM_PATCHING_DEFINED */ + +#ifdef _MSC_VER +__declspec(dllexport) +#endif +MEM_PATCHING MEM_ENTRY MemSetPatching(const char ***skipDLLs); + +#endif /* MEM_WIN32 */ + +/* internal routines */ +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _shi_enterCriticalSection(void); +MEM_ENTRY1 void MEM_ENTRY _shi_leaveCriticalSection(void); +MEM_BOOL shi_call_new_handler_msc(size_t, MEM_BOOL); + + +/* Wrapper macros for debugging API */ +#ifndef _SHI_dbgMacros +#ifdef MEM_DEBUG +#define MemRegisterTask() _dbgMemRegisterTask(__FILE__, __LINE__) +#define MemUnregisterTask() _dbgMemUnregisterTask(__FILE__, __LINE__) +#define MemPoolInit(flags) _dbgMemPoolInit(flags, __FILE__, __LINE__) +#define MemPoolInitFS(bs, bc, f) _dbgMemPoolInitFS(bs,bc,f,__FILE__,__LINE__) +#define MemPoolInitRegion(addr, sz, f) \ + _dbgMemPoolInitRegion(addr, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedShared(nm, sz, f) \ + _dbgMemPoolInitNamedShared(nm, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f) \ + _dbgMemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f, __FILE__, __LINE__) +#define MemPoolAttachShared(p, n) \ + _dbgMemPoolAttachShared(p, n, __FILE__, __LINE__) +#define MemPoolFree(pool) _dbgMemPoolFree(pool, __FILE__, __LINE__) +#define MemPoolSetPageSize(p, s) _dbgMemPoolSetPageSize(p,s,__FILE__,__LINE__) +#define MemPoolSetBlockSizeFS(p, s) \ + _dbgMemPoolSetBlockSizeFS(p, s, __FILE__, __LINE__) +#define MemPoolSetSmallBlockSize(p, s) \ + _dbgMemPoolSetSmallBlockSize(p, s, __FILE__, __LINE__) +#define MemPoolSetFloor(p, f) _dbgMemPoolSetFloor(p, f, __FILE__, __LINE__) +#define MemPoolSetCeiling(p, c) _dbgMemPoolSetCeiling(p,c,__FILE__, __LINE__) +#define MemPoolPreAllocate(p,s,t) \ + _dbgMemPoolPreAllocate(p,s,t,__FILE__, __LINE__) +#define MemPoolPreAllocateHandles(p,h) \ + _dbgMemPoolPreAllocateHandles(p,h,__FILE__, __LINE__) +#define MemPoolShrink(p) _dbgMemPoolShrink(p, __FILE__, __LINE__) +#define MemPoolCheck(p) _dbgMemPoolCheck(p, __FILE__, __LINE__) +#define MemPoolWalk(p, e) _dbgMemPoolWalk(p, e, __FILE__, __LINE__) +#define MemPoolSize(p) _dbgMemPoolSize(p, __FILE__, __LINE__) +#define MemPoolCount(p) _dbgMemPoolCount(p, __FILE__, __LINE__) +#define MemPoolInfo(p,x,i) _dbgMemPoolInfo(p,x,i, __FILE__, __LINE__) +#define MemPoolFirst(i, b) _dbgMemPoolFirst(i, b, __FILE__, __LINE__) +#define MemPoolNext(i, b) _dbgMemPoolNext(i, b, __FILE__, __LINE__) +#define MemPoolLock(p) _dbgMemPoolLock(p, __FILE__, __LINE__) +#define MemPoolUnlock(p) _dbgMemPoolUnlock(p, __FILE__, __LINE__) +#define MemAlloc(p, f, s) _dbgMemAlloc(p, f, s, __FILE__, __LINE__) +#define MemReAlloc(h, s, f) _dbgMemReAlloc(h, s, f, __FILE__, __LINE__) +#define MemFree(h) _dbgMemFree(h, __FILE__, __LINE__) +#define MemLock(h) _dbgMemLock(h, __FILE__, __LINE__) +#define MemUnlock(h) _dbgMemUnlock(h, __FILE__, __LINE__) +#define MemFix(h) _dbgMemFix(h, __FILE__, __LINE__) +#define MemUnfix(h) _dbgMemUnfix(h, __FILE__, __LINE__) +#define MemSize(h) _dbgMemSize(h, __FILE__, __LINE__) +#define MemSizeRequested(h) _dbgMemSizeRequested(h, __FILE__, __LINE__) +#define MemLockCount(h) _dbgMemLockCount(h, __FILE__, __LINE__) +#define MemIsMoveable(h) _dbgMemIsMoveable(h, __FILE__, __LINE__) +#define MemHandle(p) _dbgMemHandle(p, __FILE__, __LINE__) +#define MemAllocPtr(p, s, f) _dbgMemAllocPtr(p, s, f, __FILE__, __LINE__) +#define MemReAllocPtr(p, s, f) _dbgMemReAllocPtr(p, s, f, __FILE__,__LINE__) +#define MemFreePtr(p) _dbgMemFreePtr(p, __FILE__, __LINE__) +#define MemSizePtr(p) _dbgMemSizePtr(p, __FILE__, __LINE__) +#define MemCheckPtr(p, x) _dbgMemCheckPtr(p, x, __FILE__, __LINE__) +#define MemAllocFS(p) _dbgMemAllocFS(p, __FILE__, __LINE__) +#define MemFreeFS(p) _dbgMemFreeFS(p, __FILE__, __LINE__) + +#else /* MEM_DEBUG */ + +/* MEM_DEBUG not defined: define dbgMemXXX as no-op macros + * each macro returns "success" value when MEM_DEBUG not defined + */ +#ifndef dbgMemBreakpoint +#define dbgMemBreakpoint() ((void)0) +#define dbgMemCheckAll() 1 +#define dbgMemCheckPtr(p, f, s) 1 +#define dbgMemDeferFreeing(b) 1 +#define dbgMemFormatCall(i, b, s) 0 +#define dbgMemFormatErrorInfo(i, b, s) 0 +#define dbgMemPoolDeferFreeing(p, b) 1 +#define dbgMemFreeDeferred() 1 +#define dbgMemPoolFreeDeferred(p) 1 +#define dbgMemPoolInfo(p, b) 1 +#define dbgMemPoolSetCheckFrequency(p, f) 1 +#define dbgMemPoolSetDeferQueueLen(p, b) 1 +#define dbgMemPoolSetName(p, n) 1 +#define dbgMemProtectPtr(p, f) 1 +#define dbgMemPtrInfo(p, b) 1 +#define dbgMemReallocMoves(b) 1 +#define dbgMemReportLeakage(p, c1, c2) 1 +#define dbgMemReportWrongTaskRef(b) 1 +#define dbgMemScheduleChecking(b, p, i) 1 +#define dbgMemSetCheckFrequency(f) 1 +#define dbgMemSetCheckpoint(c) 1 +#define dbgMemSetDefaultErrorOutput(x, f) 1 +#define dbgMemSetDeferQueueLen(l) 1 +#define dbgMemSetDeferSizeThreshold(s) 1 +#define dbgMemSetEntryHandler(f) 0 +#define dbgMemSetExitHandler(f) 0 +#define dbgMemSetFreeFill(c) 1 +#define dbgMemSetGuardFill(c) 1 +#define dbgMemSetGuardSize(s) 1 +#define dbgMemSetInUseFill(c) 1 +#define dbgMemSetCallstackChains(s) 1 +#define dbgMemSetStackChecking(s) 1 +#define dbgMemSetSafetyLevel(s) 1 +#define dbgMemSettingsInfo(b) 1 +#define dbgMemSuppressFreeFill(b) 1 +#define dbgMemTotalCount() 1 +#define dbgMemTotalSize() 1 +#define dbgMemWalkHeap(b) MEM_POOL_OK +#endif /* dbgMemBreakpoint */ + +#endif /* MEM_DEBUG */ +#endif /* _SHI_dbgMacros */ + +#if defined(__WATCOMC__) && defined(__SW_3S) +/* Watcom stack calling convention */ + #pragma aux MemDefaultPool "_*"; + #pragma aux MemDefaultPoolBlockSizeFS "_*"; + #pragma aux MemDefaultPoolPageSize "_*"; + #pragma aux MemDefaultPoolFlags "_*"; + #pragma aux SmartHeap_malloc "_*"; + #pragma aux SmartHeap_far_malloc "_*"; + #pragma aux SmartHeap_new "_*"; +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_PROT) */ diff --git a/3rdparty/smartheap/SMRTHEAP.HPP b/3rdparty/smartheap/SMRTHEAP.HPP new file mode 100644 index 00000000..663b6c90 --- /dev/null +++ b/3rdparty/smartheap/SMRTHEAP.HPP @@ -0,0 +1,159 @@ +// smrtheap.hpp -- SmartHeap public C++ header file +// Professional Memory Management Library +// +// Copyright (C) 1991-1996 by Arthur D. Applegate +// All Rights Reserved. +// +// No part of this source code may be copied, modified or reproduced +// in any form without retaining the above copyright notice. +// This source code, or source code derived from it, may not be redistributed +// without express written permission of the author. +// +// COMMENTS: +// - Include this header file to call the SmartHeap-specific versions of +// operators new (i.e. with placement syntax), to: +// o allocate from a specific memory pool; +// o specify allocation flags, such as zero-initialization; +// o resize an allocation. +// +// - If you include this header file, you must compile and link shnew.cpp, or +// link with one of the SmartHeap static operator new libraries: +// sh[l|d]XXXX.lib +// +// - Can be used in both EXEs and DLLs. +// +// - For 16-bit x86 platforms, use only in large or compact memory model. +// +// - If you do not want to use SmartHeap's global operator new but you do +// want to use SmartHeap's other facilities in a C++ application, then +// include the smrtheap.h header file but do not include this header file, +// and do not link with shnew.cpp. The two ".Xpp" files are present +// ONLY for the purpose of defining operator new and operator delete. +// +// - Use the MemDefaultPool global variable to refer to a memory pool to pass +// to SmartHeap functions that accept a pool as a parameter, +// e.g. MemPoolCount, MemPoolSize, MemPoolWalk, etc. +// + +#if !defined(_SMARTHEAP_HPP) +#define _SMARTHEAP_HPP + +#if defined(_MSC_VER) \ + && (defined(M_I86LM) || defined(M_I86CM) || defined(M_I86HM)) \ + && !defined(MEM_HUGE) +#define MEM_HUGE 0x8000u +#endif + +#ifndef __BORLANDC__ +/* Borland C++ does not treat extern "C++" correctly */ +extern "C++" +{ +#endif /* __BORLANDC__ */ + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(disable : 4507) +#endif + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#endif +#endif + +#include + +#include "smrtheap.h" + +#if defined(new) +#if defined(MEM_DEBUG) +#undef new +#endif +#endif + +#if ((defined(__BORLANDC__) && (__BORLANDC__ >= 0x450)) \ + || (defined(__WATCOMC__) && __WATCOMC__ >= 1000) \ + || (defined(__IBMCPP__) && __IBMCPP__ >= 250)) +#define SHI_ARRAY_NEW 1 +#endif + +void MEM_FAR * MEM_ENTRY_ANSI shi_New(unsigned long sz, unsigned flags=0, MEM_POOL pool=0); + +// operator new variants: + + +// version of new that passes memory allocation flags +// (e.g. MEM_ZEROINIT to zero-initialize memory) +// call with syntax 'ptr = new (flags) ' +inline void MEM_FAR *operator new(size_t sz, unsigned flags) + { return shi_New(sz, flags); } + +// version of new that allocates from a specified memory pool with alloc flags +// call with the syntax 'ptr = new (pool, [flags=0]) ' +inline void MEM_FAR *operator new(size_t sz, MEM_POOL pool, unsigned flags=0) + { return shi_New(sz, flags, pool); } +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t sz, MEM_POOL pool, unsigned flags=0) + { return shi_New(sz, flags, pool); } +#endif + +// version of new that changes the size of a memory block previously allocated +// from an SmartHeap memory pool +// call with the syntax 'ptr = new (ptr, flags) ' +#if !defined(MEM_DEBUG) || !defined(__HIGHC__) +/* bug in MetaWare High C++ parser confuses this with new(file,line) */ +inline void MEM_FAR *operator new(size_t new_sz, void MEM_FAR *lpMem, + unsigned flags) + { return MemReAllocPtr(lpMem, new_sz, flags); } +#ifdef SHI_ARRAY_NEW +inline void MEM_FAR *operator new[](size_t new_sz, void MEM_FAR *lpMem, + unsigned flags) + { return MemReAllocPtr(lpMem, new_sz, flags); } +#endif // SHI_ARRAY_NEW +#endif + + +// new_handler prototypes: note that MSC/C++ prototype differs from the +// protosed ANSI standard prototype for set_new_handler +#ifdef __MWERKS__ +#define MEM_CPP_THROW throw() +#else +#define MEM_CPP_THROW +#endif // __MWERKS__ +#ifndef _CRTIMP +#define _CRTIMP +#endif // _CRTIMP +#ifdef _MSC_VER +_CRTIMP _PNH MEM_ENTRY_ANSI _set_new_handler(_PNH); +#if UINT_MAX == 0xFFFFu +_PNH MEM_ENTRY_ANSI _set_fnew_handler(_PNH); +_PNHH MEM_ENTRY_ANSI _set_hnew_handler(_PNHH); +#endif // UINT_MAX +#endif // _MSC_VER +typedef void (MEM_ENTRY_ANSI * pnh)(); +_CRTIMP pnh MEM_ENTRY_ANSI set_new_handler(pnh) MEM_CPP_THROW; + +#ifndef DBG_FORMAL +#define DBG_FORMAL +#define DBG_ACTUAL +#ifndef DEBUG_NEW +#define DEBUG_NEW new +#endif // DEBUG_NEW +#define DEBUG_NEW1(x_) new(x_) +#define DEBUG_NEW2(x_, y_) new(x_, y_) +#define DEBUG_NEW3(x_, y_, z_) new(x_, y_, z_) +#define DEBUG_DELETE delete +#endif + +#ifdef DEFINE_NEW_MACRO +#define new DEBUG_NEW +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 900 +#pragma warning(default : 4507) +#endif + +#ifndef __BORLANDC__ +} +#endif /* __BORLANDC__ */ + +#endif /* !defined(_SMARTHEAP_HPP) */ diff --git a/CMakeLists.txt b/CMakeLists.txt index 6067d1f9..eafee9ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,8 +1,9 @@ -cmake_minimum_required(VERSION 3.0...3.5 FATAL_ERROR) +cmake_minimum_required(VERSION 3.13 FATAL_ERROR) project(isle CXX) option(ISLE_BUILD_APP "Build ISLE.EXE application" ON) +option(ISLE_USE_SMARTHEAP "Build with SmartHeap" ${MSVC}) add_library(lego1 SHARED LEGO1/act1state.cpp @@ -177,6 +178,16 @@ add_library(lego1 SHARED LEGO1/viewmanager.cpp ) +if (ISLE_USE_SMARTHEAP) + add_library(SmartHeap::SmartHeap STATIC IMPORTED) + set_target_properties(SmartHeap::SmartHeap PROPERTIES + IMPORTED_LOCATION "${CMAKE_SOURCE_DIR}/3rdparty/smartheap/SHLW32MT.LIB" + INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/3rdparty/smartheap" + INTERFACE_COMPILE_OPTIONS "/FI${CMAKE_SOURCE_DIR}/3rdparty/smartheap/SMRTHEAP.HPP") + + target_link_libraries(lego1 PRIVATE SmartHeap::SmartHeap) +endif() + # Link libraries target_link_libraries(lego1 PRIVATE ddraw dsound winmm) @@ -194,6 +205,10 @@ if (ISLE_BUILD_APP) # Include LEGO1 headers in ISLE target_include_directories(isle PRIVATE "${CMAKE_SOURCE_DIR}/LEGO1") + if (ISLE_USE_SMARTHEAP) + target_link_libraries(isle PRIVATE SmartHeap::SmartHeap) + endif() + # Link DSOUND, WINMM, and LEGO1 target_link_libraries(isle PRIVATE dsound winmm lego1) From 4a50a9ff56f9edf3f2848b3439fda64c3c609e43 Mon Sep 17 00:00:00 2001 From: pewpew Date: Sun, 16 Jul 2023 01:43:08 -0500 Subject: [PATCH 05/10] MxNotificationManager and MxParam initial work. (#78) * MxNotificationManager initial work. * Add .swp files to .gitignore. * Checkpoint before anything too crazy with param * Cleanup and add MxParam. * Checkpoint for everything except MxNotificationManager::Register. * Add int return type to MxCore::GetId instead of relying on implicit function nonsense. * Add stlcompat.h so this can still be built on modern compilers, fix affected type size asserts. * Switch to Mx types * Add BUILD_COMPAT option to CMake so the project can still be built with modern compilers. * Change vtable14 and vtable18 to Register and Unregister in MxTickleManager. * Remove last unsigned int reference to id type. * Remove MxList, use one inherited class per type. Improves accuracy again. * Address compiler compatibility code review. * Match MxNotificationManager::Register. * Re-enable MxNotificationManager DECOMP_SIZE_ASSERT. --- .gitignore | 1 + CMakeLists.txt | 1 + LEGO1/compat.h | 13 +++ LEGO1/mxcore.h | 7 +- LEGO1/mxnotificationmanager.cpp | 140 ++++++++++++++++++++++++++++++-- LEGO1/mxnotificationmanager.h | 52 +++++++++++- LEGO1/mxparam.cpp | 11 +++ LEGO1/mxparam.h | 33 ++++++++ LEGO1/mxticklemanager.h | 4 +- 9 files changed, 250 insertions(+), 12 deletions(-) create mode 100644 LEGO1/mxparam.cpp create mode 100644 LEGO1/mxparam.h diff --git a/.gitignore b/.gitignore index 14ad2717..402fb660 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ Release/ ISLE.EXE LEGO1.DLL build/ +*.swp diff --git a/CMakeLists.txt b/CMakeLists.txt index eafee9ff..fa4de1e5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -135,6 +135,7 @@ add_library(lego1 SHARED LEGO1/mxomnicreateparam.cpp LEGO1/mxomnicreateparambase.cpp LEGO1/mxpalette.cpp + LEGO1/mxparam.cpp LEGO1/mxpresenter.cpp LEGO1/mxscheduler.cpp LEGO1/mxsemaphore.cpp diff --git a/LEGO1/compat.h b/LEGO1/compat.h index 7d76dfd0..6248259b 100644 --- a/LEGO1/compat.h +++ b/LEGO1/compat.h @@ -11,6 +11,19 @@ #define COMPAT_CONST #endif +#define MSVC420_VERSION 1020 + +// STL compatibility. +#if defined(_MSC_VER) && _MSC_VER <= MSVC420_VERSION +#include +#else +#include +#include +using namespace std; +template +using List = list; +#endif + // We use `override` so newer compilers can tell us our vtables are valid, // however this keyword was added in C++11, so we define it as empty for // compatibility with older compilers. diff --git a/LEGO1/mxcore.h b/LEGO1/mxcore.h index 9fb3e689..8ca7c421 100644 --- a/LEGO1/mxcore.h +++ b/LEGO1/mxcore.h @@ -31,8 +31,13 @@ class MxCore return !strcmp(name, MxCore::ClassName()); } + inline MxU32 GetId() + { + return m_id; + } + private: - unsigned int m_id; + MxU32 m_id; }; diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index 472c87b5..593572bb 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -1,15 +1,143 @@ +#include "legoomni.h" +#include "mxautolocker.h" +#include "mxcore.h" #include "mxnotificationmanager.h" +#include "mxparam.h" +#include "mxtypes.h" -// OFFSET: LEGO1 0x100ac450 STUB +#include "compat.h" +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxNotification, 0x8); +DECOMP_SIZE_ASSERT(MxNotificationManager, 0x40); + +// OFFSET: LEGO1 0x100ac220 +MxNotification::MxNotification(MxCore *p_target, MxParam *p_param) +{ + m_target = p_target; + m_param = p_param->Clone(); +} + +// OFFSET: LEGO1 0x100ac240 +MxNotification::~MxNotification() +{ + delete m_param; +} + +// OFFSET: LEGO1 0x100ac250 +MxNotificationManager::MxNotificationManager() : MxCore(), m_lock(), m_listenerIds() +{ + m_unk2c = 0; + m_queue = NULL; + m_active = TRUE; + m_sendList = NULL; +} + +// OFFSET: LEGO1 0x100ac450 MxNotificationManager::~MxNotificationManager() +{ + MxAutoLocker lock(&m_lock); + Tickle(); + delete m_queue; + m_queue = NULL; + + TickleManager()->Unregister(this); +} + +// OFFSET: LEGO1 0x100ac800 +MxResult MxNotificationManager::Tickle() +{ + m_sendList = new MxNotificationPtrList(); + if (m_sendList == NULL) { + return FAILURE; + } + else { + { + MxAutoLocker lock(&m_lock); + swap(m_queue, m_sendList); + } + + while (m_sendList->size() != 0) { + MxNotification *notif = m_sendList->front(); + m_sendList->pop_front(); + notif->GetTarget()->Notify(*notif->GetParam()); + delete notif; + } + + delete m_sendList; + m_sendList = NULL; + return SUCCESS; + } +} + +// OFFSET: LEGO1 0x100ac600 +MxResult MxNotificationManager::Create(MxS32 p_unk1, MxS32 p_unk2) +{ + MxResult result = SUCCESS; + m_queue = new MxNotificationPtrList(); + + if (m_queue == NULL) { + result = FAILURE; + } + else { + TickleManager()->Register(this, 10); + } + + return result; +} + +// OFFSET: LEGO1 0x100acd20 +void MxNotificationManager::Register(MxCore *p_listener) +{ + MxAutoLocker lock(&m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it != m_listenerIds.end()) + return; + + m_listenerIds.push_back(p_listener->GetId()); +} + +// OFFSET: LEGO1 0x100acdf0 +void MxNotificationManager::Unregister(MxCore *p_listener) +{ + MxAutoLocker lock(&m_lock); + + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + + if (it != m_listenerIds.end()) { + m_listenerIds.erase(it); + FlushPending(p_listener); + } +} + +// OFFSET: LEGO1 0x100ac990 STUB +void MxNotificationManager::FlushPending(MxCore *p_listener) { // TODO } -// OFFSET: LEGO1 0x100ac800 STUB -MxLong MxNotificationManager::Tickle() +// OFFSET: LEGO1 0x100ac6c0 +MxResult MxNotificationManager::Send(MxCore *p_listener, MxParam *p_param) { - // TODO + MxAutoLocker lock(&m_lock); - return 0; -} \ No newline at end of file + if (m_active == FALSE) { + return FAILURE; + } + else { + MxIdList::iterator it = find(m_listenerIds.begin(), m_listenerIds.end(), p_listener->GetId()); + if (it == m_listenerIds.end()) { + return FAILURE; + } + else { + MxNotification *notif = new MxNotification(p_listener, p_param); + if (notif != NULL) { + m_queue->push_back(notif); + return SUCCESS; + } + } + } + + return FAILURE; +} diff --git a/LEGO1/mxnotificationmanager.h b/LEGO1/mxnotificationmanager.h index 86cb4f00..e313510b 100644 --- a/LEGO1/mxnotificationmanager.h +++ b/LEGO1/mxnotificationmanager.h @@ -2,16 +2,62 @@ #define MXNOTIFICATIONMANAGER_H #include "mxcore.h" +#include "mxcriticalsection.h" +#include "mxtypes.h" + +#include "compat.h" + +class MxNotification +{ +public: + MxNotification(MxCore *p_target, MxParam *p_param); + ~MxNotification(); + + inline MxCore *GetTarget() + { + return m_target; + } + + inline MxParam *GetParam() + { + return m_param; + } + +private: + MxCore *m_target; // 0x0 + MxParam *m_param; // 0x4 +}; + +class MxIdList : public List +{}; + +class MxNotificationPtrList : public List +{}; // VTABLE 0x100dc078 class MxNotificationManager : public MxCore { +private: + MxNotificationPtrList *m_queue; // 0x8 + MxNotificationPtrList *m_sendList; // 0xc + MxCriticalSection m_lock; // 0x10 + MxS32 m_unk2c; // 0x2c + MxIdList m_listenerIds; // 0x30 + MxBool m_active; // 0x3c + public: - virtual ~MxNotificationManager(); // vtable+0x0 + MxNotificationManager(); + virtual ~MxNotificationManager(); // vtable+0x0 (scalar deleting destructor) - virtual MxLong Tickle(); // vtable+0x8 + virtual MxResult Tickle(); // vtable+0x8 + // TODO: Where does this method come from? + virtual MxResult Create(MxS32 p_unk1, MxS32 p_unk2); // vtable+0x14 + void Register(MxCore *p_listener); + void Unregister(MxCore *p_listener); + MxResult Send(MxCore *p_listener, MxParam *p_param); - // 0x10: MxCriticalSection +private: + void FlushPending(MxCore *p_listener); }; #endif // MXNOTIFICATIONMANAGER_H diff --git a/LEGO1/mxparam.cpp b/LEGO1/mxparam.cpp new file mode 100644 index 00000000..d7bb36b2 --- /dev/null +++ b/LEGO1/mxparam.cpp @@ -0,0 +1,11 @@ +#include "mxparam.h" + +#include "decomp.h" + +DECOMP_SIZE_ASSERT(MxParam, 0xc); + +// OFFSET: LEGO1 0x10010390 +MxParam* MxParam::Clone() +{ + return new MxParam(m_type, m_sender); +} diff --git a/LEGO1/mxparam.h b/LEGO1/mxparam.h new file mode 100644 index 00000000..c4150ff7 --- /dev/null +++ b/LEGO1/mxparam.h @@ -0,0 +1,33 @@ +#ifndef MXPARAM_H +#define MXPARAM_H + +#include "mxomnicreateparambase.h" +#include "mxtypes.h" + +class MxCore; + +// VTABLE 0x100d56e0 +class MxParam : public MxOmniCreateParamBase +{ +public: + inline MxParam(MxS32 p_type, MxCore *p_sender) : MxOmniCreateParamBase(), m_type(p_type), m_sender(p_sender){} + + virtual ~MxParam(){}; // vtable+0x0 (scalar deleting destructor) + virtual MxParam *Clone(); // vtable+0x4 + + inline MxS32 GetType() const + { + return m_type; + } + + inline MxCore *GetSender() const + { + return m_sender; + } + +private: + MxS32 m_type; // 0x4 + MxCore *m_sender; // 0x8 +}; + +#endif // MXPARAM_H diff --git a/LEGO1/mxticklemanager.h b/LEGO1/mxticklemanager.h index 60f2f14d..3d976d5a 100644 --- a/LEGO1/mxticklemanager.h +++ b/LEGO1/mxticklemanager.h @@ -12,8 +12,8 @@ class MxTickleManager : public MxCore virtual MxLong Tickle(); virtual const char *ClassName() const; virtual MxBool IsA(const char *name) const; - virtual void vtable14(); - virtual void vtable18(); + virtual void Register(MxCore *p_listener, int p_milliseconds); + virtual void Unregister(MxCore *p_listener); virtual void vtable1c(void *v, int p); virtual void vtable20(); }; From e3bf7b53b57de2629ccc96ef87bfe325453241de Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Sun, 16 Jul 2023 02:49:47 -0400 Subject: [PATCH 06/10] MxEntity (#84) * Start MxEntity * MxEntity: make MxAtomId a member --- LEGO1/mxentity.cpp | 15 ++++----------- LEGO1/mxentity.h | 10 +++++----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/LEGO1/mxentity.cpp b/LEGO1/mxentity.cpp index 7459dd24..1b5ea84f 100644 --- a/LEGO1/mxentity.cpp +++ b/LEGO1/mxentity.cpp @@ -1,19 +1,12 @@ #include "mxentity.h" -// OFFSET: LEGO1 0x1001d190 STUB +// OFFSET: LEGO1 0x1001d190 MxEntity::MxEntity() { - // TODO + this->m_mxEntityId = -1; } -// OFFSET: LEGO1 0x1000c110 STUB +// OFFSET: LEGO1 0x1000c110 MxEntity::~MxEntity() { - // TODO -} - -// OFFSET: LEGO1 0x10001070 STUB -void MxEntity::Destroy() -{ - // TODO -} +} \ No newline at end of file diff --git a/LEGO1/mxentity.h b/LEGO1/mxentity.h index 7123abbf..a7e26e37 100644 --- a/LEGO1/mxentity.h +++ b/LEGO1/mxentity.h @@ -1,7 +1,9 @@ #ifndef MXENTITY_H #define MXENTITY_H +#include "mxatomid.h" #include "mxcore.h" +#include "mxtypes.h" // VTABLE 0x100d5390 class MxEntity : public MxCore @@ -22,11 +24,9 @@ class MxEntity : public MxCore { return !strcmp(name, MxEntity::ClassName()) || MxCore::IsA(name); } - - virtual void Destroy(); // vtable+0x1c - - // 0x8: MxResult - // 0xc MxAtomId +private: + MxS32 m_mxEntityId; // 0x8 + MxAtomId m_atom; // 0xc }; #endif // MXENTITY_H From a31626cffb7a393f37ec558505af0d505d20b627 Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Sun, 16 Jul 2023 02:51:11 -0400 Subject: [PATCH 07/10] MxDSAction/Chunk/MediaAction/Sound (#85) * Match MxDSChunk ctor/dtor * Push work on MxDSAction/MediaAction/Sound * MxDSMediaAction constructor is matching up to a mov location * Match MxDSSound constructor by adding the missing member just four bytes in between them in ghidra.. isn't that enough for ghidra to justify a member variable? * Match MxDSMediaAction constructor Today's lesson: ecx suggests '1' --- LEGO1/mxdsaction.cpp | 8 +++--- LEGO1/mxdsaction.h | 55 ++++++++++++++++++++------------------- LEGO1/mxdschunk.cpp | 14 +++++++--- LEGO1/mxdschunk.h | 12 ++++++++- LEGO1/mxdsmediaaction.cpp | 13 ++++++--- LEGO1/mxdsmediaaction.h | 12 ++++++++- LEGO1/mxdssound.cpp | 2 +- LEGO1/mxdssound.h | 4 +++ 8 files changed, 80 insertions(+), 40 deletions(-) diff --git a/LEGO1/mxdsaction.cpp b/LEGO1/mxdsaction.cpp index e5162f89..b5cf6e75 100644 --- a/LEGO1/mxdsaction.cpp +++ b/LEGO1/mxdsaction.cpp @@ -5,10 +5,12 @@ MxDSAction::MxDSAction() { // TODO this->SetType(MxDSType_Action); + this->m_omni = NULL; + this->m_someTimingField = -0x80000000; } -// OFFSET: LEGO1 0x100ada80 STUB +// OFFSET: LEGO1 0x100ada80 MxDSAction::~MxDSAction() { - // TODO -} + delete this->m_unk7c; +} \ No newline at end of file diff --git a/LEGO1/mxdsaction.h b/LEGO1/mxdsaction.h index e26d28a6..155d7cc2 100644 --- a/LEGO1/mxdsaction.h +++ b/LEGO1/mxdsaction.h @@ -2,6 +2,7 @@ #define MXDSACTION_H #include "mxdsobject.h" +#include "mxomni.h" // VTABLE 0x100dc098 // SIZE 0x94 @@ -23,33 +24,33 @@ class MxDSAction : public MxDSObject { return !strcmp(name, MxDSAction::ClassName()) || MxDSObject::IsA(name); } - - int m_unk2c; - int m_unk30; - int m_unk34; - int m_unk38; - int m_unk3c; - int m_unk40; - int m_unk44; - int m_unk48; - int m_unk4c; - int m_unk50; - int m_unk54; - int m_unk58; - int m_unk5c; - int m_unk60; - int m_unk64; - int m_unk68; - int m_unk6c; - int m_unk70; - int m_unk74; - int m_unk78; - int m_unk7c; - int m_unk80; - int m_unk84; - int m_unk88; - int m_unk8c; - int m_unk90; +private: + MxLong m_unk2c; + MxLong m_unk30; + MxLong m_unk34; + MxLong* m_unk38; + MxLong m_unk3c; + MxLong m_unk40; + MxLong m_unk44; + MxLong m_unk48; + MxLong m_unk4c; + MxLong m_unk50; + MxLong m_unk54; + MxLong m_unk58; + MxLong m_unk5c; + MxLong m_unk60; + MxLong m_unk64; + MxLong m_unk68; + MxLong m_unk6c; + MxLong m_unk70; + MxLong m_unk74; + MxLong m_unk78; + MxLong* m_unk7c; + MxLong m_unk80; + MxLong m_unk84; + MxLong m_unk88; + MxOmni* m_omni; // 0x8c + MxS32 m_someTimingField; // 0x90 }; #endif // MXDSACTION_H diff --git a/LEGO1/mxdschunk.cpp b/LEGO1/mxdschunk.cpp index 7ec8531c..63c43ba2 100644 --- a/LEGO1/mxdschunk.cpp +++ b/LEGO1/mxdschunk.cpp @@ -1,13 +1,19 @@ #include "mxdschunk.h" -// OFFSET: LEGO1 0x100be050 STUB +// OFFSET: LEGO1 0x100be050 MxDSChunk::MxDSChunk() { - // TODO + this->m_length = 0; + this->m_pStuff = NULL; + this->m_buffer = -1; + this->m_long1FromHeader = 0; + this->m_long2FromHeader = 0; } -// OFFSET: LEGO1 0x100be170 STUB +// OFFSET: LEGO1 0x100be170 MxDSChunk::~MxDSChunk() { - // TODO + if ((this->m_length & 1) != 0) { + delete this->m_pStuff; + } } diff --git a/LEGO1/mxdschunk.h b/LEGO1/mxdschunk.h index 8758ffa3..f9b1d9d0 100644 --- a/LEGO1/mxdschunk.h +++ b/LEGO1/mxdschunk.h @@ -1,8 +1,11 @@ #ifndef MXDSCHUNK_H #define MXDSCHUNK_H -#include "mxcore.h" +#include "mxcore.h" +#include "mxtypes.h" + +// VTABLE 0x100dc7f8 class MxDSChunk : public MxCore { public: @@ -21,6 +24,13 @@ class MxDSChunk : public MxCore { return !strcmp(name, MxDSChunk::ClassName()) || MxCore::IsA(name); } +private: + MxS16 m_length; // 0x8 + MxLong m_buffer; // 0xc + MxLong m_long1FromHeader; // 0x10 + MxLong m_long2FromHeader; // 0x14 + void* m_pStuff; // 0x18 + void* m_pSomething; // 0x1c }; #endif // MXDSCHUNK_H diff --git a/LEGO1/mxdsmediaaction.cpp b/LEGO1/mxdsmediaaction.cpp index 5f9c1132..a8acde30 100644 --- a/LEGO1/mxdsmediaaction.cpp +++ b/LEGO1/mxdsmediaaction.cpp @@ -3,12 +3,19 @@ // OFFSET: LEGO1 0x100c8b40 MxDSMediaAction::MxDSMediaAction() { - // TODO + this->m_unk98 = 0; + this->m_unk9c = 0; + this->m_unka0 = 0; + this->m_unka4 = 0; + this->m_unka8 = 0; + this->m_unkac = 1; + this->m_unkb4 = 0xffffffff; + this->m_unkb0 = 0; this->SetType(MxDSType_MediaAction); } -// OFFSET: LEGO1 0x100c8cf0 STUB +// OFFSET: LEGO1 0x100c8cf0 MxDSMediaAction::~MxDSMediaAction() { - // TODO + delete this->m_unk98; } diff --git a/LEGO1/mxdsmediaaction.h b/LEGO1/mxdsmediaaction.h index 5beb12f5..5e6a6141 100644 --- a/LEGO1/mxdsmediaaction.h +++ b/LEGO1/mxdsmediaaction.h @@ -1,6 +1,7 @@ #ifndef MXDSMEDIAACTION_H #define MXDSMEDIAACTION_H +#include "decomp.h" #include "mxdsaction.h" // VTABLE 0x100dcd40 @@ -23,7 +24,16 @@ class MxDSMediaAction : public MxDSAction { return !strcmp(name, MxDSMediaAction::ClassName()) || MxDSAction::IsA(name); } - +private: + MxS32* m_unk94; + MxS32* m_unk98; + MxS32* m_unk9c; + MxS32* m_unka0; + MxS32* m_unka4; + MxS32* m_unka8; + MxS32 m_unkac; + MxS32* m_unkb0; + MxS32 m_unkb4; }; #endif // MXDSMEDIAACTION_H diff --git a/LEGO1/mxdssound.cpp b/LEGO1/mxdssound.cpp index 30894abc..d05f785d 100644 --- a/LEGO1/mxdssound.cpp +++ b/LEGO1/mxdssound.cpp @@ -3,7 +3,7 @@ // OFFSET: LEGO1 0x100c92c0 MxDSSound::MxDSSound() { - // TODO + this->m_lastField = 0x4f; this->SetType(MxDSType_Sound); } diff --git a/LEGO1/mxdssound.h b/LEGO1/mxdssound.h index 45a61d63..eca6c055 100644 --- a/LEGO1/mxdssound.h +++ b/LEGO1/mxdssound.h @@ -2,6 +2,7 @@ #define MXDSSOUND_H #include "mxdsmediaaction.h" +#include "mxtypes.h" // VTABLE 0x100dcdd0 // SIZE 0xc0 @@ -23,6 +24,9 @@ class MxDSSound : public MxDSMediaAction { return !strcmp(name, MxDSSound::ClassName()) || MxDSMediaAction::IsA(name); } +private: + MxS32 m_unkb8; + MxLong m_lastField; // 0xbc }; From 19dcfe1164e20cf5296bd4bad459fe837b41b2ca Mon Sep 17 00:00:00 2001 From: Mark Langen Date: Sun, 16 Jul 2023 09:27:30 -0700 Subject: [PATCH 08/10] Fix SmartHeap files (#90) --- 3rdparty/smartheap/SHMALLOC.H | 126 ++-- 3rdparty/smartheap/SMRTHEAP.H | 1312 ++++++++++++++++----------------- 2 files changed, 719 insertions(+), 719 deletions(-) diff --git a/3rdparty/smartheap/SHMALLOC.H b/3rdparty/smartheap/SHMALLOC.H index fff43c88..709c19b8 100644 --- a/3rdparty/smartheap/SHMALLOC.H +++ b/3rdparty/smartheap/SHMALLOC.H @@ -1,63 +1,63 @@ -/* shmalloc.h -- SmartHeap ANSI Standard C memory API - * Professional Memory Management Library - * - * Copyright (C) 1991-1996 by Arthur D. Applegate. All Rights Reserved. - * All Rights Reserved. - * - * No part of this source code may be copied, modified or reproduced - * in any form without retaining the above copyright notice. - * This source code, or source code derived from it, may not be redistributed - * without express written permission of the author. - */ - -#if !(defined(_SHMALLOC_H)) -#define _SHMALLOC_H - -#include "smrtheap.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/* ANSI Standard Memory Management API */ - -#if (!defined(MEM_DEBUG) && !defined(NO_MALLOC_MACRO)) || defined(MALLOC_MACRO) -#ifdef malloc -#undef malloc -#endif -#define malloc(s) MEM_malloc(s) -#ifdef calloc -#undef calloc -#endif -#define calloc(s,c) MEM_calloc(s,c) -#ifdef realloc -#undef realloc -#endif -#define realloc(p,s) MEM_realloc(p,s) -#ifdef free -#undef free -#endif -#define free(p) MEM_free(p) - -#endif /* NO_MALLOC_MACRO */ - -#ifndef MEM_malloc -void MEM_FAR * MEM_ENTRY_ANSI MEM_malloc(size_t size); -void MEM_FAR * MEM_ENTRY_ANSI MEM_calloc(size_t nobj, size_t size); -void MEM_FAR * MEM_ENTRY_ANSI MEM_realloc(void MEM_FAR *p, size_t size); -void MEM_ENTRY_ANSI MEM_free(void MEM_FAR *p); -#endif /* MEM_malloc */ - -#if defined(__WATCOMC__) && defined(__SW_3S) -/* Watcom stack calling convention */ - #pragma aux (syscall) MEM_malloc - #pragma aux (syscall) MEM_realloc - #pragma aux (syscall) MEM_calloc - #pragma aux (syscall) MEM_free -#endif /* __WATCOMC__ */ - -#ifdef __cplusplus -} -#endif - -#endif /* !defined(_SHMALLOC_H) */ +/* shmalloc.h -- SmartHeap ANSI Standard C memory API + * Professional Memory Management Library + * + * Copyright (C) 1991-1996 by Arthur D. Applegate. All Rights Reserved. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the author. + */ + +#if !(defined(_SHMALLOC_H)) +#define _SHMALLOC_H + +#include "smrtheap.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ANSI Standard Memory Management API */ + +#if (!defined(MEM_DEBUG) && !defined(NO_MALLOC_MACRO)) || defined(MALLOC_MACRO) +#ifdef malloc +#undef malloc +#endif +#define malloc(s) MEM_malloc(s) +#ifdef calloc +#undef calloc +#endif +#define calloc(s,c) MEM_calloc(s,c) +#ifdef realloc +#undef realloc +#endif +#define realloc(p,s) MEM_realloc(p,s) +#ifdef free +#undef free +#endif +#define free(p) MEM_free(p) + +#endif /* NO_MALLOC_MACRO */ + +#ifndef MEM_malloc +void MEM_FAR * MEM_ENTRY_ANSI MEM_malloc(size_t size); +void MEM_FAR * MEM_ENTRY_ANSI MEM_calloc(size_t nobj, size_t size); +void MEM_FAR * MEM_ENTRY_ANSI MEM_realloc(void MEM_FAR *p, size_t size); +void MEM_ENTRY_ANSI MEM_free(void MEM_FAR *p); +#endif /* MEM_malloc */ + +#if defined(__WATCOMC__) && defined(__SW_3S) +/* Watcom stack calling convention */ + #pragma aux (syscall) MEM_malloc + #pragma aux (syscall) MEM_realloc + #pragma aux (syscall) MEM_calloc + #pragma aux (syscall) MEM_free +#endif /* __WATCOMC__ */ + +#ifdef __cplusplus +} +#endif + +#endif /* !defined(_SHMALLOC_H) */ diff --git a/3rdparty/smartheap/SMRTHEAP.H b/3rdparty/smartheap/SMRTHEAP.H index aab58b84..b4f17a74 100644 --- a/3rdparty/smartheap/SMRTHEAP.H +++ b/3rdparty/smartheap/SMRTHEAP.H @@ -1,656 +1,656 @@ -/* smrtheap.h -- SmartHeap (tm) public C header file - * Professional Memory Management Library - * - * Copyright (C) 1991-1997 by Arthur D. Applegate. All Rights Reserved. - * All Rights Reserved. - * - * No part of this source code may be copied, modified or reproduced - * in any form without retaining the above copyright notice. - * This source code, or source code derived from it, may not be redistributed - * without express written permission of the author. - * - */ - -#if !defined(_SMARTHEAP_H) -#define _SMARTHEAP_H - -#include -#include - -#if !defined(macintosh) && !defined(THINK_C) && !defined(__MWERKS__) \ - && !defined(SHANSI) && UINT_MAX == 0xFFFFu \ - && (defined(_Windows) || defined(_WINDOWS) || defined(__WINDOWS__)) - #define MEM_WIN16 -#endif - -#if (UINT_MAX == 0xFFFFu) && (defined(MEM_WIN16) \ - || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__)) - /* 16-bit X86 */ - #if defined(SYS_DLL) - #if defined(_MSC_VER) && _MSC_VER <= 600 - #define MEM_ENTRY _export _loadds far pascal - #else - #define MEM_ENTRY _export far pascal - #endif - #else - #define MEM_ENTRY far pascal - #endif - #ifdef __WATCOMC__ - #define MEM_ENTRY_ANSI __far - #else - #define MEM_ENTRY_ANSI far cdecl - #endif - #define MEM_FAR far - #if defined(MEM_WIN16) - #define MEM_ENTRY2 _export far pascal - #elif defined(DOS16M) || defined(DOSX286) - #define MEM_ENTRY2 _export _loadds far pascal - #endif - -#else /* not 16-bit X86 */ - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) \ - || defined(__WIN32__) || defined(__NT__) - #define MEM_WIN32 - #if defined(_MSC_VER) - #if defined(_SHI_Pool) && defined(SYS_DLL) - #define MEM_ENTRY1 __declspec(dllexport) - #define MEM_ENTRY4 __declspec(dllexport) extern - #elif !defined(_SHI_Pool) && (defined(MEM_DEBUG) || defined(MEM_DLL)) - #define MEM_ENTRY1 __declspec(dllimport) - #if defined(_M_IX86) || defined(_X86_) - #define MemDefaultPool shi_MemDefaultPool - #define MEM_ENTRY4 __declspec(dllimport) - #endif - #endif - #endif - #if !defined(_MSC_VER) || defined(_M_IX86) || defined(_X86_) - #define MEM_ENTRY __stdcall - #else - #define MEM_ENTRY __cdecl /* for NT/RISC */ - #endif - #ifndef __WATCOMC__ - #define MEM_ENTRY_ANSI __cdecl - #endif - -#elif defined(__OS2__) - #if defined(__BORLANDC__) || defined(__WATCOMC__) - #if defined(SYS_DLL) - #define MEM_ENTRY __export __syscall - #else - #define MEM_ENTRY __syscall - #endif /* SYS_DLL */ - #ifdef __BORLANDC__ - #define MEM_ENTRY_ANSI __stdcall - #endif - #elif defined(__IBMC__) || defined(__IBMCPP__) - #if defined(SYS_DLL) && 0 - #define MEM_ENTRY _Export _System - #else - #define MEM_ENTRY _System - #endif - #define MEM_ENTRY_ANSI _Optlink - #define MEM_ENTRY3 MEM_ENTRY - #define MEM_CALLBACK MEM_ENTRY3 - #define MEM_ENTRY2 - #endif -#endif /* __OS2__ */ - -#if defined(__WATCOMC__) && defined(__SW_3S) - /* Watcom stack calling convention */ -#ifndef __OS2__ -#ifdef __WINDOWS_386__ - #pragma aux syscall "*_" parm routine [eax ebx ecx edx fs gs] modify [eax]; -#else - #pragma aux syscall "*_" parm routine [eax ebx ecx edx] modify [eax]; -#endif -#ifndef MEM_ENTRY - #define MEM_ENTRY __syscall -#endif /* MEM_ENTRY */ -#endif -#endif /* Watcom stack calling convention */ - -#endif /* end of system-specific declarations */ - -#ifndef MEM_ENTRY - #define MEM_ENTRY -#endif -#ifndef MEM_ENTRY1 - #define MEM_ENTRY1 -#endif -#ifndef MEM_ENTRY2 - #define MEM_ENTRY2 MEM_ENTRY -#endif -#ifndef MEM_ENTRY3 - #define MEM_ENTRY3 -#endif -#ifndef MEM_ENTRY4 - #define MEM_ENTRY4 extern -#endif -#ifndef MEM_CALLBACK -#define MEM_CALLBACK MEM_ENTRY2 -#endif -#ifndef MEM_ENTRY_ANSI - #define MEM_ENTRY_ANSI -#endif -#ifndef MEM_FAR - #define MEM_FAR -#endif - -#ifdef applec -/* Macintosh: Apple MPW C/C++ passes char/short parms as longs (4 bytes), - * whereas Symantec C/C++ for MPW passes these as words (2 bytes); - * therefore, canonicalize all integer parms as 'int' for this platform. - */ - #define MEM_USHORT unsigned - #define MEM_UCHAR unsigned -#else - #define MEM_USHORT unsigned short - #define MEM_UCHAR unsigned char -#endif /* applec */ - -#ifdef MEM_DEBUG -#include "heapagnt.h" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -/*** Types ***/ - -#ifndef MEM_BOOL_DEFINED -#define MEM_BOOL_DEFINED -typedef int MEM_BOOL; -#endif - -/* Version Masks */ -typedef unsigned MEM_VERSION; -#define MEM_MAJOR_VERSION(v) (((v) & 0xF000u) >> 12) -#define MEM_MINOR_VERSION(v) (((v) & 0x0F00u) >> 8) -#define MEM_UPDATE_VERSION(v) ((v) & 0x00FFu) - -/* Note: these types are struct's rather than integral types to facilitate - * compile-time type-checking. MEM_POOL and MEM_HANDLE should be regarded - * as black boxes, and treated just like handles. - * You should not have any type casts to or from MEM_POOL or MEM_HANDLE; - * nor should you dereference variables of type MEM_POOL or MEM_HANDLE - * (unless you are using SmartHeap to replace NewHandle on the Mac, and - * you have existing code that dereferences handles). - */ -#ifndef MEM_POOL_DEFINED -#define MEM_POOL_DEFINED -#ifdef _SHI_Pool - typedef struct _SHI_Pool MEM_FAR *MEM_POOL; - typedef struct _SHI_MovHandle MEM_FAR *MEM_HANDLE; -#else - #ifdef THINK_C - typedef void *MEM_POOL; - typedef void **MEM_HANDLE; - #else - typedef struct _SHI_Pool { int reserved; } MEM_FAR *MEM_POOL; - typedef struct _SHI_MovHandle { int reserved; } MEM_FAR *MEM_HANDLE; - #endif -#endif -#endif /* MEM_POOL_DEFINED */ - - -#if !defined(MEM_DEBUG) || !(defined(MEM_WIN16) || defined(MEM_WIN32)) -#define SHI_MAJOR_VERSION 3 -#define SHI_MINOR_VERSION 3 -#define SHI_UPDATE_LEVEL 0 -#endif /* !WINDOWS */ - -#ifndef MEM_DEBUG - -/* Error codes: errorCode field of MEM_ERROR_INFO */ -#ifndef MEM_ERROR_CODE_DEFINED -#define MEM_ERROR_CODE_DEFINED -typedef enum -{ - MEM_NO_ERROR=0, - MEM_INTERNAL_ERROR, - MEM_OUT_OF_MEMORY, - MEM_BLOCK_TOO_BIG, - MEM_ALLOC_ZERO, - MEM_RESIZE_FAILED, - MEM_LOCK_ERROR, - MEM_EXCEEDED_CEILING, - MEM_TOO_MANY_PAGES, - MEM_TOO_MANY_TASKS, - MEM_BAD_MEM_POOL, - MEM_BAD_BLOCK, - MEM_BAD_FREE_BLOCK, - MEM_BAD_HANDLE, - MEM_BAD_POINTER, - MEM_WRONG_TASK, - MEM_NOT_FIXED_SIZE, - MEM_BAD_FLAGS, - MEM_ERROR_CODE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ -} MEM_ERROR_CODE; -#endif /* MEM_ERROR_CODE_DEFINED */ - - -/* ### we should have packing pragma around these structure decls in case - * ### user is compiling with non-default packing directive (only needed - * ### if user is packing more strictly than native int size *and* if - * ### native int size is != native long and ptr sizes) - */ - -/* Error info, passed to error-handling callback routine */ -#ifndef MEM_ERROR_INFO_DEFINED -#define MEM_ERROR_INFO_DEFINED -typedef struct _MEM_ERROR_INFO -{ - MEM_ERROR_CODE errorCode; /* error code identifying type of error */ - MEM_POOL pool; /* pool in which error occurred, if known */ -} MEM_ERROR_INFO; - -/* Error handling callback function */ -typedef MEM_BOOL (MEM_ENTRY2 * MEM_ENTRY3 MEM_ERROR_FN) - (MEM_ERROR_INFO MEM_FAR *); - -#endif /* MEM_ERROR_INFO_DEFINED */ - -#endif /* MEM_DEBUG */ - - -#ifndef MEM_BLOCK_TYPE_DEFINED -#define MEM_BLOCK_TYPE_DEFINED -/* Block Type: field of MEM_POOL_ENTRY, field of MEM_POOL_INFO, - * parameter to MemPoolPreAllocate - */ -typedef enum -{ - MEM_FS_BLOCK = 0x0001u, - MEM_VAR_MOVEABLE_BLOCK = 0x0002u, - MEM_VAR_FIXED_BLOCK = 0x0004u, - MEM_EXTERNAL_BLOCK = 0x0008u, - MEM_BLOCK_TYPE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ -} MEM_BLOCK_TYPE; -#endif /* MEM_BLOCK_TYPE_DEFINED */ - -#ifndef MEM_POOL_ENTRY_DEFINED -#define MEM_POOL_ENTRY_DEFINED -/* Pool Entry: parameter to MemPoolWalk */ -typedef struct -{ - void MEM_FAR *entry; - MEM_POOL pool; - MEM_BLOCK_TYPE type; - MEM_BOOL isInUse; - unsigned long size; - MEM_HANDLE handle; - unsigned lockCount; - void MEM_FAR *reserved_ptr; -} MEM_POOL_ENTRY; -#endif /* MEM_POOL_ENTRY_DEFINED */ - -#ifndef MEM_POOL_STATUS_DEFINED -#define MEM_POOL_STATUS_DEFINED -/* Pool Status: returned by MemPoolWalk, MemPoolFirst, MemPoolNext */ -typedef enum -{ - MEM_POOL_OK = 1, - MEM_POOL_CORRUPT = -1, - MEM_POOL_CORRUPT_FATAL = -2, - MEM_POOL_END = 0, - MEM_POOL_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ -} MEM_POOL_STATUS; -#endif /* MEM_POOL_STATUS_DEFINED */ - -#ifndef MEM_POINTER_STATUS_DEFINED -#define MEM_POINTER_STATUS_DEFINED -/* Pointer Status: returned by MemCheckPtr */ -typedef enum -{ - MEM_POINTER_OK = 1, - MEM_POINTER_WILD = 0, - MEM_POINTER_FREE = -1, - MEM_POINTER_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ -} MEM_POINTER_STATUS; -#endif /* MEM_POINTER_STATUS_DEFINED */ - -/* Pool Info: parameter to MemPoolInfo, MemPoolFirst, MemPoolNext */ -typedef struct -{ - MEM_POOL pool; - MEM_BLOCK_TYPE type; /* disjunctive combination of block type flags */ - unsigned short blockSizeFS; - unsigned short smallBlockSize; - unsigned pageSize; - unsigned long floor; - unsigned long ceiling; - unsigned flags; - MEM_ERROR_FN errorFn; -} MEM_POOL_INFO; - -/* Flags passed to MemAlloc, MemAllocPtr, MemReAlloc, MemReAllocPtr */ -#define MEM_FIXED 0x0000u /* fixed handle-based block */ -#define MEM_ZEROINIT 0x0001u /* == TRUE for SH 1.5 compatibility */ -#define MEM_MOVEABLE 0x0002u /* moveable handle-based block */ -#define MEM_RESIZEABLE 0x0004u /* reserve space above block */ -#define MEM_RESIZE_IN_PLACE 0x0008u /* do not move block (realloc) */ -#define MEM_NOGROW 0x0010u /* do not grow heap to satisfy request */ -#define MEM_NOEXTERNAL 0x0020u /* reserved for internal use */ -#define MEM_NOCOMPACT 0x0040u /* do not compact to satisfy request */ -#define MEM_NO_SERIALIZE 0x0080u /* do not serialize this request */ -#define MEM_HANDLEBASED 0x4000u /* for internal use */ -#define MEM_RESERVED 0x8000u /* for internal use */ - -#define MEM_UNLOCK_FAILED USHRT_MAX - -/* Flags passed to MemPoolInit, MemPoolInitFS */ -#ifndef MEM_POOL_SHARED -#define MEM_POOL_SHARED 0x0001u /* == TRUE for SH 1.5 compatibility */ -#define MEM_POOL_SERIALIZE 0x0002u /* pool used in more than one thread */ -#define MEM_POOL_VIRTUAL_LOCK 0x0004u /* pool is locked in physical memory */ -#define MEM_POOL_ZEROINIT 0x0008u /* malloc/new from pool zero-inits */ -#define MEM_POOL_REGION 0x0010u /* store pool in user-supplied region*/ -#define MEM_POOL_DEFAULT 0x8000u /* pool with default characteristics */ -#endif /* MEM_POOL_SHARED */ - -MEM_ENTRY4 MEM_POOL MemDefaultPool; - -/* Default memory pool for C malloc, C++ new (for backwards compatibility) */ -#define MEM_DEFAULT_POOL MemDefaultPool - -/* define and initialize these variables at file scope to change defaults */ -extern unsigned short MemDefaultPoolBlockSizeFS; -extern unsigned MemDefaultPoolPageSize; -extern unsigned MemDefaultPoolFlags; - -/* define SmartHeap_malloc at file scope if you - * are intentionally _NOT_ linking in the SmartHeap malloc definition - * ditto for SmartHeap operator new, and fmalloc et al. - */ -extern int SmartHeap_malloc; -extern int SmartHeap_far_malloc; -extern int SmartHeap_new; - -#define MEM_ERROR_RET ULONG_MAX - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* !defined(_SMARTHEAP_H) */ - - -/*** Function Prototypes ***/ - -#ifndef _SMARTHEAP_PROT -#define _SMARTHEAP_PROT - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef _shAPI - #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) - #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY _dbg ## name - #else - #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY name - #endif -#endif - -#ifndef _dbgARGS - #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) - #define _dbgARGS1 const char MEM_FAR *, int - #define _dbgARGS , _dbgARGS1 - #else - #define _dbgARGS1 void - #define _dbgARGS - #endif -#endif - - -/**** HOW TO READ SmartHeap PROTOTYPES **** - * prototypes below have the follow syntax in order to support both debug - * and non-debug APIs with single-source: - * - * _shiAPI(, )([] _dbgARGS); - * - * the above translates to a C prototype as follows: - * - * ([]); - */ - -/* Library Version */ -MEM_ENTRY1 MEM_VERSION MEM_ENTRY MemVersion(void); - -/* Library Registration */ -_shAPI(MEM_BOOL, MemRegisterTask)(_dbgARGS1); -_shAPI(MEM_BOOL, MemUnregisterTask)(_dbgARGS1); - -/* Memory Pool Functions */ -_shAPI(MEM_POOL, MemPoolInit)(unsigned _dbgARGS); -_shAPI(MEM_POOL, MemPoolInitFS)(MEM_USHORT, unsigned long, - unsigned _dbgARGS); -_shAPI(MEM_POOL, MemPoolInitRegion)(void MEM_FAR *, - unsigned long size, unsigned _dbgARGS); -_shAPI(MEM_POOL, MemPoolInitNamedShared)(const char MEM_FAR *, - unsigned long size,unsigned _dbgARGS); -_shAPI(MEM_POOL, MemPoolInitNamedSharedEx)(void MEM_FAR *addr, - unsigned pidCount, unsigned long MEM_FAR *pids, void MEM_FAR *security, - const char MEM_FAR *name, unsigned long size, unsigned flags _dbgARGS); -_shAPI(MEM_POOL, MemPoolAttachShared)(MEM_POOL, const char MEM_FAR * _dbgARGS); -_shAPI(MEM_BOOL, MemPoolFree)(MEM_POOL _dbgARGS); -MEM_POOL MEM_ENTRY MemInitDefaultPool(void); -MEM_BOOL MEM_ENTRY MemFreeDefaultPool(void); -_shAPI(unsigned, MemPoolSetPageSize)(MEM_POOL, unsigned _dbgARGS); -_shAPI(MEM_BOOL, MemPoolSetBlockSizeFS)(MEM_POOL, MEM_USHORT _dbgARGS); -_shAPI(MEM_BOOL, MemPoolSetSmallBlockSize)(MEM_POOL, MEM_USHORT _dbgARGS); -_shAPI(unsigned long, MemPoolSetFloor)(MEM_POOL, unsigned long _dbgARGS); -_shAPI(unsigned long, MemPoolSetCeiling)(MEM_POOL, unsigned long _dbgARGS); -_shAPI(unsigned long, MemPoolPreAllocate)(MEM_POOL, unsigned long, - MEM_BLOCK_TYPE _dbgARGS); -_shAPI(unsigned long, MemPoolPreAllocateHandles)(MEM_POOL, - unsigned long _dbgARGS); -_shAPI(unsigned long, MemPoolShrink)(MEM_POOL _dbgARGS); -_shAPI(unsigned long, MemPoolSize)(MEM_POOL _dbgARGS); -_shAPI(unsigned long, MemPoolCount)(MEM_POOL _dbgARGS); -_shAPI(MEM_BOOL, MemPoolInfo)(MEM_POOL, void MEM_FAR *, - MEM_POOL_INFO MEM_FAR* _dbgARGS); -_shAPI(MEM_POOL_STATUS, MemPoolFirst)(MEM_POOL_INFO MEM_FAR *, - MEM_BOOL _dbgARGS); -_shAPI(MEM_POOL_STATUS,MemPoolNext)(MEM_POOL_INFO MEM_FAR*,MEM_BOOL _dbgARGS); -_shAPI(MEM_POOL_STATUS,MemPoolWalk)(MEM_POOL,MEM_POOL_ENTRY MEM_FAR*_dbgARGS); -_shAPI(MEM_BOOL, MemPoolCheck)(MEM_POOL _dbgARGS); -_shAPI(MEM_BOOL, MemPoolLock)(MEM_POOL _dbgARGS); -_shAPI(MEM_BOOL, MemPoolUnlock)(MEM_POOL _dbgARGS); - -/* Handle-based API for moveable memory within heap. */ -_shAPI(MEM_HANDLE, MemAlloc)(MEM_POOL, unsigned, unsigned long _dbgARGS); -_shAPI(MEM_HANDLE, MemReAlloc)(MEM_HANDLE,unsigned long,unsigned _dbgARGS); -_shAPI(MEM_BOOL, MemFree)(MEM_HANDLE _dbgARGS); -_shAPI(void MEM_FAR *, MemLock)(MEM_HANDLE _dbgARGS); -_shAPI(unsigned, MemUnlock)(MEM_HANDLE _dbgARGS); -_shAPI(void MEM_FAR *, MemFix)(MEM_HANDLE _dbgARGS); -_shAPI(unsigned, MemUnfix)(MEM_HANDLE _dbgARGS); -_shAPI(unsigned, MemLockCount)(MEM_HANDLE _dbgARGS); -#ifndef MemFlags -#define MemFlags(mem) MemLockCount(mem) -#endif -_shAPI(MEM_BOOL, MemIsMoveable)(MEM_HANDLE _dbgARGS); -_shAPI(unsigned long, MemSize)(MEM_HANDLE _dbgARGS); -_shAPI(unsigned long, MemSizeRequested)(MEM_HANDLE _dbgARGS); -_shAPI(MEM_HANDLE, MemHandle)(void MEM_FAR * _dbgARGS); -#ifndef MEM_REFERENCE - #ifdef MEM_DEBUG - MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemReference(MEM_HANDLE, - const char MEM_FAR *, int); - #define MEM_REFERENCE(handle) \ - _dbgMemReference(handle, __FILE__, __LINE__) - #else - #define MEM_REFERENCE(handle) (*(void MEM_FAR * MEM_FAR *)handle) - #endif -#endif - -/* General Heap Allocator (returns direct pointer to memory) */ -_shAPI(void MEM_FAR*,MemAllocPtr)(MEM_POOL,unsigned long,unsigned _dbgARGS); -_shAPI(void MEM_FAR *, MemReAllocPtr)(void MEM_FAR *, unsigned long, - unsigned _dbgARGS); -_shAPI(MEM_BOOL, MemFreePtr)(void MEM_FAR * _dbgARGS); -_shAPI(unsigned long, MemSizePtr)(void MEM_FAR * _dbgARGS); -_shAPI(MEM_POINTER_STATUS, MemCheckPtr)(MEM_POOL, void MEM_FAR * _dbgARGS); - -/* Fixed-Size Allocator */ -_shAPI(void MEM_FAR *, MemAllocFS)(MEM_POOL _dbgARGS); -_shAPI(MEM_BOOL, MemFreeFS)(void MEM_FAR * _dbgARGS); - -/* Error Handling Functions */ -MEM_ENTRY1 MEM_ERROR_FN MEM_ENTRY MemSetErrorHandler(MEM_ERROR_FN); -MEM_ENTRY1 MEM_BOOL MEM_ENTRY MemDefaultErrorHandler(MEM_ERROR_INFO MEM_FAR*); -MEM_ENTRY1 void MEM_ENTRY MemErrorUnwind(void); - -#ifdef MEM_WIN32 -/* patching control */ - -#ifndef MEM_PATCHING_DEFINED -#define MEM_PATCHING_DEFINED -typedef enum -{ - MEM_PATCH_ALL = 0, - MEM_SKIP_PATCHING_THIS_DLL = 1, - MEM_DISABLE_SYSTEM_HEAP_PATCHING = 2, - MEM_DISABLE_ALL_PATCHING = 4|2|1, - MEM_PATCHING_INT_MAX = INT_MAX /* to ensure enum is full int in size */ -} MEM_PATCHING; -#endif /* MEM_PATCHING_DEFINED */ - -#ifdef _MSC_VER -__declspec(dllexport) -#endif -MEM_PATCHING MEM_ENTRY MemSetPatching(const char ***skipDLLs); - -#endif /* MEM_WIN32 */ - -/* internal routines */ -MEM_ENTRY1 MEM_BOOL MEM_ENTRY _shi_enterCriticalSection(void); -MEM_ENTRY1 void MEM_ENTRY _shi_leaveCriticalSection(void); -MEM_BOOL shi_call_new_handler_msc(size_t, MEM_BOOL); - - -/* Wrapper macros for debugging API */ -#ifndef _SHI_dbgMacros -#ifdef MEM_DEBUG -#define MemRegisterTask() _dbgMemRegisterTask(__FILE__, __LINE__) -#define MemUnregisterTask() _dbgMemUnregisterTask(__FILE__, __LINE__) -#define MemPoolInit(flags) _dbgMemPoolInit(flags, __FILE__, __LINE__) -#define MemPoolInitFS(bs, bc, f) _dbgMemPoolInitFS(bs,bc,f,__FILE__,__LINE__) -#define MemPoolInitRegion(addr, sz, f) \ - _dbgMemPoolInitRegion(addr, sz, f, __FILE__, __LINE__) -#define MemPoolInitNamedShared(nm, sz, f) \ - _dbgMemPoolInitNamedShared(nm, sz, f, __FILE__, __LINE__) -#define MemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f) \ - _dbgMemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f, __FILE__, __LINE__) -#define MemPoolAttachShared(p, n) \ - _dbgMemPoolAttachShared(p, n, __FILE__, __LINE__) -#define MemPoolFree(pool) _dbgMemPoolFree(pool, __FILE__, __LINE__) -#define MemPoolSetPageSize(p, s) _dbgMemPoolSetPageSize(p,s,__FILE__,__LINE__) -#define MemPoolSetBlockSizeFS(p, s) \ - _dbgMemPoolSetBlockSizeFS(p, s, __FILE__, __LINE__) -#define MemPoolSetSmallBlockSize(p, s) \ - _dbgMemPoolSetSmallBlockSize(p, s, __FILE__, __LINE__) -#define MemPoolSetFloor(p, f) _dbgMemPoolSetFloor(p, f, __FILE__, __LINE__) -#define MemPoolSetCeiling(p, c) _dbgMemPoolSetCeiling(p,c,__FILE__, __LINE__) -#define MemPoolPreAllocate(p,s,t) \ - _dbgMemPoolPreAllocate(p,s,t,__FILE__, __LINE__) -#define MemPoolPreAllocateHandles(p,h) \ - _dbgMemPoolPreAllocateHandles(p,h,__FILE__, __LINE__) -#define MemPoolShrink(p) _dbgMemPoolShrink(p, __FILE__, __LINE__) -#define MemPoolCheck(p) _dbgMemPoolCheck(p, __FILE__, __LINE__) -#define MemPoolWalk(p, e) _dbgMemPoolWalk(p, e, __FILE__, __LINE__) -#define MemPoolSize(p) _dbgMemPoolSize(p, __FILE__, __LINE__) -#define MemPoolCount(p) _dbgMemPoolCount(p, __FILE__, __LINE__) -#define MemPoolInfo(p,x,i) _dbgMemPoolInfo(p,x,i, __FILE__, __LINE__) -#define MemPoolFirst(i, b) _dbgMemPoolFirst(i, b, __FILE__, __LINE__) -#define MemPoolNext(i, b) _dbgMemPoolNext(i, b, __FILE__, __LINE__) -#define MemPoolLock(p) _dbgMemPoolLock(p, __FILE__, __LINE__) -#define MemPoolUnlock(p) _dbgMemPoolUnlock(p, __FILE__, __LINE__) -#define MemAlloc(p, f, s) _dbgMemAlloc(p, f, s, __FILE__, __LINE__) -#define MemReAlloc(h, s, f) _dbgMemReAlloc(h, s, f, __FILE__, __LINE__) -#define MemFree(h) _dbgMemFree(h, __FILE__, __LINE__) -#define MemLock(h) _dbgMemLock(h, __FILE__, __LINE__) -#define MemUnlock(h) _dbgMemUnlock(h, __FILE__, __LINE__) -#define MemFix(h) _dbgMemFix(h, __FILE__, __LINE__) -#define MemUnfix(h) _dbgMemUnfix(h, __FILE__, __LINE__) -#define MemSize(h) _dbgMemSize(h, __FILE__, __LINE__) -#define MemSizeRequested(h) _dbgMemSizeRequested(h, __FILE__, __LINE__) -#define MemLockCount(h) _dbgMemLockCount(h, __FILE__, __LINE__) -#define MemIsMoveable(h) _dbgMemIsMoveable(h, __FILE__, __LINE__) -#define MemHandle(p) _dbgMemHandle(p, __FILE__, __LINE__) -#define MemAllocPtr(p, s, f) _dbgMemAllocPtr(p, s, f, __FILE__, __LINE__) -#define MemReAllocPtr(p, s, f) _dbgMemReAllocPtr(p, s, f, __FILE__,__LINE__) -#define MemFreePtr(p) _dbgMemFreePtr(p, __FILE__, __LINE__) -#define MemSizePtr(p) _dbgMemSizePtr(p, __FILE__, __LINE__) -#define MemCheckPtr(p, x) _dbgMemCheckPtr(p, x, __FILE__, __LINE__) -#define MemAllocFS(p) _dbgMemAllocFS(p, __FILE__, __LINE__) -#define MemFreeFS(p) _dbgMemFreeFS(p, __FILE__, __LINE__) - -#else /* MEM_DEBUG */ - -/* MEM_DEBUG not defined: define dbgMemXXX as no-op macros - * each macro returns "success" value when MEM_DEBUG not defined - */ -#ifndef dbgMemBreakpoint -#define dbgMemBreakpoint() ((void)0) -#define dbgMemCheckAll() 1 -#define dbgMemCheckPtr(p, f, s) 1 -#define dbgMemDeferFreeing(b) 1 -#define dbgMemFormatCall(i, b, s) 0 -#define dbgMemFormatErrorInfo(i, b, s) 0 -#define dbgMemPoolDeferFreeing(p, b) 1 -#define dbgMemFreeDeferred() 1 -#define dbgMemPoolFreeDeferred(p) 1 -#define dbgMemPoolInfo(p, b) 1 -#define dbgMemPoolSetCheckFrequency(p, f) 1 -#define dbgMemPoolSetDeferQueueLen(p, b) 1 -#define dbgMemPoolSetName(p, n) 1 -#define dbgMemProtectPtr(p, f) 1 -#define dbgMemPtrInfo(p, b) 1 -#define dbgMemReallocMoves(b) 1 -#define dbgMemReportLeakage(p, c1, c2) 1 -#define dbgMemReportWrongTaskRef(b) 1 -#define dbgMemScheduleChecking(b, p, i) 1 -#define dbgMemSetCheckFrequency(f) 1 -#define dbgMemSetCheckpoint(c) 1 -#define dbgMemSetDefaultErrorOutput(x, f) 1 -#define dbgMemSetDeferQueueLen(l) 1 -#define dbgMemSetDeferSizeThreshold(s) 1 -#define dbgMemSetEntryHandler(f) 0 -#define dbgMemSetExitHandler(f) 0 -#define dbgMemSetFreeFill(c) 1 -#define dbgMemSetGuardFill(c) 1 -#define dbgMemSetGuardSize(s) 1 -#define dbgMemSetInUseFill(c) 1 -#define dbgMemSetCallstackChains(s) 1 -#define dbgMemSetStackChecking(s) 1 -#define dbgMemSetSafetyLevel(s) 1 -#define dbgMemSettingsInfo(b) 1 -#define dbgMemSuppressFreeFill(b) 1 -#define dbgMemTotalCount() 1 -#define dbgMemTotalSize() 1 -#define dbgMemWalkHeap(b) MEM_POOL_OK -#endif /* dbgMemBreakpoint */ - -#endif /* MEM_DEBUG */ -#endif /* _SHI_dbgMacros */ - -#if defined(__WATCOMC__) && defined(__SW_3S) -/* Watcom stack calling convention */ - #pragma aux MemDefaultPool "_*"; - #pragma aux MemDefaultPoolBlockSizeFS "_*"; - #pragma aux MemDefaultPoolPageSize "_*"; - #pragma aux MemDefaultPoolFlags "_*"; - #pragma aux SmartHeap_malloc "_*"; - #pragma aux SmartHeap_far_malloc "_*"; - #pragma aux SmartHeap_new "_*"; -#endif - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* !defined(_SMARTHEAP_PROT) */ +/* smrtheap.h -- SmartHeap (tm) public C header file + * Professional Memory Management Library + * + * Copyright (C) 1991-1997 by Arthur D. Applegate. All Rights Reserved. + * All Rights Reserved. + * + * No part of this source code may be copied, modified or reproduced + * in any form without retaining the above copyright notice. + * This source code, or source code derived from it, may not be redistributed + * without express written permission of the author. + * + */ + +#if !defined(_SMARTHEAP_H) +#define _SMARTHEAP_H + +#include +#include + +#if !defined(macintosh) && !defined(THINK_C) && !defined(__MWERKS__) \ + && !defined(SHANSI) && UINT_MAX == 0xFFFFu \ + && (defined(_Windows) || defined(_WINDOWS) || defined(__WINDOWS__)) + #define MEM_WIN16 +#endif + +#if (UINT_MAX == 0xFFFFu) && (defined(MEM_WIN16) \ + || defined(MSDOS) || defined(__MSDOS__) || defined(__DOS__)) + /* 16-bit X86 */ + #if defined(SYS_DLL) + #if defined(_MSC_VER) && _MSC_VER <= 600 + #define MEM_ENTRY _export _loadds far pascal + #else + #define MEM_ENTRY _export far pascal + #endif + #else + #define MEM_ENTRY far pascal + #endif + #ifdef __WATCOMC__ + #define MEM_ENTRY_ANSI __far + #else + #define MEM_ENTRY_ANSI far cdecl + #endif + #define MEM_FAR far + #if defined(MEM_WIN16) + #define MEM_ENTRY2 _export far pascal + #elif defined(DOS16M) || defined(DOSX286) + #define MEM_ENTRY2 _export _loadds far pascal + #endif + +#else /* not 16-bit X86 */ + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) \ + || defined(__WIN32__) || defined(__NT__) + #define MEM_WIN32 + #if defined(_MSC_VER) + #if defined(_SHI_Pool) && defined(SYS_DLL) + #define MEM_ENTRY1 __declspec(dllexport) + #define MEM_ENTRY4 __declspec(dllexport) extern + #elif !defined(_SHI_Pool) && (defined(MEM_DEBUG) || defined(MEM_DLL)) + #define MEM_ENTRY1 __declspec(dllimport) + #if defined(_M_IX86) || defined(_X86_) + #define MemDefaultPool shi_MemDefaultPool + #define MEM_ENTRY4 __declspec(dllimport) + #endif + #endif + #endif + #if !defined(_MSC_VER) || defined(_M_IX86) || defined(_X86_) + #define MEM_ENTRY __stdcall + #else + #define MEM_ENTRY __cdecl /* for NT/RISC */ + #endif + #ifndef __WATCOMC__ + #define MEM_ENTRY_ANSI __cdecl + #endif + +#elif defined(__OS2__) + #if defined(__BORLANDC__) || defined(__WATCOMC__) + #if defined(SYS_DLL) + #define MEM_ENTRY __export __syscall + #else + #define MEM_ENTRY __syscall + #endif /* SYS_DLL */ + #ifdef __BORLANDC__ + #define MEM_ENTRY_ANSI __stdcall + #endif + #elif defined(__IBMC__) || defined(__IBMCPP__) + #if defined(SYS_DLL) && 0 + #define MEM_ENTRY _Export _System + #else + #define MEM_ENTRY _System + #endif + #define MEM_ENTRY_ANSI _Optlink + #define MEM_ENTRY3 MEM_ENTRY + #define MEM_CALLBACK MEM_ENTRY3 + #define MEM_ENTRY2 + #endif +#endif /* __OS2__ */ + +#if defined(__WATCOMC__) && defined(__SW_3S) + /* Watcom stack calling convention */ +#ifndef __OS2__ +#ifdef __WINDOWS_386__ + #pragma aux syscall "*_" parm routine [eax ebx ecx edx fs gs] modify [eax]; +#else + #pragma aux syscall "*_" parm routine [eax ebx ecx edx] modify [eax]; +#endif +#ifndef MEM_ENTRY + #define MEM_ENTRY __syscall +#endif /* MEM_ENTRY */ +#endif +#endif /* Watcom stack calling convention */ + +#endif /* end of system-specific declarations */ + +#ifndef MEM_ENTRY + #define MEM_ENTRY +#endif +#ifndef MEM_ENTRY1 + #define MEM_ENTRY1 +#endif +#ifndef MEM_ENTRY2 + #define MEM_ENTRY2 MEM_ENTRY +#endif +#ifndef MEM_ENTRY3 + #define MEM_ENTRY3 +#endif +#ifndef MEM_ENTRY4 + #define MEM_ENTRY4 extern +#endif +#ifndef MEM_CALLBACK +#define MEM_CALLBACK MEM_ENTRY2 +#endif +#ifndef MEM_ENTRY_ANSI + #define MEM_ENTRY_ANSI +#endif +#ifndef MEM_FAR + #define MEM_FAR +#endif + +#ifdef applec +/* Macintosh: Apple MPW C/C++ passes char/short parms as longs (4 bytes), + * whereas Symantec C/C++ for MPW passes these as words (2 bytes); + * therefore, canonicalize all integer parms as 'int' for this platform. + */ + #define MEM_USHORT unsigned + #define MEM_UCHAR unsigned +#else + #define MEM_USHORT unsigned short + #define MEM_UCHAR unsigned char +#endif /* applec */ + +#ifdef MEM_DEBUG +#include "heapagnt.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*** Types ***/ + +#ifndef MEM_BOOL_DEFINED +#define MEM_BOOL_DEFINED +typedef int MEM_BOOL; +#endif + +/* Version Masks */ +typedef unsigned MEM_VERSION; +#define MEM_MAJOR_VERSION(v) (((v) & 0xF000u) >> 12) +#define MEM_MINOR_VERSION(v) (((v) & 0x0F00u) >> 8) +#define MEM_UPDATE_VERSION(v) ((v) & 0x00FFu) + +/* Note: these types are struct's rather than integral types to facilitate + * compile-time type-checking. MEM_POOL and MEM_HANDLE should be regarded + * as black boxes, and treated just like handles. + * You should not have any type casts to or from MEM_POOL or MEM_HANDLE; + * nor should you dereference variables of type MEM_POOL or MEM_HANDLE + * (unless you are using SmartHeap to replace NewHandle on the Mac, and + * you have existing code that dereferences handles). + */ +#ifndef MEM_POOL_DEFINED +#define MEM_POOL_DEFINED +#ifdef _SHI_Pool + typedef struct _SHI_Pool MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle MEM_FAR *MEM_HANDLE; +#else + #ifdef THINK_C + typedef void *MEM_POOL; + typedef void **MEM_HANDLE; + #else + typedef struct _SHI_Pool { int reserved; } MEM_FAR *MEM_POOL; + typedef struct _SHI_MovHandle { int reserved; } MEM_FAR *MEM_HANDLE; + #endif +#endif +#endif /* MEM_POOL_DEFINED */ + + +#if !defined(MEM_DEBUG) || !(defined(MEM_WIN16) || defined(MEM_WIN32)) +#define SHI_MAJOR_VERSION 3 +#define SHI_MINOR_VERSION 3 +#define SHI_UPDATE_LEVEL 0 +#endif /* !WINDOWS */ + +#ifndef MEM_DEBUG + +/* Error codes: errorCode field of MEM_ERROR_INFO */ +#ifndef MEM_ERROR_CODE_DEFINED +#define MEM_ERROR_CODE_DEFINED +typedef enum +{ + MEM_NO_ERROR=0, + MEM_INTERNAL_ERROR, + MEM_OUT_OF_MEMORY, + MEM_BLOCK_TOO_BIG, + MEM_ALLOC_ZERO, + MEM_RESIZE_FAILED, + MEM_LOCK_ERROR, + MEM_EXCEEDED_CEILING, + MEM_TOO_MANY_PAGES, + MEM_TOO_MANY_TASKS, + MEM_BAD_MEM_POOL, + MEM_BAD_BLOCK, + MEM_BAD_FREE_BLOCK, + MEM_BAD_HANDLE, + MEM_BAD_POINTER, + MEM_WRONG_TASK, + MEM_NOT_FIXED_SIZE, + MEM_BAD_FLAGS, + MEM_ERROR_CODE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_ERROR_CODE; +#endif /* MEM_ERROR_CODE_DEFINED */ + + +/* ### we should have packing pragma around these structure decls in case + * ### user is compiling with non-default packing directive (only needed + * ### if user is packing more strictly than native int size *and* if + * ### native int size is != native long and ptr sizes) + */ + +/* Error info, passed to error-handling callback routine */ +#ifndef MEM_ERROR_INFO_DEFINED +#define MEM_ERROR_INFO_DEFINED +typedef struct _MEM_ERROR_INFO +{ + MEM_ERROR_CODE errorCode; /* error code identifying type of error */ + MEM_POOL pool; /* pool in which error occurred, if known */ +} MEM_ERROR_INFO; + +/* Error handling callback function */ +typedef MEM_BOOL (MEM_ENTRY2 * MEM_ENTRY3 MEM_ERROR_FN) + (MEM_ERROR_INFO MEM_FAR *); + +#endif /* MEM_ERROR_INFO_DEFINED */ + +#endif /* MEM_DEBUG */ + + +#ifndef MEM_BLOCK_TYPE_DEFINED +#define MEM_BLOCK_TYPE_DEFINED +/* Block Type: field of MEM_POOL_ENTRY, field of MEM_POOL_INFO, + * parameter to MemPoolPreAllocate + */ +typedef enum +{ + MEM_FS_BLOCK = 0x0001u, + MEM_VAR_MOVEABLE_BLOCK = 0x0002u, + MEM_VAR_FIXED_BLOCK = 0x0004u, + MEM_EXTERNAL_BLOCK = 0x0008u, + MEM_BLOCK_TYPE_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_BLOCK_TYPE; +#endif /* MEM_BLOCK_TYPE_DEFINED */ + +#ifndef MEM_POOL_ENTRY_DEFINED +#define MEM_POOL_ENTRY_DEFINED +/* Pool Entry: parameter to MemPoolWalk */ +typedef struct +{ + void MEM_FAR *entry; + MEM_POOL pool; + MEM_BLOCK_TYPE type; + MEM_BOOL isInUse; + unsigned long size; + MEM_HANDLE handle; + unsigned lockCount; + void MEM_FAR *reserved_ptr; +} MEM_POOL_ENTRY; +#endif /* MEM_POOL_ENTRY_DEFINED */ + +#ifndef MEM_POOL_STATUS_DEFINED +#define MEM_POOL_STATUS_DEFINED +/* Pool Status: returned by MemPoolWalk, MemPoolFirst, MemPoolNext */ +typedef enum +{ + MEM_POOL_OK = 1, + MEM_POOL_CORRUPT = -1, + MEM_POOL_CORRUPT_FATAL = -2, + MEM_POOL_END = 0, + MEM_POOL_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POOL_STATUS; +#endif /* MEM_POOL_STATUS_DEFINED */ + +#ifndef MEM_POINTER_STATUS_DEFINED +#define MEM_POINTER_STATUS_DEFINED +/* Pointer Status: returned by MemCheckPtr */ +typedef enum +{ + MEM_POINTER_OK = 1, + MEM_POINTER_WILD = 0, + MEM_POINTER_FREE = -1, + MEM_POINTER_STATUS_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_POINTER_STATUS; +#endif /* MEM_POINTER_STATUS_DEFINED */ + +/* Pool Info: parameter to MemPoolInfo, MemPoolFirst, MemPoolNext */ +typedef struct +{ + MEM_POOL pool; + MEM_BLOCK_TYPE type; /* disjunctive combination of block type flags */ + unsigned short blockSizeFS; + unsigned short smallBlockSize; + unsigned pageSize; + unsigned long floor; + unsigned long ceiling; + unsigned flags; + MEM_ERROR_FN errorFn; +} MEM_POOL_INFO; + +/* Flags passed to MemAlloc, MemAllocPtr, MemReAlloc, MemReAllocPtr */ +#define MEM_FIXED 0x0000u /* fixed handle-based block */ +#define MEM_ZEROINIT 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_MOVEABLE 0x0002u /* moveable handle-based block */ +#define MEM_RESIZEABLE 0x0004u /* reserve space above block */ +#define MEM_RESIZE_IN_PLACE 0x0008u /* do not move block (realloc) */ +#define MEM_NOGROW 0x0010u /* do not grow heap to satisfy request */ +#define MEM_NOEXTERNAL 0x0020u /* reserved for internal use */ +#define MEM_NOCOMPACT 0x0040u /* do not compact to satisfy request */ +#define MEM_NO_SERIALIZE 0x0080u /* do not serialize this request */ +#define MEM_HANDLEBASED 0x4000u /* for internal use */ +#define MEM_RESERVED 0x8000u /* for internal use */ + +#define MEM_UNLOCK_FAILED USHRT_MAX + +/* Flags passed to MemPoolInit, MemPoolInitFS */ +#ifndef MEM_POOL_SHARED +#define MEM_POOL_SHARED 0x0001u /* == TRUE for SH 1.5 compatibility */ +#define MEM_POOL_SERIALIZE 0x0002u /* pool used in more than one thread */ +#define MEM_POOL_VIRTUAL_LOCK 0x0004u /* pool is locked in physical memory */ +#define MEM_POOL_ZEROINIT 0x0008u /* malloc/new from pool zero-inits */ +#define MEM_POOL_REGION 0x0010u /* store pool in user-supplied region*/ +#define MEM_POOL_DEFAULT 0x8000u /* pool with default characteristics */ +#endif /* MEM_POOL_SHARED */ + +MEM_ENTRY4 MEM_POOL MemDefaultPool; + +/* Default memory pool for C malloc, C++ new (for backwards compatibility) */ +#define MEM_DEFAULT_POOL MemDefaultPool + +/* define and initialize these variables at file scope to change defaults */ +extern unsigned short MemDefaultPoolBlockSizeFS; +extern unsigned MemDefaultPoolPageSize; +extern unsigned MemDefaultPoolFlags; + +/* define SmartHeap_malloc at file scope if you + * are intentionally _NOT_ linking in the SmartHeap malloc definition + * ditto for SmartHeap operator new, and fmalloc et al. + */ +extern int SmartHeap_malloc; +extern int SmartHeap_far_malloc; +extern int SmartHeap_new; + +#define MEM_ERROR_RET ULONG_MAX + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_H) */ + + +/*** Function Prototypes ***/ + +#ifndef _SMARTHEAP_PROT +#define _SMARTHEAP_PROT + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _shAPI + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY _dbg ## name + #else + #define _shAPI(ret, name) MEM_ENTRY1 ret MEM_ENTRY name + #endif +#endif + +#ifndef _dbgARGS + #if defined(MEM_DEBUG) && !defined(SHI_NO_MEM_DEBUG) + #define _dbgARGS1 const char MEM_FAR *, int + #define _dbgARGS , _dbgARGS1 + #else + #define _dbgARGS1 void + #define _dbgARGS + #endif +#endif + + +/**** HOW TO READ SmartHeap PROTOTYPES **** + * prototypes below have the follow syntax in order to support both debug + * and non-debug APIs with single-source: + * + * _shiAPI(, )([] _dbgARGS); + * + * the above translates to a C prototype as follows: + * + * ([]); + */ + +/* Library Version */ +MEM_ENTRY1 MEM_VERSION MEM_ENTRY MemVersion(void); + +/* Library Registration */ +_shAPI(MEM_BOOL, MemRegisterTask)(_dbgARGS1); +_shAPI(MEM_BOOL, MemUnregisterTask)(_dbgARGS1); + +/* Memory Pool Functions */ +_shAPI(MEM_POOL, MemPoolInit)(unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitFS)(MEM_USHORT, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitRegion)(void MEM_FAR *, + unsigned long size, unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedShared)(const char MEM_FAR *, + unsigned long size,unsigned _dbgARGS); +_shAPI(MEM_POOL, MemPoolInitNamedSharedEx)(void MEM_FAR *addr, + unsigned pidCount, unsigned long MEM_FAR *pids, void MEM_FAR *security, + const char MEM_FAR *name, unsigned long size, unsigned flags _dbgARGS); +_shAPI(MEM_POOL, MemPoolAttachShared)(MEM_POOL, const char MEM_FAR * _dbgARGS); +_shAPI(MEM_BOOL, MemPoolFree)(MEM_POOL _dbgARGS); +MEM_POOL MEM_ENTRY MemInitDefaultPool(void); +MEM_BOOL MEM_ENTRY MemFreeDefaultPool(void); +_shAPI(unsigned, MemPoolSetPageSize)(MEM_POOL, unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetBlockSizeFS)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(MEM_BOOL, MemPoolSetSmallBlockSize)(MEM_POOL, MEM_USHORT _dbgARGS); +_shAPI(unsigned long, MemPoolSetFloor)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolSetCeiling)(MEM_POOL, unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocate)(MEM_POOL, unsigned long, + MEM_BLOCK_TYPE _dbgARGS); +_shAPI(unsigned long, MemPoolPreAllocateHandles)(MEM_POOL, + unsigned long _dbgARGS); +_shAPI(unsigned long, MemPoolShrink)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolSize)(MEM_POOL _dbgARGS); +_shAPI(unsigned long, MemPoolCount)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolInfo)(MEM_POOL, void MEM_FAR *, + MEM_POOL_INFO MEM_FAR* _dbgARGS); +_shAPI(MEM_POOL_STATUS, MemPoolFirst)(MEM_POOL_INFO MEM_FAR *, + MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolNext)(MEM_POOL_INFO MEM_FAR*,MEM_BOOL _dbgARGS); +_shAPI(MEM_POOL_STATUS,MemPoolWalk)(MEM_POOL,MEM_POOL_ENTRY MEM_FAR*_dbgARGS); +_shAPI(MEM_BOOL, MemPoolCheck)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolLock)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemPoolUnlock)(MEM_POOL _dbgARGS); + +/* Handle-based API for moveable memory within heap. */ +_shAPI(MEM_HANDLE, MemAlloc)(MEM_POOL, unsigned, unsigned long _dbgARGS); +_shAPI(MEM_HANDLE, MemReAlloc)(MEM_HANDLE,unsigned long,unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFree)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemLock)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnlock)(MEM_HANDLE _dbgARGS); +_shAPI(void MEM_FAR *, MemFix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemUnfix)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned, MemLockCount)(MEM_HANDLE _dbgARGS); +#ifndef MemFlags +#define MemFlags(mem) MemLockCount(mem) +#endif +_shAPI(MEM_BOOL, MemIsMoveable)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSize)(MEM_HANDLE _dbgARGS); +_shAPI(unsigned long, MemSizeRequested)(MEM_HANDLE _dbgARGS); +_shAPI(MEM_HANDLE, MemHandle)(void MEM_FAR * _dbgARGS); +#ifndef MEM_REFERENCE + #ifdef MEM_DEBUG + MEM_ENTRY1 void MEM_FAR * MEM_ENTRY _dbgMemReference(MEM_HANDLE, + const char MEM_FAR *, int); + #define MEM_REFERENCE(handle) \ + _dbgMemReference(handle, __FILE__, __LINE__) + #else + #define MEM_REFERENCE(handle) (*(void MEM_FAR * MEM_FAR *)handle) + #endif +#endif + +/* General Heap Allocator (returns direct pointer to memory) */ +_shAPI(void MEM_FAR*,MemAllocPtr)(MEM_POOL,unsigned long,unsigned _dbgARGS); +_shAPI(void MEM_FAR *, MemReAllocPtr)(void MEM_FAR *, unsigned long, + unsigned _dbgARGS); +_shAPI(MEM_BOOL, MemFreePtr)(void MEM_FAR * _dbgARGS); +_shAPI(unsigned long, MemSizePtr)(void MEM_FAR * _dbgARGS); +_shAPI(MEM_POINTER_STATUS, MemCheckPtr)(MEM_POOL, void MEM_FAR * _dbgARGS); + +/* Fixed-Size Allocator */ +_shAPI(void MEM_FAR *, MemAllocFS)(MEM_POOL _dbgARGS); +_shAPI(MEM_BOOL, MemFreeFS)(void MEM_FAR * _dbgARGS); + +/* Error Handling Functions */ +MEM_ENTRY1 MEM_ERROR_FN MEM_ENTRY MemSetErrorHandler(MEM_ERROR_FN); +MEM_ENTRY1 MEM_BOOL MEM_ENTRY MemDefaultErrorHandler(MEM_ERROR_INFO MEM_FAR*); +MEM_ENTRY1 void MEM_ENTRY MemErrorUnwind(void); + +#ifdef MEM_WIN32 +/* patching control */ + +#ifndef MEM_PATCHING_DEFINED +#define MEM_PATCHING_DEFINED +typedef enum +{ + MEM_PATCH_ALL = 0, + MEM_SKIP_PATCHING_THIS_DLL = 1, + MEM_DISABLE_SYSTEM_HEAP_PATCHING = 2, + MEM_DISABLE_ALL_PATCHING = 4|2|1, + MEM_PATCHING_INT_MAX = INT_MAX /* to ensure enum is full int in size */ +} MEM_PATCHING; +#endif /* MEM_PATCHING_DEFINED */ + +#ifdef _MSC_VER +__declspec(dllexport) +#endif +MEM_PATCHING MEM_ENTRY MemSetPatching(const char ***skipDLLs); + +#endif /* MEM_WIN32 */ + +/* internal routines */ +MEM_ENTRY1 MEM_BOOL MEM_ENTRY _shi_enterCriticalSection(void); +MEM_ENTRY1 void MEM_ENTRY _shi_leaveCriticalSection(void); +MEM_BOOL shi_call_new_handler_msc(size_t, MEM_BOOL); + + +/* Wrapper macros for debugging API */ +#ifndef _SHI_dbgMacros +#ifdef MEM_DEBUG +#define MemRegisterTask() _dbgMemRegisterTask(__FILE__, __LINE__) +#define MemUnregisterTask() _dbgMemUnregisterTask(__FILE__, __LINE__) +#define MemPoolInit(flags) _dbgMemPoolInit(flags, __FILE__, __LINE__) +#define MemPoolInitFS(bs, bc, f) _dbgMemPoolInitFS(bs,bc,f,__FILE__,__LINE__) +#define MemPoolInitRegion(addr, sz, f) \ + _dbgMemPoolInitRegion(addr, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedShared(nm, sz, f) \ + _dbgMemPoolInitNamedShared(nm, sz, f, __FILE__, __LINE__) +#define MemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f) \ + _dbgMemPoolInitNamedSharedEx(a, c, p, sec, nm, sz, f, __FILE__, __LINE__) +#define MemPoolAttachShared(p, n) \ + _dbgMemPoolAttachShared(p, n, __FILE__, __LINE__) +#define MemPoolFree(pool) _dbgMemPoolFree(pool, __FILE__, __LINE__) +#define MemPoolSetPageSize(p, s) _dbgMemPoolSetPageSize(p,s,__FILE__,__LINE__) +#define MemPoolSetBlockSizeFS(p, s) \ + _dbgMemPoolSetBlockSizeFS(p, s, __FILE__, __LINE__) +#define MemPoolSetSmallBlockSize(p, s) \ + _dbgMemPoolSetSmallBlockSize(p, s, __FILE__, __LINE__) +#define MemPoolSetFloor(p, f) _dbgMemPoolSetFloor(p, f, __FILE__, __LINE__) +#define MemPoolSetCeiling(p, c) _dbgMemPoolSetCeiling(p,c,__FILE__, __LINE__) +#define MemPoolPreAllocate(p,s,t) \ + _dbgMemPoolPreAllocate(p,s,t,__FILE__, __LINE__) +#define MemPoolPreAllocateHandles(p,h) \ + _dbgMemPoolPreAllocateHandles(p,h,__FILE__, __LINE__) +#define MemPoolShrink(p) _dbgMemPoolShrink(p, __FILE__, __LINE__) +#define MemPoolCheck(p) _dbgMemPoolCheck(p, __FILE__, __LINE__) +#define MemPoolWalk(p, e) _dbgMemPoolWalk(p, e, __FILE__, __LINE__) +#define MemPoolSize(p) _dbgMemPoolSize(p, __FILE__, __LINE__) +#define MemPoolCount(p) _dbgMemPoolCount(p, __FILE__, __LINE__) +#define MemPoolInfo(p,x,i) _dbgMemPoolInfo(p,x,i, __FILE__, __LINE__) +#define MemPoolFirst(i, b) _dbgMemPoolFirst(i, b, __FILE__, __LINE__) +#define MemPoolNext(i, b) _dbgMemPoolNext(i, b, __FILE__, __LINE__) +#define MemPoolLock(p) _dbgMemPoolLock(p, __FILE__, __LINE__) +#define MemPoolUnlock(p) _dbgMemPoolUnlock(p, __FILE__, __LINE__) +#define MemAlloc(p, f, s) _dbgMemAlloc(p, f, s, __FILE__, __LINE__) +#define MemReAlloc(h, s, f) _dbgMemReAlloc(h, s, f, __FILE__, __LINE__) +#define MemFree(h) _dbgMemFree(h, __FILE__, __LINE__) +#define MemLock(h) _dbgMemLock(h, __FILE__, __LINE__) +#define MemUnlock(h) _dbgMemUnlock(h, __FILE__, __LINE__) +#define MemFix(h) _dbgMemFix(h, __FILE__, __LINE__) +#define MemUnfix(h) _dbgMemUnfix(h, __FILE__, __LINE__) +#define MemSize(h) _dbgMemSize(h, __FILE__, __LINE__) +#define MemSizeRequested(h) _dbgMemSizeRequested(h, __FILE__, __LINE__) +#define MemLockCount(h) _dbgMemLockCount(h, __FILE__, __LINE__) +#define MemIsMoveable(h) _dbgMemIsMoveable(h, __FILE__, __LINE__) +#define MemHandle(p) _dbgMemHandle(p, __FILE__, __LINE__) +#define MemAllocPtr(p, s, f) _dbgMemAllocPtr(p, s, f, __FILE__, __LINE__) +#define MemReAllocPtr(p, s, f) _dbgMemReAllocPtr(p, s, f, __FILE__,__LINE__) +#define MemFreePtr(p) _dbgMemFreePtr(p, __FILE__, __LINE__) +#define MemSizePtr(p) _dbgMemSizePtr(p, __FILE__, __LINE__) +#define MemCheckPtr(p, x) _dbgMemCheckPtr(p, x, __FILE__, __LINE__) +#define MemAllocFS(p) _dbgMemAllocFS(p, __FILE__, __LINE__) +#define MemFreeFS(p) _dbgMemFreeFS(p, __FILE__, __LINE__) + +#else /* MEM_DEBUG */ + +/* MEM_DEBUG not defined: define dbgMemXXX as no-op macros + * each macro returns "success" value when MEM_DEBUG not defined + */ +#ifndef dbgMemBreakpoint +#define dbgMemBreakpoint() ((void)0) +#define dbgMemCheckAll() 1 +#define dbgMemCheckPtr(p, f, s) 1 +#define dbgMemDeferFreeing(b) 1 +#define dbgMemFormatCall(i, b, s) 0 +#define dbgMemFormatErrorInfo(i, b, s) 0 +#define dbgMemPoolDeferFreeing(p, b) 1 +#define dbgMemFreeDeferred() 1 +#define dbgMemPoolFreeDeferred(p) 1 +#define dbgMemPoolInfo(p, b) 1 +#define dbgMemPoolSetCheckFrequency(p, f) 1 +#define dbgMemPoolSetDeferQueueLen(p, b) 1 +#define dbgMemPoolSetName(p, n) 1 +#define dbgMemProtectPtr(p, f) 1 +#define dbgMemPtrInfo(p, b) 1 +#define dbgMemReallocMoves(b) 1 +#define dbgMemReportLeakage(p, c1, c2) 1 +#define dbgMemReportWrongTaskRef(b) 1 +#define dbgMemScheduleChecking(b, p, i) 1 +#define dbgMemSetCheckFrequency(f) 1 +#define dbgMemSetCheckpoint(c) 1 +#define dbgMemSetDefaultErrorOutput(x, f) 1 +#define dbgMemSetDeferQueueLen(l) 1 +#define dbgMemSetDeferSizeThreshold(s) 1 +#define dbgMemSetEntryHandler(f) 0 +#define dbgMemSetExitHandler(f) 0 +#define dbgMemSetFreeFill(c) 1 +#define dbgMemSetGuardFill(c) 1 +#define dbgMemSetGuardSize(s) 1 +#define dbgMemSetInUseFill(c) 1 +#define dbgMemSetCallstackChains(s) 1 +#define dbgMemSetStackChecking(s) 1 +#define dbgMemSetSafetyLevel(s) 1 +#define dbgMemSettingsInfo(b) 1 +#define dbgMemSuppressFreeFill(b) 1 +#define dbgMemTotalCount() 1 +#define dbgMemTotalSize() 1 +#define dbgMemWalkHeap(b) MEM_POOL_OK +#endif /* dbgMemBreakpoint */ + +#endif /* MEM_DEBUG */ +#endif /* _SHI_dbgMacros */ + +#if defined(__WATCOMC__) && defined(__SW_3S) +/* Watcom stack calling convention */ + #pragma aux MemDefaultPool "_*"; + #pragma aux MemDefaultPoolBlockSizeFS "_*"; + #pragma aux MemDefaultPoolPageSize "_*"; + #pragma aux MemDefaultPoolFlags "_*"; + #pragma aux SmartHeap_malloc "_*"; + #pragma aux SmartHeap_far_malloc "_*"; + #pragma aux SmartHeap_new "_*"; +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* !defined(_SMARTHEAP_PROT) */ From c7acbf559f6f52f06d00cd1be193b5f611529925 Mon Sep 17 00:00:00 2001 From: MS Date: Sun, 16 Jul 2023 21:37:21 -0400 Subject: [PATCH 09/10] lego1: implement MXIOINFO (#54) * Implementation of MXIOINFO. Not a 100% match, but we are very close. I don't wanna wrangle with this one any more, so I figured I would open it up for review in case anyone else has ideas. **Known problems:** - The Open function uses a `movzx` instruction on the value of parameter `fdwOpen` before pushing to OpenFile from the kernel. You can force this to appear by casting to `unsigned short`, but this disturbs the instructions for the rest of the file. To get the "best" overall match I decided to leave this out. - Flush, Advance, and Descend differ only in the order of operands on a `cmp` instruction. - This entire file is honestly pretty ugly. The main reason is all the nested ifs; we are constrained by returning a result value from each function, but only at the very end instead of bailing out with a `return`. By far the worst offender is the do/while loop in the Descend function. **Design considerations:** - We are casting the file handle from MMIOINFO to `HFILE` everywhere it is used, so I decided to just change the type. While doing that, I figured I might as well just pull out the members from the struct so we don't have `m_info` all over the place. - Without using a struct member, we have the issue of the obvious `memset` used to zero out the values in the constructor. I changed this to work on the object itself, which would not be valid in most cases, but seems fine here since we have no virtual methods. There is a lot of repeated code here, namely the call to `_llseek` to reset `m_lDiskOffset` based on the current file position. You could move this to an inline function, but maybe that's not appropriate. There are probably strides to be made on code clarity and comments (if needed or wanted) here. I'm open to any suggestions. * remove casts on read, add size assert * Use more Mx* types and param style convention * Fixing up MXIOINFO to prepare for merge. * Following feedback from @stravant and @itsmattkc, reverted back to using `MMIOINFO` struct as the class member instead of adding its values directly. (We actually gained a little on accuracy with this change.) * The memset to zero out the values in the constructor now acts on `m_info` instead of `this`. Strictly speaking we don't need the size assert any more but I decided to keep it in case we change the members later for some reason. * Casting the `hmmio` member to `HFILE` (int) or `HMMIO` (WORD) typedefs where needed. * Squelch a signed/unsigned type comparison warning --- LEGO1/mxioinfo.cpp | 422 +++++++++++++++++++++++++++++++++++++++++++-- LEGO1/mxioinfo.h | 16 +- 2 files changed, 419 insertions(+), 19 deletions(-) diff --git a/LEGO1/mxioinfo.cpp b/LEGO1/mxioinfo.cpp index 2d55ef36..c834f33d 100644 --- a/LEGO1/mxioinfo.cpp +++ b/LEGO1/mxioinfo.cpp @@ -1,9 +1,15 @@ #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)); // OFFSET: LEGO1 0x100cc800 MXIOINFO::MXIOINFO() { - memset(&m_info, 0, sizeof(MMIOINFO)); + memset(&m_info, 0, sizeof(m_info)); } // OFFSET: LEGO1 0x100cc820 @@ -13,37 +19,427 @@ MXIOINFO::~MXIOINFO() } // OFFSET: LEGO1 0x100cc830 -MxU16 MXIOINFO::Open(const char *filename, DWORD fdwOpen) +MxU16 MXIOINFO::Open(const char *p_filename, MxULong p_flags) { - return 0; + OFSTRUCT _unused; + MxU16 result = 0; + + m_info.lBufOffset = 0; + m_info.lDiskOffset = 0; + + // 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 + int 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; } // OFFSET: LEGO1 0x100cc8e0 -void MXIOINFO::Close(MxLong arg) +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; } // OFFSET: LEGO1 0x100cc930 -MxULong MXIOINFO::Read(HPSTR pch, LONG cch) +MxLong MXIOINFO::Read(void *p_buf, MxLong p_len) { - return 0; + MxLong bytes_read = 0; + + if (m_info.pchBuffer) { + + int 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; } // OFFSET: LEGO1 0x100cca00 -LONG MXIOINFO::Seek(LONG lOffset, int iOrigin) +MxLong MXIOINFO::Seek(MxLong p_offset, int p_origin) { - return 0; + 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 + int 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. + int 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; } // OFFSET: LEGO1 0x100ccbc0 -void MXIOINFO::SetBuffer(LPSTR pchBuffer, LONG cchBuffer, LONG unk) +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; +} + +// OFFSET: 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)) { + // (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; +} + +// OFFSET: 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 { + int 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; } // OFFSET: LEGO1 0x100cce60 -MxU16 MXIOINFO::Descend(LPMMCKINFO pmmcki, const MMCKINFO *pmmckiParent, UINT fuDescend) +MxU16 MXIOINFO::Descend(MMCKINFO *p_chunkInfo, const MMCKINFO *p_parentInfo, MxU16 p_descend) { - return 0; + 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) { + if (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; + + // This loop is... something + do { + 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; + } else { + if (p_chunkInfo->fccType != tmp.fccType) + continue; + } + running = FALSE; + } else { + if (p_chunkInfo->ckid != tmp.ckid) { + if (Seek((tmp.cksize&1)+tmp.cksize, SEEK_CUR) != -1) { + continue; + } else { + result = MMIOERR_CANNOTSEEK; + } + } + running = FALSE; + } + } + } + + } while (running); + + if (!result) + memcpy(p_chunkInfo, &tmp, sizeof(MMCKINFO)); + + } + + return result; } diff --git a/LEGO1/mxioinfo.h b/LEGO1/mxioinfo.h index 5ce0947a..83da930a 100644 --- a/LEGO1/mxioinfo.h +++ b/LEGO1/mxioinfo.h @@ -12,13 +12,17 @@ class MXIOINFO MXIOINFO(); __declspec(dllexport) ~MXIOINFO(); - MxU16 Open(const char *filename, DWORD fdwOpen); - void Close(MxLong arg); - LONG Seek(LONG lOffset, int iOrigin); - MxULong Read(HPSTR pch, LONG cch); - void SetBuffer(LPSTR pchBuffer, LONG cchBuffer, LONG unk); - MxU16 Descend(LPMMCKINFO pmmcki, const MMCKINFO *pmmckiParent, UINT fuDescend); + MxU16 Open(const char *, MxULong); + MxU16 Close(MxLong); + MxLong Read(void *, MxLong); + MxLong Seek(MxLong, int); + MxU16 SetBuffer(char *, MxLong, MxLong); + MxU16 Flush(MxU16); + MxU16 Advance(MxU16); + MxU16 Descend(MMCKINFO *, const MMCKINFO *, MxU16); + // NOTE: In MXIOINFO, the `hmmio` member of MMIOINFO is used like + // an HFILE (int) instead of an HMMIO (WORD). MMIOINFO m_info; }; From 9fa08b101701e2a91f023180d9d847e532fc3818 Mon Sep 17 00:00:00 2001 From: pewpew Date: Sun, 16 Jul 2023 20:38:37 -0500 Subject: [PATCH 10/10] Pretty much match MxNotificationManager::FlushPending. (#91) --- LEGO1/mxnotificationmanager.cpp | 46 +++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/LEGO1/mxnotificationmanager.cpp b/LEGO1/mxnotificationmanager.cpp index 593572bb..b7d001aa 100644 --- a/LEGO1/mxnotificationmanager.cpp +++ b/LEGO1/mxnotificationmanager.cpp @@ -111,10 +111,52 @@ void MxNotificationManager::Unregister(MxCore *p_listener) } } -// OFFSET: LEGO1 0x100ac990 STUB +// OFFSET: LEGO1 0x100ac990 void MxNotificationManager::FlushPending(MxCore *p_listener) { - // TODO + MxNotificationPtrList pending; + MxNotification *notif; + + { + MxAutoLocker lock(&m_lock); + + // Find all notifications from, and addressed to, p_listener. + if (m_sendList != NULL) { + MxNotificationPtrList::iterator it = m_sendList->begin(); + while (it != m_sendList->end()) { + notif = *it; + if ((notif->GetTarget()->GetId() == p_listener->GetId()) || + (notif->GetParam()->GetSender()) && (notif->GetParam()->GetSender()->GetId() == p_listener->GetId())) { + m_sendList->erase(it++); + pending.push_back(notif); + } + else { + it++; + } + } + } + + MxNotificationPtrList::iterator it = m_queue->begin(); + while (it != m_queue->end()) { + notif = *it; + if ((notif->GetTarget()->GetId() == p_listener->GetId()) || + (notif->GetParam()->GetSender()) && (notif->GetParam()->GetSender()->GetId() == p_listener->GetId())) { + m_queue->erase(it++); + pending.push_back(notif); + } + else { + it++; + } + } + } + + // Deliver those notifications. + while (pending.size() != 0) { + notif = pending.front(); + pending.pop_front(); + notif->GetTarget()->Notify(*notif->GetParam()); + delete notif; + } } // OFFSET: LEGO1 0x100ac6c0