From 9ba5b14db66fa73ec59bc8f2fdb3c0ad6a76484c Mon Sep 17 00:00:00 2001 From: elasota Date: Tue, 27 Apr 2021 00:14:16 -0400 Subject: [PATCH] Add HouseTool --- Aerofoil.sln | 7 + HouseTool/HouseTool.cpp | 1813 +++++++++++++++++++++++++++ HouseTool/HouseTool.vcxproj | 101 ++ HouseTool/HouseTool.vcxproj.filters | 25 + 4 files changed, 1946 insertions(+) create mode 100644 HouseTool/HouseTool.cpp create mode 100644 HouseTool/HouseTool.vcxproj create mode 100644 HouseTool/HouseTool.vcxproj.filters diff --git a/Aerofoil.sln b/Aerofoil.sln index 29fe237..f40e54d 100644 --- a/Aerofoil.sln +++ b/Aerofoil.sln @@ -49,6 +49,7 @@ Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "ReleasePackageInstaller", " {B852D549-4020-4477-8BFB-E199FF78B047} = {B852D549-4020-4477-8BFB-E199FF78B047} {2FF15659-5C72-48B8-B55B-3C658E4125B5} = {2FF15659-5C72-48B8-B55B-3C658E4125B5} {3B7FD18D-7A50-4DF5-AC25-543E539BFACE} = {3B7FD18D-7A50-4DF5-AC25-543E539BFACE} + {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67} = {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67} {36DAF5FA-6ADB-4F20-9810-1610DE0AE653} = {36DAF5FA-6ADB-4F20-9810-1610DE0AE653} EndProjectSection EndProject @@ -68,6 +69,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GenerateFonts", "GenerateFo EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin2h", "bin2h\bin2h.vcxproj", "{D045F28D-F245-44DD-B576-CC91BF3BE6E9}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "HouseTool", "HouseTool\HouseTool.vcxproj", "{B31BFF9D-2D14-4B1A-A625-8348CC3D8D67}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -188,6 +191,10 @@ Global {D045F28D-F245-44DD-B576-CC91BF3BE6E9}.Debug|x64.Build.0 = Debug|x64 {D045F28D-F245-44DD-B576-CC91BF3BE6E9}.Release|x64.ActiveCfg = Release|x64 {D045F28D-F245-44DD-B576-CC91BF3BE6E9}.Release|x64.Build.0 = Release|x64 + {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67}.Debug|x64.ActiveCfg = Debug|x64 + {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67}.Debug|x64.Build.0 = Debug|x64 + {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67}.Release|x64.ActiveCfg = Release|x64 + {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/HouseTool/HouseTool.cpp b/HouseTool/HouseTool.cpp new file mode 100644 index 0000000..bb052f7 --- /dev/null +++ b/HouseTool/HouseTool.cpp @@ -0,0 +1,1813 @@ +#include +#include "PLCore.h" +#include "PLBigEndian.h" +#include "MacRomanConversion.h" +#include "UTF8.h" +#include "WindowsUnicodeToolShim.h" + +#include + +typedef uint8_t Boolean; + +#define kMaxScores 10 +#define kMaxRoomObs 24 +#define kNumTiles 8 + +// Object types + +#define kFloorVent 0x01 // Blowers +#define kCeilingVent 0x02 +#define kFloorBlower 0x03 +#define kCeilingBlower 0x04 +#define kSewerGrate 0x05 +#define kLeftFan 0x06 +#define kRightFan 0x07 +#define kTaper 0x08 +#define kCandle 0x09 +#define kStubby 0x0A +#define kTiki 0x0B +#define kBBQ 0x0C +#define kInvisBlower 0x0D +#define kGrecoVent 0x0E +#define kSewerBlower 0x0F +#define kLiftArea 0x10 + +#define kTable 0x11 // Furniture +#define kShelf 0x12 +#define kCabinet 0x13 +#define kFilingCabinet 0x14 +#define kWasteBasket 0x15 +#define kMilkCrate 0x16 +#define kCounter 0x17 +#define kDresser 0x18 +#define kDeckTable 0x19 +#define kStool 0x1A +#define kTrunk 0x1B +#define kInvisObstacle 0x1C +#define kManhole 0x1D +#define kBooks 0x1E +#define kInvisBounce 0x1F + +#define kRedClock 0x21 // Prizes +#define kBlueClock 0x22 +#define kYellowClock 0x23 +#define kCuckoo 0x24 +#define kPaper 0x25 +#define kBattery 0x26 +#define kBands 0x27 +#define kGreaseRt 0x28 +#define kGreaseLf 0x29 +#define kFoil 0x2A +#define kInvisBonus 0x2B +#define kStar 0x2C +#define kSparkle 0x2D +#define kHelium 0x2E +#define kSlider 0x2F + +#define kUpStairs 0x31 // Transport +#define kDownStairs 0x32 +#define kMailboxLf 0x33 +#define kMailboxRt 0x34 +#define kFloorTrans 0x35 +#define kCeilingTrans 0x36 +#define kDoorInLf 0x37 +#define kDoorInRt 0x38 +#define kDoorExRt 0x39 +#define kDoorExLf 0x3A +#define kWindowInLf 0x3B +#define kWindowInRt 0x3C +#define kWindowExRt 0x3D +#define kWindowExLf 0x3E +#define kInvisTrans 0x3F +#define kDeluxeTrans 0x40 + +#define kLightSwitch 0x41 // Switches +#define kMachineSwitch 0x42 +#define kThermostat 0x43 +#define kPowerSwitch 0x44 +#define kKnifeSwitch 0x45 +#define kInvisSwitch 0x46 +#define kTrigger 0x47 +#define kLgTrigger 0x48 +#define kSoundTrigger 0x49 + +#define kCeilingLight 0x51 // Lights +#define kLightBulb 0x52 +#define kTableLamp 0x53 +#define kHipLamp 0x54 +#define kDecoLamp 0x55 +#define kFlourescent 0x56 +#define kTrackLight 0x57 +#define kInvisLight 0x58 + +#define kShredder 0x61 // Appliances +#define kToaster 0x62 +#define kMacPlus 0x63 +#define kGuitar 0x64 +#define kTV 0x65 +#define kCoffee 0x66 +#define kOutlet 0x67 +#define kVCR 0x68 +#define kStereo 0x69 +#define kMicrowave 0x6A +#define kCinderBlock 0x6B +#define kFlowerBox 0x6C +#define kCDs 0x6D +#define kCustomPict 0x6E + +#define kBalloon 0x71 // Enemies +#define kCopterLf 0x72 +#define kCopterRt 0x73 +#define kDartLf 0x74 +#define kDartRt 0x75 +#define kBall 0x76 +#define kDrip 0x77 +#define kFish 0x78 +#define kCobweb 0x79 + +#define kOzma 0x81 // Clutter +#define kMirror 0x82 +#define kMousehole 0x83 +#define kFireplace 0x84 +#define kFlower 0x85 +#define kWallWindow 0x86 +#define kBear 0x87 +#define kCalendar 0x88 +#define kVase1 0x89 +#define kVase2 0x8A +#define kBulletin 0x8B +#define kCloud 0x8C +#define kFaucet 0x8D +#define kRug 0x8E +#define kChimes 0x8F + + +struct EnumDef +{ + int m_value; + const char *m_name; +}; + +struct Bool8 +{ + uint8_t m_value; +}; + +template +struct StaticArray +{ + static const int kSize = TSize; + + T m_data[TSize]; +}; + + +template +struct PascalStr +{ + static const int kSize = TSize; + + uint8_t m_length; + uint8_t m_chars[TSize]; +}; + +typedef PascalStr<15> PStr15_t; +typedef PascalStr<27> PStr27_t; +typedef PascalStr<31> PStr31_t; +typedef PascalStr<255> PStr255_t; + + + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t distance; // 2 + Bool8 initial; // 1 + Bool8 state; // 1 F. lf. dn. rt. up + uint8_t vector; // 1 | x | x | x | x | 8 | 4 | 2 | 1 | + uint8_t tall; // 1 +} blowerType; // total = 10 + +typedef struct +{ + BERect bounds; // 8 + BEInt16_t pict; // 2 +} furnitureType; // total = 10 + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t length; // 2 grease spill + BEInt16_t points; // 2 invis bonus + Bool8 state; // 1 + Bool8 initial; // 1 +} bonusType; // total = 10 + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t tall; // 2 invis transport + BEInt16_t where; // 2 + uint8_t who; // 1 + uint8_t wide; // 1 +} transportType; // total = 10 + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t delay; // 2 + BEInt16_t where; // 2 + uint8_t who; // 1 + uint8_t type; // 1 +} switchType; // total = 10 + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t length; // 2 + uint8_t byte0; // 1 + uint8_t byte1; // 1 + Bool8 initial; // 1 + Bool8 state; // 1 +} lightType; // total = 10 + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t height; // 2 toaster, pict ID + uint8_t byte0; // 1 + uint8_t delay; // 1 + Bool8 initial; // 1 + Bool8 state; // 1 +} applianceType; // total = 10 + +typedef struct +{ + BEPoint topLeft; // 4 + BEInt16_t length; // 2 + uint8_t delay; // 1 + uint8_t byte0; // 1 + Bool8 initial; // 1 + Bool8 state; // 1 +} enemyType; // total = 10 + +typedef struct +{ + BERect bounds; // 8 + BEInt16_t pict; // 2 +} clutterType; // total = 10 + +struct objectType +{ + union u + { + blowerType a; + furnitureType b; + bonusType c; + transportType d; + switchType e; + lightType f; + applianceType g; + enemyType h; + clutterType i; + StaticArray pad; + + u(); + u(const u &other); + ~u(); + }; + + BEInt16_t what; // 2 + u data; // 10 +}; // total = 12 + +objectType::u::u() +{ + static_assert(sizeof(*this) == 10, "Wrong size"); +} + +objectType::u::~u() +{ +} + +objectType::u::u(const u &other) +{ + memcpy(this, &other, sizeof(*this)); +} + +typedef objectType *objectPtr; + +typedef struct +{ + PStr31_t banner; // 32 = 32 + StaticArray names; // 16 * 10 = 160 + StaticArray scores; // 4 * 10 = 40 + StaticArray timeStamps; // 4 * 10 = 40 + StaticArray levels; // 2 * 10 = 20 +} scoresType; // total = 292 + +typedef struct +{ + BEInt16_t version; // 2 + BEInt16_t wasStarsLeft; // 2 + BEUInt32_t timeStamp; // 4 + BEPoint where; // 4 + BEInt32_t score; // 4 + BEInt32_t unusedLong; // 4 + BEInt32_t unusedLong2; // 4 + BEInt16_t energy; // 2 + BEInt16_t bands; // 2 + BEInt16_t roomNumber; // 2 + BEInt16_t gliderState; // 2 + BEInt16_t numGliders; // 2 + BEInt16_t foil; // 2 + BEInt16_t unusedShort; // 2 + Bool8 facing; // 1 + Bool8 showFoil; // 1 +} gameType; // total = 40 + +typedef struct +{ + BEInt16_t unusedShort; // 2 + uint8_t unusedByte; // 1 + Bool8 visited; // 1 + objectType objects[kMaxRoomObs]; // 24 * 12 +} savedRoom, *saveRoomPtr; // total = 292 + +typedef struct +{ + PStr27_t name; // 28 + BEInt16_t bounds; // 2 + uint8_t leftStart; // 1 + uint8_t rightStart; // 1 + uint8_t unusedByte; // 1 + Bool8 visited; // 1 + BEInt16_t background; // 2 + StaticArray tiles; // 2 * 8 + BEInt16_t floor, suite; // 2 + 2 + BEInt16_t openings; // 2 + BEInt16_t numObjects; // 2 + StaticArray objects; // 24 * 12 +} roomType, *roomPtr; // total = 348 + +struct houseType +{ + BEInt16_t version; // 2 + BEInt16_t unusedShort; // 2 + BEInt32_t timeStamp; // 4 + BEInt32_t flags; // 4 (bit 0 = wardBit) + BEPoint initial; // 4 + PStr255_t banner; // 256 + PStr255_t trailer; // 256 + scoresType highScores; // 292 + gameType savedGame_Unused; // 40 + Bool8 hasGame; // 1 + Bool8 unusedBoolean; // 1 + BEInt16_t firstRoom; // 2 + BEInt16_t nRooms; // 2 + + static const size_t kBinaryDataSize = 866; +}; + +static const size_t houseSize = sizeof(houseType); + +#define ENUM_VALUE_DEF(k) { k, #k } + +EnumDef g_objectTypeEnum[] = +{ + { -1, "kObjectIsEmpty" }, + ENUM_VALUE_DEF(kFloorVent), + ENUM_VALUE_DEF(kCeilingVent), + ENUM_VALUE_DEF(kFloorBlower), + ENUM_VALUE_DEF(kCeilingBlower), + ENUM_VALUE_DEF(kSewerGrate), + ENUM_VALUE_DEF(kLeftFan), + ENUM_VALUE_DEF(kRightFan), + ENUM_VALUE_DEF(kTaper), + ENUM_VALUE_DEF(kCandle), + ENUM_VALUE_DEF(kStubby), + ENUM_VALUE_DEF(kTiki), + ENUM_VALUE_DEF(kBBQ), + ENUM_VALUE_DEF(kInvisBlower), + ENUM_VALUE_DEF(kGrecoVent), + ENUM_VALUE_DEF(kSewerBlower), + ENUM_VALUE_DEF(kLiftArea), + ENUM_VALUE_DEF(kTable), + ENUM_VALUE_DEF(kShelf), + ENUM_VALUE_DEF(kCabinet), + ENUM_VALUE_DEF(kFilingCabinet), + ENUM_VALUE_DEF(kWasteBasket), + ENUM_VALUE_DEF(kMilkCrate), + ENUM_VALUE_DEF(kCounter), + ENUM_VALUE_DEF(kDresser), + ENUM_VALUE_DEF(kDeckTable), + ENUM_VALUE_DEF(kStool), + ENUM_VALUE_DEF(kTrunk), + ENUM_VALUE_DEF(kInvisObstacle), + ENUM_VALUE_DEF(kManhole), + ENUM_VALUE_DEF(kBooks), + ENUM_VALUE_DEF(kInvisBounce), + ENUM_VALUE_DEF(kRedClock), + ENUM_VALUE_DEF(kBlueClock), + ENUM_VALUE_DEF(kYellowClock), + ENUM_VALUE_DEF(kCuckoo), + ENUM_VALUE_DEF(kPaper), + ENUM_VALUE_DEF(kBattery), + ENUM_VALUE_DEF(kBands), + ENUM_VALUE_DEF(kGreaseRt), + ENUM_VALUE_DEF(kGreaseLf), + ENUM_VALUE_DEF(kFoil), + ENUM_VALUE_DEF(kInvisBonus), + ENUM_VALUE_DEF(kStar), + ENUM_VALUE_DEF(kSparkle), + ENUM_VALUE_DEF(kHelium), + ENUM_VALUE_DEF(kSlider), + ENUM_VALUE_DEF(kUpStairs), + ENUM_VALUE_DEF(kDownStairs), + ENUM_VALUE_DEF(kMailboxLf), + ENUM_VALUE_DEF(kMailboxRt), + ENUM_VALUE_DEF(kFloorTrans), + ENUM_VALUE_DEF(kCeilingTrans), + ENUM_VALUE_DEF(kDoorInLf), + ENUM_VALUE_DEF(kDoorInRt), + ENUM_VALUE_DEF(kDoorExRt), + ENUM_VALUE_DEF(kDoorExLf), + ENUM_VALUE_DEF(kWindowInLf), + ENUM_VALUE_DEF(kWindowInRt), + ENUM_VALUE_DEF(kWindowExRt), + ENUM_VALUE_DEF(kWindowExLf), + ENUM_VALUE_DEF(kInvisTrans), + ENUM_VALUE_DEF(kDeluxeTrans), + ENUM_VALUE_DEF(kLightSwitch), + ENUM_VALUE_DEF(kMachineSwitch), + ENUM_VALUE_DEF(kThermostat), + ENUM_VALUE_DEF(kPowerSwitch), + ENUM_VALUE_DEF(kKnifeSwitch), + ENUM_VALUE_DEF(kInvisSwitch), + ENUM_VALUE_DEF(kTrigger), + ENUM_VALUE_DEF(kLgTrigger), + ENUM_VALUE_DEF(kSoundTrigger), + ENUM_VALUE_DEF(kCeilingLight), + ENUM_VALUE_DEF(kLightBulb), + ENUM_VALUE_DEF(kTableLamp), + ENUM_VALUE_DEF(kHipLamp), + ENUM_VALUE_DEF(kDecoLamp), + ENUM_VALUE_DEF(kFlourescent), + ENUM_VALUE_DEF(kTrackLight), + ENUM_VALUE_DEF(kInvisLight), + ENUM_VALUE_DEF(kShredder), + ENUM_VALUE_DEF(kToaster), + ENUM_VALUE_DEF(kMacPlus), + ENUM_VALUE_DEF(kGuitar), + ENUM_VALUE_DEF(kTV), + ENUM_VALUE_DEF(kCoffee), + ENUM_VALUE_DEF(kOutlet), + ENUM_VALUE_DEF(kVCR), + ENUM_VALUE_DEF(kStereo), + ENUM_VALUE_DEF(kMicrowave), + ENUM_VALUE_DEF(kCinderBlock), + ENUM_VALUE_DEF(kFlowerBox), + ENUM_VALUE_DEF(kCDs), + ENUM_VALUE_DEF(kCustomPict), + ENUM_VALUE_DEF(kBalloon), + ENUM_VALUE_DEF(kCopterLf), + ENUM_VALUE_DEF(kCopterRt), + ENUM_VALUE_DEF(kDartLf), + ENUM_VALUE_DEF(kDartRt), + ENUM_VALUE_DEF(kBall), + ENUM_VALUE_DEF(kDrip), + ENUM_VALUE_DEF(kFish), + ENUM_VALUE_DEF(kCobweb), + ENUM_VALUE_DEF(kOzma), + ENUM_VALUE_DEF(kMirror), + ENUM_VALUE_DEF(kMousehole), + ENUM_VALUE_DEF(kFireplace), + ENUM_VALUE_DEF(kFlower), + ENUM_VALUE_DEF(kWallWindow), + ENUM_VALUE_DEF(kBear), + ENUM_VALUE_DEF(kCalendar), + ENUM_VALUE_DEF(kVase1), + ENUM_VALUE_DEF(kVase2), + ENUM_VALUE_DEF(kBulletin), + ENUM_VALUE_DEF(kCloud), + ENUM_VALUE_DEF(kFaucet), + ENUM_VALUE_DEF(kRug), + ENUM_VALUE_DEF(kChimes), +}; + +const size_t g_objectTypeEnumSize = sizeof(g_objectTypeEnum) / sizeof(g_objectTypeEnum[0]); + + +struct IDataVisitor +{ + virtual IDataVisitor *EnterIndex(int index) = 0; + virtual IDataVisitor *EnterNamed(const char *name) = 0; + virtual void Exit() = 0; + + virtual void VisitLPStr(uint8_t &length, uint8_t *chars, int capacity) = 0; + virtual void VisitInt32(int32_t &v) = 0; + virtual void VisitUInt32(uint32_t &v) = 0; + virtual void VisitInt16(int16_t &v) = 0; + virtual void VisitBool8(uint8_t &v) = 0; + virtual void VisitByte(uint8_t &v) = 0; + virtual bool VisitEnum(const EnumDef *enumDefs, size_t numDefs, int &v) = 0; + + virtual bool VisitStaticCapacity(size_t size) = 0; + virtual void VisitDynamicCapacity(size_t &size) = 0; +}; + +bool VisitEnum(const EnumDef *enumDefs, size_t numDefs, IDataVisitor *visitor); + +void Visit(roomType &v, IDataVisitor *visitor); +void Visit(objectType &v, IDataVisitor *visitor); +void Visit(blowerType &v, IDataVisitor *visitor); +void Visit(furnitureType &v, IDataVisitor *visitor); +void Visit(bonusType &v, IDataVisitor *visitor); +void Visit(transportType &v, IDataVisitor *visitor); +void Visit(switchType &v, IDataVisitor *visitor); +void Visit(lightType &v, IDataVisitor *visitor); +void Visit(applianceType &v, IDataVisitor *visitor); +void Visit(enemyType &v, IDataVisitor *visitor); +void Visit(clutterType &v, IDataVisitor *visitor); +void Visit(scoresType &v, IDataVisitor *visitor); +void Visit(gameType &v, IDataVisitor *visitor); +void Visit(Bool8 &v, IDataVisitor *visitor); +void Visit(uint8_t &v, IDataVisitor *visitor); +void Visit(BEInt16_t &v, IDataVisitor *visitor); +void Visit(BEInt32_t &v, IDataVisitor *visitor); +void Visit(BEUInt32_t &v, IDataVisitor *visitor); +void Visit(BEPoint &v, IDataVisitor *visitor); +void Visit(BERect &v, IDataVisitor *visitor); + +template +void Visit(PascalStr &pstr, IDataVisitor *visitor) +{ + visitor->VisitLPStr(pstr.m_length, pstr.m_chars, TSize); +} + +template +void Visit(StaticArray &arr, IDataVisitor *visitor) +{ + if (!visitor->VisitStaticCapacity(TSize)) + return; + + for (int i = 0; i < TSize; i++) + { + IDataVisitor *subscriptVisitor = visitor->EnterIndex(i); + if (subscriptVisitor) + { + Visit(arr.m_data[i], visitor); + subscriptVisitor->Exit(); + } + } +} + +template +void VisitField(const char *subscriptName, T &subscript, IDataVisitor *visitor) +{ + IDataVisitor *subscriptVisitor = visitor->EnterNamed(subscriptName); + if (subscriptVisitor) + { + Visit(subscript, visitor); + subscriptVisitor->Exit(); + } +} + +template +void VisitArray(T *arr, int size, IDataVisitor *visitor) +{ + if (!visitor->VisitStaticCapacity(static_cast(size))) + return; + + for (int i = 0; i < size; i++) + { + IDataVisitor *subscriptVisitor = visitor->EnterIndex(i); + if (subscriptVisitor) + { + Visit(arr[i], visitor); + subscriptVisitor->Exit(); + } + } +} + + +bool VisitEnum(const EnumDef *enumDefs, size_t numDefs, int &v, IDataVisitor *visitor) +{ + return visitor->VisitEnum(enumDefs, numDefs, v); +} + +void Visit(houseType &house, std::vector &rooms, IDataVisitor *visitor) +{ + VisitField("version", house.version, visitor); + VisitField("unusedShort", house.unusedShort, visitor); + VisitField("timeStamp", house.timeStamp, visitor); + VisitField("flags", house.flags, visitor); + VisitField("initial", house.initial, visitor); + VisitField("banner", house.banner, visitor); + VisitField("trailer", house.trailer, visitor); + VisitField("highScores", house.highScores, visitor); + VisitField("savedGame", house.savedGame_Unused, visitor); + VisitField("hasGame", house.hasGame, visitor); + VisitField("unusedBoolean", house.unusedBoolean, visitor); + VisitField("firstRoom", house.firstRoom, visitor); + VisitField("nRooms", house.nRooms, visitor); + + IDataVisitor *roomsSubscript = visitor->EnterNamed("rooms"); + if (roomsSubscript) + { + size_t size = rooms.size(); + roomsSubscript->VisitDynamicCapacity(size); + + if (size > 0x7fff) + size = 0x7fff; + + if (size < rooms.size()) + rooms.resize(size); + else if (size > rooms.size()) + { + roomType emptyRoom; + memset(&emptyRoom, 0, sizeof(emptyRoom)); + + rooms.reserve(size); + while (size > rooms.size()) + rooms.push_back(emptyRoom); + } + + house.nRooms = static_cast(size); + + for (size_t i = 0; i < size; i++) + { + IDataVisitor *roomSubscript = roomsSubscript->EnterIndex(static_cast(i)); + if (roomSubscript) + { + Visit(rooms[i], roomSubscript); + roomSubscript->Exit(); + } + } + + roomsSubscript->Exit(); + } +} + +void Visit(blowerType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("distance", v.distance, visitor); + VisitField("initial", v.initial, visitor); + VisitField("state", v.state, visitor); + VisitField("vector", v.vector, visitor); + VisitField("tall", v.tall, visitor); +} + +void Visit(furnitureType &v, IDataVisitor *visitor) +{ + VisitField("bounds", v.bounds, visitor); + VisitField("pict", v.pict, visitor); +} + +void Visit(bonusType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("length", v.length, visitor); + VisitField("points", v.points, visitor); + VisitField("state", v.state, visitor); + VisitField("initial", v.initial, visitor); +} + +void Visit(transportType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("tall", v.tall, visitor); + VisitField("where", v.where, visitor); + VisitField("who", v.who, visitor); + VisitField("wide", v.wide, visitor); +} + +void Visit(switchType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("delay", v.delay, visitor); + VisitField("where", v.where, visitor); + VisitField("who", v.who, visitor); + VisitField("type", v.type, visitor); +} + +void Visit(lightType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("length", v.length, visitor); + VisitField("byte0", v.byte0, visitor); + VisitField("byte1", v.byte1, visitor); + VisitField("initial", v.initial, visitor); + VisitField("state", v.state, visitor); +} + +void Visit(applianceType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("height", v.height, visitor); + VisitField("byte0", v.byte0, visitor); + VisitField("delay", v.delay, visitor); + VisitField("initial", v.initial, visitor); + VisitField("state", v.state, visitor); +} + +void Visit(enemyType &v, IDataVisitor *visitor) +{ + VisitField("topLeft", v.topLeft, visitor); + VisitField("length", v.length, visitor); + VisitField("delay", v.delay, visitor); + VisitField("byte0", v.byte0, visitor); + VisitField("initial", v.initial, visitor); + VisitField("state", v.state, visitor); +} + +void Visit(clutterType &v, IDataVisitor *visitor) +{ + VisitField("bounds", v.bounds, visitor); + VisitField("pict", v.pict, visitor); +} + +void Visit(objectType &v, IDataVisitor *visitor) +{ + IDataVisitor *whatVisitor = visitor->EnterNamed("what"); + if (whatVisitor) + { + int ev = v.what; + if (!VisitEnum(g_objectTypeEnum, g_objectTypeEnumSize, ev, visitor)) + Visit(v.what, visitor); + whatVisitor->Exit(); + } + + switch (static_cast(v.what)) + { + default: + //VisitField("pad", v.data.pad, visitor); + break; + + case kFloorVent: + case kCeilingVent: + case kFloorBlower: + case kCeilingBlower: + case kSewerGrate: + case kLeftFan: + case kRightFan: + case kTaper: + case kCandle: + case kStubby: + case kTiki: + case kBBQ: + case kInvisBlower: + case kGrecoVent: + case kSewerBlower: + case kLiftArea: + Visit(v.data.a, visitor); + break; + + case kTable: + case kShelf: + case kCabinet: + case kFilingCabinet: + case kWasteBasket: + case kMilkCrate: + case kCounter: + case kDresser: + case kDeckTable: + case kStool: + case kTrunk: + case kInvisObstacle: + case kManhole: + case kBooks: + case kInvisBounce: + Visit(v.data.b, visitor); + break; + + case kRedClock: + case kBlueClock: + case kYellowClock: + case kCuckoo: + case kPaper: + case kBattery: + case kBands: + case kGreaseRt: + case kGreaseLf: + case kFoil: + case kInvisBonus: + case kStar: + case kSparkle: + case kHelium: + case kSlider: + Visit(v.data.c, visitor); + break; + + case kUpStairs: + case kDownStairs: + case kMailboxLf: + case kMailboxRt: + case kFloorTrans: + case kCeilingTrans: + case kDoorInLf: + case kDoorInRt: + case kDoorExRt: + case kDoorExLf: + case kWindowInLf: + case kWindowInRt: + case kWindowExRt: + case kWindowExLf: + case kInvisTrans: + case kDeluxeTrans: + Visit(v.data.d, visitor); + break; + + case kLightSwitch: + case kMachineSwitch: + case kThermostat: + case kPowerSwitch: + case kKnifeSwitch: + case kInvisSwitch: + case kTrigger: + case kLgTrigger: + case kSoundTrigger: + Visit(v.data.e, visitor); + break; + + case kCeilingLight: + case kLightBulb: + case kTableLamp: + case kHipLamp: + case kDecoLamp: + case kFlourescent: + case kTrackLight: + case kInvisLight: + Visit(v.data.f, visitor); + break; + + case kShredder: + case kToaster: + case kMacPlus: + case kGuitar: + case kTV: + case kCoffee: + case kOutlet: + case kVCR: + case kStereo: + case kMicrowave: + case kCinderBlock: + case kFlowerBox: + case kCDs: + case kCustomPict: + Visit(v.data.g, visitor); + break; + + case kBalloon: + case kCopterLf: + case kCopterRt: + case kDartLf: + case kDartRt: + case kBall: + case kDrip: + case kFish: + case kCobweb: + Visit(v.data.h, visitor); + break; + + case kOzma: + case kMirror: + case kMousehole: + case kFireplace: + case kFlower: + case kWallWindow: + case kBear: + case kCalendar: + case kVase1: + case kVase2: + case kBulletin: + case kCloud: + case kFaucet: + case kRug: + case kChimes: + Visit(v.data.i, visitor); + break; + } +} + +void Visit(roomType &v, IDataVisitor *visitor) +{ + VisitField("name", v.name, visitor); + VisitField("bounds", v.bounds, visitor); + VisitField("leftStart", v.leftStart, visitor); + VisitField("rightStart", v.rightStart, visitor); + VisitField("unusedByte", v.unusedByte, visitor); + VisitField("visited", v.visited, visitor); + VisitField("background", v.background, visitor); + VisitField("tiles", v.tiles, visitor); + VisitField("floor", v.floor, visitor); + VisitField("suite", v.suite, visitor); + VisitField("openings", v.openings, visitor); + VisitField("numObjects", v.numObjects, visitor); + VisitField("objects", v.objects, visitor); +} + +void Visit(scoresType &v, IDataVisitor *visitor) +{ + VisitField("banner", v.banner, visitor); + VisitField("names", v.names, visitor); + VisitField("scores", v.scores, visitor); + VisitField("timeStamps", v.timeStamps, visitor); + VisitField("levels", v.levels, visitor); +} + +void Visit(gameType &v, IDataVisitor *visitor) +{ + VisitField("version", v.version, visitor); + VisitField("starsLeft", v.wasStarsLeft, visitor); + VisitField("timeStamp", v.timeStamp, visitor); + VisitField("where", v.where, visitor); + VisitField("score", v.score, visitor); + VisitField("unusedLong", v.unusedLong, visitor); + VisitField("unusedLong2", v.unusedLong2, visitor); + VisitField("energy", v.energy, visitor); + VisitField("bands", v.bands, visitor); + VisitField("roomNumber", v.roomNumber, visitor); + VisitField("gliderState", v.gliderState, visitor); + VisitField("numGliders", v.numGliders, visitor); + VisitField("foil", v.foil, visitor); + VisitField("unusedShort", v.unusedShort, visitor); + VisitField("facing", v.facing, visitor); + VisitField("showFoil", v.showFoil, visitor); +} + +void Visit(Bool8 &v, IDataVisitor *visitor) +{ + visitor->VisitBool8(v.m_value); +} + +void Visit(uint8_t &v, IDataVisitor *visitor) +{ + visitor->VisitByte(v); +} + +void Visit(BEInt16_t &v, IDataVisitor *visitor) +{ + int16_t vi = v; + visitor->VisitInt16(vi); + v = vi; +} + +void Visit(BEInt32_t &v, IDataVisitor *visitor) +{ + int32_t vi = v; + visitor->VisitInt32(vi); + v = vi; +} + +void Visit(BEUInt32_t &v, IDataVisitor *visitor) +{ + uint32_t vi = v; + visitor->VisitUInt32(vi); + v = vi; +} + +void Visit(BEPoint &v, IDataVisitor *visitor) +{ + VisitField("h", v.h, visitor); + VisitField("v", v.v, visitor); +} + +void Visit(BERect &v, IDataVisitor *visitor) +{ + VisitField("top", v.top, visitor); + VisitField("left", v.left, visitor); + VisitField("bottom", v.bottom, visitor); + VisitField("right", v.right, visitor); +} + +int PrintUsage() +{ + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "HouseTool decompile \n"); + fprintf(stderr, "HouseTool patch \n"); + return -1; +} + +bool ReadHouseFromPath(const char *path, houseType &house, std::vector &rooms) +{ + FILE *f = fopen_utf8(path, "rb"); + if (!f) + return false; + + if (fread(&house, 1, houseType::kBinaryDataSize, f) != houseType::kBinaryDataSize) + { + fclose(f); + return false; + } + + int16_t nRooms = house.nRooms; + if (nRooms < 0) + { + fclose(f); + return false; + } + + rooms.resize(nRooms); + + if (nRooms > 0) + { + if (fread(&rooms[0], 1, sizeof(roomType) * nRooms, f) != sizeof(roomType) * nRooms) + { + rooms.clear(); + fclose(f); + return false; + } + } + + fclose(f); + return true; +} + + +class PatchVisitor final : public IDataVisitor +{ +public: + PatchVisitor(const char *scope, const char *replacementValue); + + IDataVisitor *EnterIndex(int index) override; + IDataVisitor *EnterNamed(const char *name) override; + void Exit() override; + + void VisitLPStr(uint8_t &length, uint8_t *chars, int capacity) override; + void VisitInt32(int32_t &v) override; + void VisitUInt32(uint32_t &v) override; + void VisitInt16(int16_t &v) override; + void VisitBool8(uint8_t &v) override; + void VisitByte(uint8_t &v) override; + bool VisitEnum(const EnumDef *enumDefs, size_t numDefs, int &v) override; + + bool VisitStaticCapacity(size_t size) override; + void VisitDynamicCapacity(size_t &size) override; + + bool PatchedOK() const; + +private: + static bool DecodeInteger(const std::string &scopeStr, size_t startPos, int &outInteger, size_t &outEndPos); + static bool DecodeQuotedString(const std::string &scopeStr, size_t startPos, std::string &outStr, size_t &outEndPos); + + std::string m_scope; + std::string m_nextScope; + int m_scopeInteger; + bool m_nextScopeIsInteger; + const char *m_replacementValue; + + void EnterScope(); + bool TryEnterScope(); + + bool m_isDone; + bool m_haveScope; + bool m_patchedOK; +}; + +PatchVisitor::PatchVisitor(const char *scope, const char *replacementValue) + : m_scopeInteger(0) + , m_nextScopeIsInteger(false) + , m_replacementValue(replacementValue) + , m_nextScope(scope) + , m_isDone(false) + , m_haveScope(true) + , m_patchedOK(false) +{ + EnterScope(); +} + +IDataVisitor *PatchVisitor::EnterIndex(int index) +{ + if (m_isDone || !m_haveScope || !m_nextScopeIsInteger) + return nullptr; + + if (m_scopeInteger == index) + { + EnterScope(); + return this; + } + + return nullptr; +} + +IDataVisitor *PatchVisitor::EnterNamed(const char *name) +{ + if (m_isDone || !m_haveScope || m_nextScopeIsInteger) + return nullptr; + + if (m_scope == name) + { + EnterScope(); + return this; + } + + return nullptr; +} + +void PatchVisitor::Exit() +{ + m_isDone = true; +} + +void PatchVisitor::VisitLPStr(uint8_t &length, uint8_t *chars, int capacity) +{ + if (m_isDone || m_haveScope) + return; + + const uint8_t *replacementUTF8 = reinterpret_cast(m_replacementValue); + size_t rLen = strlen(m_replacementValue); + + length = 0; + while (rLen > 0) + { + uint32_t codePoint = 0; + size_t charsDigested = 0; + if (!PortabilityLayer::UTF8Processor::DecodeCodePoint(replacementUTF8, rLen, charsDigested, codePoint)) + break; + + rLen -= charsDigested; + replacementUTF8 += charsDigested; + + uint8_t macRomanChar = 0; + if (codePoint > 0xffff) + macRomanChar = '?'; + else + { + if (!MacRoman::FromUnicode(macRomanChar, static_cast(codePoint))) + macRomanChar = '?'; + } + + chars[length++] = macRomanChar; + if (length == capacity) + break; + } + + for (int i = length; i < capacity; i++) + chars[i] = 0; + + m_patchedOK = true; + m_isDone = true; +} + +void PatchVisitor::VisitInt32(int32_t &v) +{ + if (m_isDone || m_haveScope) + return; + + int integer = 0; + if (sscanf(m_replacementValue, "%i", &integer) == 1) + { + m_patchedOK = true; + m_isDone = true; + v = integer; + } +} + +void PatchVisitor::VisitUInt32(uint32_t &v) +{ + if (m_isDone || m_haveScope) + return; + + unsigned int integer = 0; + if (sscanf(m_replacementValue, "%u", &integer) == 1) + { + m_patchedOK = true; + m_isDone = true; + v = integer; + } +} + +void PatchVisitor::VisitInt16(int16_t &v) +{ + if (m_isDone || m_haveScope) + return; + + int integer = 0; + if (sscanf(m_replacementValue, "%i", &integer) == 1) + { + m_patchedOK = true; + m_isDone = true; + v = integer; + } +} + +void PatchVisitor::VisitBool8(uint8_t &v) +{ + if (m_isDone || m_haveScope) + return; + + if (!strcmp(m_replacementValue, "true")) + { + m_patchedOK = true; + m_isDone = true; + v = 1; + } + else if (!strcmp(m_replacementValue, "false")) + { + m_patchedOK = true; + m_isDone = true; + v = 0; + } + else + { + int integer = 0; + if (sscanf(m_replacementValue, "%i", &integer) == 1) + { + m_patchedOK = true; + m_isDone = true; + v = integer; + } + } +} + +void PatchVisitor::VisitByte(uint8_t &v) +{ + if (m_isDone || m_haveScope) + return; + + int integer = 0; + if (sscanf(m_replacementValue, "%i", &integer) == 1) + { + m_patchedOK = true; + m_isDone = true; + v = integer; + } +} + +bool PatchVisitor::VisitEnum(const EnumDef *enumDefs, size_t numDefs, int &v) +{ + if (m_isDone || m_haveScope) + return false; + + for (size_t i = 0; i < numDefs; i++) + { + if (!strcmp(enumDefs[i].m_name, m_replacementValue)) + { + m_patchedOK = true; + m_isDone = true; + v = enumDefs[i].m_value; + return true; + } + } + + return false; +} + +bool PatchVisitor::VisitStaticCapacity(size_t size) +{ + return true; +} + +void PatchVisitor::VisitDynamicCapacity(size_t &size) +{ +} + +bool PatchVisitor::PatchedOK() const +{ + return m_patchedOK; +} + +bool PatchVisitor::DecodeInteger(const std::string &scopeStr, size_t startPos, int &outInteger, size_t &outEndPos) +{ + size_t len = scopeStr.length(); + + if (startPos >= len) + return false; + + bool isNegative = false; + char firstChar = scopeStr[startPos]; + if (firstChar == '-') + { + isNegative = true; + startPos++; + + if (startPos >= len) + return false; + } + + int resultInteger = 0; + + for (size_t i = startPos; i < len; i++) + { + char decChar = scopeStr[i]; + if (decChar >= '0' && decChar <= '9') + { + int digit = decChar - '0'; + if (isNegative) + resultInteger = resultInteger * 10 - digit; + else + resultInteger = resultInteger * 10 + digit; + } + else + { + if (i == startPos) + return false; + + outInteger = resultInteger; + outEndPos = i; + return true; + } + } + + outInteger = resultInteger; + outEndPos = len; + return true; +} + +bool PatchVisitor::DecodeQuotedString(const std::string &scopeStr, size_t startPos, std::string &outString, size_t &outEndPos) +{ + size_t len = scopeStr.length(); + + if (startPos >= len || scopeStr[startPos] != '\"') + return false; + + std::vector decoded; + for (size_t i = startPos + 1; i < len; i++) + { + char decChar = scopeStr[i]; + if (decChar == '\"') + { + if (decoded.size() == 0) + outString = std::string(); + else + outString = std::string(&decoded[0], decoded.size()); + + outEndPos = i + 1; + return true; + } + + if (decChar == '\\') + { + i++; + if (i == len) + return false; + + char escChar = scopeStr[i]; + if (escChar == '\"') + decoded.push_back('\"'); + else if (escChar == '\\') + decoded.push_back('\\'); + else if (escChar == '/') + decoded.push_back('/'); + else if (escChar == 'b') + decoded.push_back('\b'); + else if (escChar == 'f') + decoded.push_back('\f'); + else if (escChar == 'n') + decoded.push_back('\n'); + else if (escChar == 'r') + decoded.push_back('\r'); + else if (escChar == 't') + decoded.push_back('\t'); + else if (escChar == 'u') + { + int nibbles[4]; + for (int ni = 0; ni < 4; ni++) + { + i++; + if (i == len) + return false; + + char nibbleChar = scopeStr[i]; + if (nibbleChar >= '0' && nibbleChar <= '9') + nibbles[ni] = nibbleChar - '0'; + else if (nibbleChar >= 'A' && nibbleChar <= 'F') + nibbles[ni] = nibbleChar - 'A' + 0xa; + else if (nibbleChar >= 'a' && nibbleChar <= 'f') + nibbles[ni] = nibbleChar - 'a' + 0xa; + else + return false; + } + + const uint16_t unicodeCodePoint = (nibbles[0] << 12) + (nibbles[1] << 8) + (nibbles[2] << 4) + nibbles[3]; + uint8_t encoded[PortabilityLayer::UTF8Processor::kMaxEncodedBytes]; + size_t emitted = 0; + PortabilityLayer::UTF8Processor::EncodeCodePoint(encoded, emitted, unicodeCodePoint); + + for (size_t ei = 0; ei < emitted; ei++) + decoded.push_back(static_cast(encoded[ei])); + } + } + else + { + if (decChar < ' ' || decChar > '~') + return false; + + decoded.push_back(decChar); + } + } + + outEndPos = len; + return false; +} + +void PatchVisitor::EnterScope() +{ + if (!m_haveScope) + { + m_isDone = true; + return; + } + + bool shouldHaveScope = (m_nextScope.size() > 0); + if (!shouldHaveScope) + { + m_haveScope = false; + return; + } + + if (!TryEnterScope()) + { + m_haveScope = false; + m_isDone = true; + } +} + +bool PatchVisitor::TryEnterScope() +{ + if (m_nextScope.size() == 0) + return false; + + if (m_nextScope[0] == '.') + { + size_t lastFieldChar = 1; + while (lastFieldChar < m_nextScope.size()) + { + char c = m_nextScope[lastFieldChar]; + if ((c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || c == '_') + lastFieldChar++; + else + break; + } + + if (lastFieldChar == 1) + return false; + + m_nextScopeIsInteger = false; + m_scope = m_nextScope.substr(1, lastFieldChar - 1); + m_nextScope = m_nextScope.substr(lastFieldChar); + + return true; + } + + if (m_nextScope[0] == '[') + { + if (m_nextScope.size() == 1) + return false; + + if (m_nextScope[1] == '\"') + { + std::string quotedStr; + size_t endPos = 0; + if (!DecodeQuotedString(m_nextScope, 1, quotedStr, endPos)) + return false; + + if (endPos >= m_nextScope.size()) + return false; + + if (m_nextScope[endPos] != ']') + return false; + + m_nextScopeIsInteger = false; + m_scope = quotedStr; + m_nextScope = m_nextScope.substr(endPos + 1); + + return true; + } + else + { + int integer = 0; + size_t endPos = 0; + if (!DecodeInteger(m_nextScope, 1, integer, endPos)) + return false; + + if (endPos >= m_nextScope.size()) + return false; + + if (m_nextScope[endPos] != ']') + return false; + + m_nextScopeIsInteger = true; + m_scope = ""; + m_scopeInteger = integer; + m_nextScope = m_nextScope.substr(endPos + 1); + + return true; + } + } + + return false; +} + + +int PatchMain(int argc, const char **argv) +{ + if (argc != 5) + return PrintUsage(); + + houseType house; + std::vector rooms; + + if (!ReadHouseFromPath(argv[2], house, rooms)) + { + fprintf(stderr, "Failed to read house\n"); + return -1; + } + + PatchVisitor patcher(argv[3], argv[4]); + Visit(house, rooms, &patcher); + + if (!patcher.PatchedOK()) + fprintf(stderr, "Patch failed\n"); + else + { + FILE *houseOutF = fopen_utf8(argv[2], "wb"); + if (!houseOutF) + { + fprintf(stderr, "Failed to open output house\n"); + return -1; + } + + fwrite(&house, 1, houseType::kBinaryDataSize, houseOutF); + if (rooms.size() > 0) + fwrite(&rooms[0], 1, sizeof(roomType) * rooms.size(), houseOutF); + + fclose(houseOutF); + } + + return 0; +} + +class DecompileVisitor final : public IDataVisitor +{ +public: + explicit DecompileVisitor(FILE *f); + + IDataVisitor *EnterIndex(int index) override; + IDataVisitor *EnterNamed(const char *name) override; + void Exit() override; + + void VisitLPStr(uint8_t &length, uint8_t *chars, int capacity) override; + void VisitInt32(int32_t &v) override; + void VisitUInt32(uint32_t &v) override; + void VisitInt16(int16_t &v) override; + void VisitBool8(uint8_t &v) override; + void VisitByte(uint8_t &v) override; + bool VisitEnum(const EnumDef *enumDefs, size_t numDefs, int &v) override; + + bool VisitStaticCapacity(size_t size) override; + void VisitDynamicCapacity(size_t &size) override; + +private: + enum ScopeType + { + ScopeType_Array, + ScopeType_Map, + ScopeType_Unknown, + }; + + FILE *m_f; + int m_indentLevel; + + bool m_isInNamed; + bool m_isInArray; + + std::vector m_scopes; + + ScopeType GetTopScope(); + void SetTopScope(ScopeType scopeType); + void PopScope(); + void PushScope(); + + void WriteIndent(); +}; + +DecompileVisitor::DecompileVisitor(FILE *f) + : m_f(f) +{ + m_scopes.push_back(ScopeType_Unknown); +} + +IDataVisitor *DecompileVisitor::EnterIndex(int index) +{ + ScopeType topScope = GetTopScope(); + if (topScope == ScopeType_Array) + { + fprintf(m_f, ",\n"); + WriteIndent(); + } + else + { + fprintf(m_f, "[\n"); + WriteIndent(); + SetTopScope(ScopeType_Array); + } + + PushScope(); + + fprintf(m_f, "[%i] = ", index); + + return this; +} + +IDataVisitor *DecompileVisitor::EnterNamed(const char *name) +{ + ScopeType topScope = GetTopScope(); + if (topScope == ScopeType_Map) + { + fprintf(m_f, ",\n"); + WriteIndent(); + } + else + { + fprintf(m_f, "{\n"); + WriteIndent(); + SetTopScope(ScopeType_Map); + } + + PushScope(); + + fprintf(m_f, "%s = ", name); + + return this; +} + +void DecompileVisitor::Exit() +{ + ScopeType topScope = GetTopScope(); + if (topScope == ScopeType_Map) + { + fprintf(m_f, "\n"); + PopScope(); + WriteIndent(); + fprintf(m_f, "}"); + } + else if (topScope == ScopeType_Array) + { + fprintf(m_f, "\n"); + PopScope(); + WriteIndent(); + fprintf(m_f, "]"); + } + else + PopScope(); +} + + +void DecompileVisitor::VisitLPStr(uint8_t &length, uint8_t *chars, int capacity) +{ + fputc('\"', m_f); + for (size_t i = 0; i < length; i++) + { + uint16_t unicodeChar = MacRoman::ToUnicode(chars[i]); + if (unicodeChar == '\\') + fputs("\\\\", m_f); + else if (unicodeChar == '\"') + fputs("\\\"", m_f); + else if (unicodeChar == '\r') + fputs("\\r", m_f); + else if (unicodeChar == '\n') + fputs("\\n", m_f); + else if (unicodeChar < 32 || unicodeChar > 126) + fprintf(m_f, "\\u%04x", unicodeChar); + else + { + uint8_t ubyte = static_cast(unicodeChar); + fwrite(&ubyte, 1, 1, m_f); + } + } + fputc('\"', m_f); +} + +void DecompileVisitor::VisitInt32(int32_t &v) +{ + fprintf(m_f, "%i", static_cast(v)); +} + +void DecompileVisitor::VisitUInt32(uint32_t &v) +{ + fprintf(m_f, "%u", static_cast(v)); +} + + +void DecompileVisitor::VisitInt16(int16_t &v) +{ + fprintf(m_f, "%i", static_cast(v)); +} + +void DecompileVisitor::VisitBool8(uint8_t &v) +{ + if (v == 0) + fprintf(m_f, "false"); + else if (v == 1) + fprintf(m_f, "true"); + else + fprintf(m_f, "%i", static_cast(v)); +} + +void DecompileVisitor::VisitByte(uint8_t &v) +{ + fprintf(m_f, "%i", static_cast(v)); +} + +bool DecompileVisitor::VisitEnum(const EnumDef *enumDefs, size_t numDefs, int &v) +{ + for (size_t i = 0; i < numDefs; i++) + { + if (enumDefs[i].m_value == v) + { + fprintf(m_f, "\"%s\"", enumDefs[i].m_name); + return true; + } + } + + return false; +} + +bool DecompileVisitor::VisitStaticCapacity(size_t size) +{ + return true; +} + +void DecompileVisitor::VisitDynamicCapacity(size_t &size) +{ +} + +DecompileVisitor::ScopeType DecompileVisitor::GetTopScope() +{ + return m_scopes[m_scopes.size() - 1]; +} + +void DecompileVisitor::SetTopScope(ScopeType scopeType) +{ + m_scopes[m_scopes.size() - 1] = scopeType; +} + +void DecompileVisitor::PopScope() +{ + m_scopes.pop_back(); +} + +void DecompileVisitor::PushScope() +{ + m_scopes.push_back(ScopeType_Unknown); +} + +void DecompileVisitor::WriteIndent() +{ + for (size_t i = 0; i < m_scopes.size(); i++) + fputc('\t', m_f); +} + +int DecompileMain(int argc, const char **argv) +{ + if (argc != 4) + return PrintUsage(); + + houseType house; + std::vector rooms; + + if (!ReadHouseFromPath(argv[2], house, rooms)) + { + fprintf(stderr, "Failed to read house\n"); + return -1; + } + + FILE *outF = fopen_utf8(argv[3], "wb"); + if (!outF) + { + fprintf(stderr, "Failed to open output house\n"); + return -1; + } + + DecompileVisitor decompiler(outF); + Visit(house, rooms, &decompiler); + + fclose(outF); + + return 0; +} + +int toolMain(int argc, const char **argv) +{ + static const size_t houseSize = sizeof(houseType); + static_assert(sizeof(houseType) >= houseType::kBinaryDataSize, "House type is too small"); + + if (argc < 3) + return PrintUsage(); + + std::string operation = argv[1]; + + if (operation == "patch") + return PatchMain(argc, argv); + + if (operation == "decompile") + return DecompileMain(argc, argv); + + return 0; +} diff --git a/HouseTool/HouseTool.vcxproj b/HouseTool/HouseTool.vcxproj new file mode 100644 index 0000000..d480288 --- /dev/null +++ b/HouseTool/HouseTool.vcxproj @@ -0,0 +1,101 @@ + + + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {B31BFF9D-2D14-4B1A-A625-8348CC3D8D67} + HouseTool + 10.0.17763.0 + + + + Application + true + v141 + MultiByte + + + Application + false + v141 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Level3 + MaxSpeed + true + true + true + true + + + Console + true + true + + + + + Level3 + Disabled + true + true + + + Console + + + + + + + + {6ec62b0f-9353-40a4-a510-3788f1368b33} + + + {15009625-1120-405e-8bba-69a16cd6713d} + + + + + + + + + \ No newline at end of file diff --git a/HouseTool/HouseTool.vcxproj.filters b/HouseTool/HouseTool.vcxproj.filters new file mode 100644 index 0000000..84f151a --- /dev/null +++ b/HouseTool/HouseTool.vcxproj.filters @@ -0,0 +1,25 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + + + + \ No newline at end of file