mirror of
https://github.com/AppleWin/AppleWin.git
synced 2024-12-23 00:30:17 +00:00
292 lines
6.7 KiB
C++
292 lines
6.7 KiB
C++
#pragma once
|
|
|
|
#include "yaml.h"
|
|
|
|
#include "StrFormat.h"
|
|
|
|
#define SS_YAML_KEY_FILEHDR "File_hdr"
|
|
#define SS_YAML_KEY_TAG "Tag"
|
|
#define SS_YAML_KEY_VERSION "Version"
|
|
#define SS_YAML_KEY_UNIT "Unit"
|
|
#define SS_YAML_KEY_TYPE "Type"
|
|
#define SS_YAML_KEY_CARD "Card"
|
|
#define SS_YAML_KEY_STATE "State"
|
|
#define SS_YAML_KEY_DEVICE "Device"
|
|
|
|
#define SS_YAML_VALUE_AWSS "AppleWin Save State"
|
|
|
|
struct MapValue;
|
|
typedef std::map<std::string, MapValue> MapYaml;
|
|
|
|
struct MapValue
|
|
{
|
|
std::string value;
|
|
MapYaml* subMap;
|
|
};
|
|
|
|
class YamlHelper
|
|
{
|
|
friend class YamlLoadHelper; // YamlLoadHelper can access YamlHelper's private members
|
|
|
|
public:
|
|
YamlHelper(void) :
|
|
m_hFile(NULL)
|
|
{
|
|
memset(&m_parser, 0, sizeof(m_parser));
|
|
memset(&m_newEvent, 0, sizeof(m_newEvent));
|
|
MakeAsciiToHexTable();
|
|
}
|
|
|
|
~YamlHelper(void)
|
|
{
|
|
FinaliseParser();
|
|
}
|
|
|
|
int InitParser(const char* pPathname);
|
|
void FinaliseParser(void);
|
|
|
|
UINT ParseFileHdr(const char* tag);
|
|
|
|
int GetScalar(std::string& scalar);
|
|
void GetMapStartEvent(void);
|
|
|
|
private:
|
|
void GetNextEvent(void);
|
|
int ParseMap(MapYaml& mapYaml);
|
|
std::string GetMapValue(MapYaml& mapYaml, const std::string &key, bool& bFound);
|
|
UINT LoadMemory(MapYaml& mapYaml, const LPBYTE pMemBase, const size_t kAddrSpaceSize, const UINT offset);
|
|
bool GetSubMap(MapYaml** mapYaml, const std::string &key, const bool canBeNull=false);
|
|
void GetMapRemainder(std::string& mapName, MapYaml& mapYaml);
|
|
|
|
void MakeAsciiToHexTable(void);
|
|
|
|
yaml_parser_t m_parser;
|
|
yaml_event_t m_newEvent;
|
|
|
|
std::string m_scalarName;
|
|
|
|
FILE* m_hFile;
|
|
char m_AsciiToHex[256];
|
|
|
|
MapYaml m_mapYaml;
|
|
};
|
|
|
|
// -----
|
|
|
|
class YamlLoadHelper
|
|
{
|
|
public:
|
|
YamlLoadHelper(YamlHelper& yamlHelper)
|
|
: m_yamlHelper(yamlHelper),
|
|
m_pMapYaml(&yamlHelper.m_mapYaml),
|
|
m_bDoGetMapRemainder(true),
|
|
m_topLevelMapName(yamlHelper.m_scalarName),
|
|
m_currentMapName(m_topLevelMapName),
|
|
m_bIteratingOverMap(false)
|
|
{
|
|
if (!m_yamlHelper.ParseMap(yamlHelper.m_mapYaml))
|
|
{
|
|
m_bDoGetMapRemainder = false;
|
|
throw std::runtime_error(m_currentMapName + ": Failed to parse map");
|
|
}
|
|
}
|
|
|
|
~YamlLoadHelper(void)
|
|
{
|
|
if (m_bDoGetMapRemainder)
|
|
m_yamlHelper.GetMapRemainder(m_topLevelMapName, m_yamlHelper.m_mapYaml);
|
|
}
|
|
|
|
INT LoadInt(const std::string key);
|
|
UINT LoadUint(const std::string key);
|
|
UINT64 LoadUint64(const std::string key);
|
|
bool LoadBool(const std::string key);
|
|
std::string LoadString_NoThrow(const std::string& key, bool& bFound);
|
|
std::string LoadString(const std::string& key);
|
|
float LoadFloat(const std::string & key);
|
|
double LoadDouble(const std::string & key);
|
|
void LoadMemory(const LPBYTE pMemBase, const size_t size, const UINT offset=0);
|
|
void LoadMemory(std::vector<BYTE>& memory, const size_t size, const UINT offset=0);
|
|
|
|
bool GetSubMap(const std::string & key, const bool canBeNull=false)
|
|
{
|
|
YamlStackItem item = {m_pMapYaml, m_currentMapName};
|
|
m_stackMap.push(item);
|
|
bool res = m_yamlHelper.GetSubMap(&m_pMapYaml, key, canBeNull);
|
|
if (!res)
|
|
m_stackMap.pop();
|
|
else
|
|
m_currentMapName = key;
|
|
return res;
|
|
}
|
|
|
|
void PopMap(void)
|
|
{
|
|
if (m_stackMap.empty())
|
|
return;
|
|
|
|
YamlStackItem item = m_stackMap.top();
|
|
m_stackMap.pop();
|
|
|
|
m_pMapYaml = item.pMapYaml;
|
|
m_currentMapName = item.mapName;
|
|
}
|
|
|
|
std::string GetMapNextSlotNumber(void)
|
|
{
|
|
if (!m_bIteratingOverMap)
|
|
{
|
|
m_iter = m_pMapYaml->begin();
|
|
m_bIteratingOverMap = true;
|
|
}
|
|
|
|
if (m_iter == m_pMapYaml->end())
|
|
{
|
|
m_bIteratingOverMap = false;
|
|
return "";
|
|
}
|
|
|
|
std::string scalar = m_iter->first;
|
|
++m_iter;
|
|
return scalar;
|
|
}
|
|
|
|
private:
|
|
YamlHelper& m_yamlHelper;
|
|
MapYaml* m_pMapYaml;
|
|
bool m_bDoGetMapRemainder;
|
|
|
|
struct YamlStackItem
|
|
{
|
|
MapYaml* pMapYaml;
|
|
std::string mapName;
|
|
};
|
|
std::stack<YamlStackItem> m_stackMap;
|
|
|
|
std::string m_topLevelMapName;
|
|
std::string m_currentMapName;
|
|
|
|
bool m_bIteratingOverMap;
|
|
MapYaml::iterator m_iter;
|
|
};
|
|
|
|
// -----
|
|
|
|
class YamlSaveHelper
|
|
{
|
|
public:
|
|
YamlSaveHelper(const std::string & pathname) :
|
|
m_hFile(NULL),
|
|
m_indent(0),
|
|
m_pWcStr(NULL),
|
|
m_wcStrSize(0),
|
|
m_pMbStr(NULL),
|
|
m_mbStrSize(0)
|
|
{
|
|
m_hFile = fopen(pathname.c_str(), "wt");
|
|
|
|
// todo: handle ERROR_ALREADY_EXISTS - ask if user wants to replace existing file
|
|
// - at this point any old file will have been truncated to zero
|
|
|
|
if(m_hFile == NULL)
|
|
throw std::runtime_error("Save error");
|
|
|
|
_tzset();
|
|
time_t ltime;
|
|
time(<ime);
|
|
char timebuf[26];
|
|
errno_t err = ctime_s(timebuf, sizeof(timebuf), <ime); // includes newline at end of string
|
|
fprintf(m_hFile, "# Date-stamp: %s\n", err == 0 ? timebuf : "Error: Datestamp\n\n");
|
|
|
|
fprintf(m_hFile, "---\n");
|
|
|
|
//
|
|
|
|
memset(m_szIndent, ' ', kMaxIndent);
|
|
}
|
|
|
|
~YamlSaveHelper()
|
|
{
|
|
if (m_hFile)
|
|
{
|
|
fprintf(m_hFile, "...\n");
|
|
fclose(m_hFile);
|
|
}
|
|
|
|
delete[] m_pWcStr;
|
|
delete[] m_pMbStr;
|
|
}
|
|
|
|
void Save(const char* format, ...) ATTRIBUTE_FORMAT_PRINTF(2, 3); // 1 is "this"
|
|
|
|
void SaveInt(const char* key, int value);
|
|
void SaveUint(const char* key, UINT value);
|
|
void SaveHexUint4(const char* key, UINT value);
|
|
void SaveHexUint8(const char* key, UINT value);
|
|
void SaveHexUint12(const char* key, UINT value);
|
|
void SaveHexUint16(const char* key, UINT value);
|
|
void SaveHexUint24(const char* key, UINT value);
|
|
void SaveHexUint32(const char* key, UINT value);
|
|
void SaveHexUint64(const char* key, UINT64 value);
|
|
void SaveBool(const char* key, bool value);
|
|
void SaveString(const char* key, const char* value);
|
|
void SaveString(const char* key, const std::string & value);
|
|
void SaveFloat(const char* key, float value);
|
|
void SaveDouble(const char* key, double value);
|
|
void SaveMemory(const LPBYTE pMemBase, const UINT uMemSize, const UINT offset=0);
|
|
|
|
class Label
|
|
{
|
|
public:
|
|
Label(YamlSaveHelper& rYamlSaveHelper, const char* format, ...) ATTRIBUTE_FORMAT_PRINTF(3, 4) : // 1 is "this"
|
|
yamlSaveHelper(rYamlSaveHelper)
|
|
{
|
|
fwrite(yamlSaveHelper.m_szIndent, 1, yamlSaveHelper.m_indent, yamlSaveHelper.m_hFile);
|
|
|
|
va_list vl;
|
|
va_start(vl, format);
|
|
vfprintf(yamlSaveHelper.m_hFile, format, vl);
|
|
va_end(vl);
|
|
|
|
yamlSaveHelper.m_indent += 2;
|
|
_ASSERT(yamlSaveHelper.m_indent < yamlSaveHelper.kMaxIndent);
|
|
}
|
|
|
|
~Label(void)
|
|
{
|
|
yamlSaveHelper.m_indent -= 2;
|
|
_ASSERT(yamlSaveHelper.m_indent >= 0);
|
|
}
|
|
|
|
YamlSaveHelper& yamlSaveHelper;
|
|
};
|
|
|
|
class Slot : public Label
|
|
{
|
|
public:
|
|
Slot(YamlSaveHelper& rYamlSaveHelper, const std::string & type, UINT slot, UINT version) :
|
|
Label(rYamlSaveHelper, "%d:\n", slot)
|
|
{
|
|
rYamlSaveHelper.Save("%s: %s\n", SS_YAML_KEY_CARD, type.c_str());
|
|
rYamlSaveHelper.Save("%s: %d\n", SS_YAML_KEY_VERSION, version);
|
|
}
|
|
|
|
~Slot(void) {}
|
|
};
|
|
|
|
void FileHdr(UINT version);
|
|
void UnitHdr(const std::string & type, UINT version);
|
|
|
|
private:
|
|
FILE* m_hFile;
|
|
|
|
int m_indent;
|
|
static const UINT kMaxIndent = 50*2;
|
|
char m_szIndent[kMaxIndent];
|
|
|
|
LPWSTR m_pWcStr;
|
|
int m_wcStrSize;
|
|
LPSTR m_pMbStr;
|
|
int m_mbStrSize;
|
|
};
|