2010-01-23 19:44:49 +00:00
|
|
|
/**********************************************************************
|
|
|
|
|
2010-07-06 21:39:08 +00:00
|
|
|
Audacity: A Digital Audio Editor
|
|
|
|
Audacity(R) is copyright (c) 1999-2010 Audacity Team.
|
|
|
|
License: GPL v2. See License.txt.
|
2010-01-23 19:44:49 +00:00
|
|
|
|
2010-07-06 21:39:08 +00:00
|
|
|
AutoRecovery.cpp
|
2010-01-23 19:44:49 +00:00
|
|
|
|
|
|
|
*******************************************************************//**
|
|
|
|
|
2017-11-09 18:32:29 +00:00
|
|
|
\class AutoSaveFile
|
|
|
|
\brief a class wrapping reading and writing of arbitrary data in
|
|
|
|
text or binary format to a file.
|
|
|
|
|
2010-01-23 19:44:49 +00:00
|
|
|
*//********************************************************************/
|
|
|
|
|
|
|
|
#include "Audacity.h"
|
2018-11-11 02:40:37 +00:00
|
|
|
#include "AutoRecovery.h"
|
2016-02-03 17:56:21 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
#include <wx/ustring.h>
|
2015-04-17 21:42:30 +00:00
|
|
|
|
|
|
|
///
|
|
|
|
/// AutoSaveFile class
|
|
|
|
///
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
// Simple "binary xml" format used exclusively for autosave documents.
|
2015-04-17 21:42:30 +00:00
|
|
|
//
|
|
|
|
// It is not intended that the user view or modify the file.
|
|
|
|
//
|
2015-06-07 17:38:29 +00:00
|
|
|
// It IS intended that very little work be done during auto save, so numbers
|
2015-04-17 21:42:30 +00:00
|
|
|
// and strings are written in their native format. They will be converted
|
|
|
|
// during recovery.
|
|
|
|
//
|
|
|
|
// The file has 3 main sections:
|
|
|
|
//
|
2020-07-01 05:45:17 +00:00
|
|
|
// character size 1 (UTF-8), 2 (UTF-16) or 4 (UTF-32)
|
2015-04-17 21:42:30 +00:00
|
|
|
// name dictionary dictionary of all names used in the document
|
|
|
|
// data fields the "encoded" XML document
|
|
|
|
//
|
2015-06-07 17:38:29 +00:00
|
|
|
// If a subtree is added, it will be preceeded with FT_Push to tell the decoder
|
|
|
|
// to preserve the active dictionary. The decoder will then restore the
|
2015-04-17 21:42:30 +00:00
|
|
|
// dictionary when an FT_Pop is encountered. Nesting is unlimited.
|
|
|
|
//
|
|
|
|
// To save space, each name (attribute or element) encountered is stored in
|
|
|
|
// the name dictionary and replaced with the assigned 2-byte identifier.
|
|
|
|
//
|
|
|
|
// All strings are in native unicode format, 2-byte or 4-byte.
|
|
|
|
//
|
2020-07-01 05:45:17 +00:00
|
|
|
// All name "lengths" are 2-byte signed, so are limited to 32767 bytes long.
|
2020-07-01 11:59:38 +00:00
|
|
|
// All string/data "lengths" are 4-byte signed.
|
2015-04-17 21:42:30 +00:00
|
|
|
|
|
|
|
enum FieldTypes
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
FT_CharSize, // type, ID, value
|
2019-04-29 00:42:10 +00:00
|
|
|
FT_StartTag, // type, ID
|
|
|
|
FT_EndTag, // type, ID
|
|
|
|
FT_String, // type, ID, string length, string
|
2015-04-17 21:42:30 +00:00
|
|
|
FT_Int, // type, ID, value
|
|
|
|
FT_Bool, // type, ID, value
|
|
|
|
FT_Long, // type, ID, value
|
|
|
|
FT_LongLong, // type, ID, value
|
|
|
|
FT_SizeT, // type, ID, value
|
2019-04-29 00:42:10 +00:00
|
|
|
FT_Float, // type, ID, value, digits
|
|
|
|
FT_Double, // type, ID, value, digits
|
2015-04-17 21:42:30 +00:00
|
|
|
FT_Data, // type, string length, string
|
|
|
|
FT_Raw, // type, string length, string
|
|
|
|
FT_Push, // type only
|
|
|
|
FT_Pop, // type only
|
2019-04-29 00:42:10 +00:00
|
|
|
FT_Name // type, ID, name length, name
|
2015-04-17 21:42:30 +00:00
|
|
|
};
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
// Static so that the dict can be reused each time.
|
|
|
|
//
|
|
|
|
// If entries get added later, like when an envelope node (for example)
|
|
|
|
// is writen and then the envelope is later removed, the dict will still
|
|
|
|
// contain the envelope name, but that's not a problem.
|
|
|
|
|
|
|
|
NameMap AutoSaveFile::mNames;
|
|
|
|
wxMemoryBuffer AutoSaveFile::mDict;
|
|
|
|
|
2019-12-07 19:30:07 +00:00
|
|
|
TranslatableString AutoSaveFile::FailureMessage( const FilePath &/*filePath*/ )
|
2019-04-29 00:51:24 +00:00
|
|
|
{
|
2019-05-01 14:27:15 +00:00
|
|
|
return
|
2019-12-07 19:30:07 +00:00
|
|
|
XO("This recovery file was saved by Audacity 2.3.0 or before.\n"
|
2019-05-01 14:27:15 +00:00
|
|
|
"You need to run that version of Audacity to recover the project." );
|
2019-04-29 00:51:24 +00:00
|
|
|
}
|
|
|
|
|
2015-04-17 21:42:30 +00:00
|
|
|
AutoSaveFile::AutoSaveFile(size_t allocSize)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mDict.SetBufSize(allocSize);
|
|
|
|
mBuffer.SetBufSize(allocSize);
|
|
|
|
|
|
|
|
// Store the size of "wxChar" so we can convert during recovery in
|
|
|
|
// case the file is used on a system with a different character size.
|
|
|
|
char size = sizeof(wxChar);
|
|
|
|
mDict.AppendByte(FT_CharSize);
|
|
|
|
mDict.AppendData(&size, sizeof(size));
|
|
|
|
|
|
|
|
mDictChanged = false;
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
AutoSaveFile::~AutoSaveFile()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::StartTag(const wxString & name)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_StartTag);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::EndTag(const wxString & name)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_EndTag);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, const wxChar *value)
|
|
|
|
{
|
|
|
|
WriteAttr(name, wxString(value));
|
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, const wxString & value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_String);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2019-03-06 19:53:39 +00:00
|
|
|
int len = value.length() * sizeof(wxChar);
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&len, sizeof(len));
|
|
|
|
mBuffer.AppendData(value.wx_str(), len);
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, int value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Int);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, bool value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Bool);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, long value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Long);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, long long value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_LongLong);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, size_t value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_SizeT);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, float value, int digits)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Float);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
|
|
|
mBuffer.AppendData(&digits, sizeof(digits));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteAttr(const wxString & name, double value, int digits)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Double);
|
2015-04-17 21:42:30 +00:00
|
|
|
WriteName(name);
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&value, sizeof(value));
|
|
|
|
mBuffer.AppendData(&digits, sizeof(digits));
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteData(const wxString & value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Data);
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2019-03-06 19:53:39 +00:00
|
|
|
int len = value.length() * sizeof(wxChar);
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&len, sizeof(len));
|
|
|
|
mBuffer.AppendData(value.wx_str(), len);
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::Write(const wxString & value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Raw);
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2019-03-06 19:53:39 +00:00
|
|
|
int len = value.length() * sizeof(wxChar);
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&len, sizeof(len));
|
|
|
|
mBuffer.AppendData(value.wx_str(), len);
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteSubTree(const AutoSaveFile & value)
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Push);
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(value.mDict.GetData(), value.mDict.GetDataLen());
|
|
|
|
mBuffer.AppendData(value.mBuffer.GetData(), value.mBuffer.GetDataLen());
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendByte(FT_Pop);
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void AutoSaveFile::WriteName(const wxString & name)
|
|
|
|
{
|
2019-03-06 19:53:39 +00:00
|
|
|
wxASSERT(name.length() * sizeof(wxChar) <= SHRT_MAX);
|
2015-04-17 21:42:30 +00:00
|
|
|
short id;
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
auto nameiter = mNames.find(name);
|
|
|
|
if (nameiter != mNames.end())
|
2015-04-17 21:42:30 +00:00
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
id = nameiter->second;
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
short len = name.length() * sizeof(wxChar);
|
|
|
|
|
2015-04-17 21:42:30 +00:00
|
|
|
id = mNames.size();
|
|
|
|
mNames[name] = id;
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mDict.AppendByte(FT_Name);
|
|
|
|
mDict.AppendData(&id, sizeof(id));
|
|
|
|
mDict.AppendData(&len, sizeof(len));
|
|
|
|
mDict.AppendData(name.wx_str(), len);
|
|
|
|
|
|
|
|
mDictChanged = true;
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
mBuffer.AppendData(&id, sizeof(id));
|
|
|
|
}
|
|
|
|
|
|
|
|
const wxMemoryBuffer &AutoSaveFile::GetDict() const
|
|
|
|
{
|
|
|
|
return mDict;
|
|
|
|
}
|
|
|
|
|
|
|
|
const wxMemoryBuffer &AutoSaveFile::GetData() const
|
|
|
|
{
|
|
|
|
return mBuffer;
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool AutoSaveFile::IsEmpty() const
|
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
return mBuffer.GetDataLen() == 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AutoSaveFile::DictChanged() const
|
|
|
|
{
|
|
|
|
return mDictChanged;
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|
|
|
|
|
2020-07-09 18:14:12 +00:00
|
|
|
// See ProjectFileIO::CheckForOrphans() for explanation of the blockids arg
|
|
|
|
wxString AutoSaveFile::Decode(const wxMemoryBuffer &buffer, BlockIDs &blockids)
|
2015-04-17 21:42:30 +00:00
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
wxMemoryInputStream in(buffer.GetData(), buffer.GetDataLen());
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
XMLStringWriter out;
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
std::vector<char> bytes;
|
|
|
|
IdMap mIds;
|
|
|
|
std::vector<IdMap> mIdStack;
|
|
|
|
char mCharSize = 0;
|
|
|
|
|
|
|
|
mIds.clear();
|
|
|
|
|
2020-07-05 19:13:30 +00:00
|
|
|
struct Error{}; // exception type for short-range try/catch
|
2020-07-01 05:45:17 +00:00
|
|
|
auto Lookup = [&mIds]( short id ) -> const wxString &
|
2015-04-17 21:42:30 +00:00
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
auto iter = mIds.find( id );
|
|
|
|
if (iter == mIds.end())
|
|
|
|
{
|
|
|
|
throw Error{};
|
|
|
|
}
|
|
|
|
return iter->second;
|
|
|
|
};
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
auto Convert = [&mCharSize](char *in, int len) -> wxString
|
2015-04-17 21:42:30 +00:00
|
|
|
{
|
2020-07-01 05:45:17 +00:00
|
|
|
wxUString str;
|
2015-04-19 05:36:55 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
switch (mCharSize)
|
|
|
|
{
|
2020-07-09 18:14:12 +00:00
|
|
|
case 1:
|
|
|
|
str.assignFromUTF8(in, len);
|
|
|
|
break;
|
2020-07-01 05:45:17 +00:00
|
|
|
|
2020-07-09 18:14:12 +00:00
|
|
|
case 2:
|
|
|
|
str.assignFromUTF16((wxChar16 *) in, len / 2);
|
|
|
|
break;
|
2015-04-19 05:36:55 +00:00
|
|
|
|
2020-07-09 18:14:12 +00:00
|
|
|
case 4:
|
|
|
|
str = wxU32CharBuffer::CreateNonOwned((wxChar32 *) in, len / 4);
|
|
|
|
break;
|
2020-07-01 05:45:17 +00:00
|
|
|
|
2020-07-09 18:14:12 +00:00
|
|
|
default:
|
|
|
|
wxASSERT_MSG(false, wxT("Characters size not 1, 2, or 4"));
|
|
|
|
break;
|
2020-07-01 05:45:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
|
|
|
};
|
2015-04-22 12:53:01 +00:00
|
|
|
|
2020-07-09 18:14:12 +00:00
|
|
|
try
|
2020-07-01 05:45:17 +00:00
|
|
|
{
|
2020-07-09 18:14:12 +00:00
|
|
|
while (!in.Eof())
|
2015-04-22 12:53:01 +00:00
|
|
|
{
|
2020-07-09 18:14:12 +00:00
|
|
|
short id;
|
2015-04-19 05:36:55 +00:00
|
|
|
|
2020-07-09 18:14:12 +00:00
|
|
|
switch (in.GetC())
|
2020-07-01 05:45:17 +00:00
|
|
|
{
|
2020-07-09 18:14:12 +00:00
|
|
|
case FT_Push:
|
|
|
|
{
|
|
|
|
mIdStack.push_back(mIds);
|
|
|
|
mIds.clear();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Pop:
|
|
|
|
{
|
|
|
|
mIds = mIdStack.back();
|
|
|
|
mIdStack.pop_back();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Name:
|
|
|
|
{
|
|
|
|
short len;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&len, sizeof(len));
|
|
|
|
bytes.reserve(len);
|
|
|
|
in.Read(bytes.data(), len);
|
|
|
|
|
|
|
|
mIds[id] = Convert(bytes.data(), len);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_StartTag:
|
|
|
|
{
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
|
|
|
|
out.StartTag(Lookup(id));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_EndTag:
|
|
|
|
{
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
|
|
|
|
out.EndTag(Lookup(id));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_String:
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&len, sizeof(len));
|
|
|
|
bytes.reserve(len);
|
|
|
|
in.Read(bytes.data(), len);
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), Convert(bytes.data(), len));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Float:
|
|
|
|
{
|
|
|
|
float val;
|
|
|
|
int dig;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
in.Read(&dig, sizeof(dig));
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val, dig);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Double:
|
|
|
|
{
|
|
|
|
double val;
|
|
|
|
int dig;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
in.Read(&dig, sizeof(dig));
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val, dig);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Int:
|
|
|
|
{
|
|
|
|
int val;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Bool:
|
|
|
|
{
|
|
|
|
bool val;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Long:
|
|
|
|
{
|
|
|
|
long val;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_LongLong:
|
|
|
|
{
|
|
|
|
long long val;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
|
|
|
|
// Look for and save the "blockid" values to support orphan
|
|
|
|
// block checking. This should be removed once autosave and
|
|
|
|
// related blocks become part of the same transaction.
|
|
|
|
const wxString &name = Lookup(id);
|
|
|
|
if (name.IsSameAs(wxT("blockid")))
|
|
|
|
{
|
|
|
|
blockids.insert(val);
|
|
|
|
}
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_SizeT:
|
|
|
|
{
|
|
|
|
size_t val;
|
|
|
|
|
|
|
|
in.Read(&id, sizeof(id));
|
|
|
|
in.Read(&val, sizeof(val));
|
|
|
|
|
|
|
|
out.WriteAttr(Lookup(id), val);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Data:
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
in.Read(&len, sizeof(len));
|
|
|
|
bytes.reserve(len);
|
|
|
|
in.Read(bytes.data(), len);
|
|
|
|
|
|
|
|
out.WriteData(Convert(bytes.data(), len));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_Raw:
|
|
|
|
{
|
|
|
|
int len;
|
|
|
|
|
|
|
|
in.Read(&len, sizeof(len));
|
|
|
|
bytes.reserve(len);
|
|
|
|
in.Read(bytes.data(), len);
|
|
|
|
|
|
|
|
out.Write(Convert(bytes.data(), len));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FT_CharSize:
|
|
|
|
{
|
|
|
|
in.Read(&mCharSize, sizeof(mCharSize));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
wxASSERT(true);
|
|
|
|
break;
|
2020-07-01 05:45:17 +00:00
|
|
|
}
|
|
|
|
}
|
2020-07-09 18:14:12 +00:00
|
|
|
}
|
|
|
|
catch( const Error& )
|
|
|
|
{
|
2020-07-05 19:13:30 +00:00
|
|
|
// Autosave was corrupt, or platform differences in size or endianness
|
|
|
|
// were not well canonicalized
|
|
|
|
return {};
|
2020-07-01 05:45:17 +00:00
|
|
|
}
|
2015-04-17 21:42:30 +00:00
|
|
|
|
2020-07-01 05:45:17 +00:00
|
|
|
return out;
|
2015-04-17 21:42:30 +00:00
|
|
|
}
|