Skip to content

Commit

Permalink
Unsafe and quick modes for object deserialization
Browse files Browse the repository at this point in the history
  • Loading branch information
wghost committed Jan 13, 2014
1 parent 64b4f92 commit a2d8de6
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 49 deletions.
2 changes: 1 addition & 1 deletion FindObjectEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ int main(int argN, char* argV[])

if (ObjRef > 0)
{
cout << "Attempting deserialization:\n" << package.Deserialize(ObjRef);
cout << "Attempting deserialization:\n" << package.Deserialize(ObjRef, true);
}

return 0;
Expand Down
115 changes: 80 additions & 35 deletions UObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@

#include <sstream>

std::string UDefaultPropertiesList::Deserialize(std::istream& stream, UPKInfo& info)
std::string UDefaultPropertiesList::Deserialize(std::istream& stream, UPKInfo& info, UObjectReference owner, bool unsafe, bool quick)
{
std::ostringstream ss;
ss << "UDefaultPropertiesList:\n";
PropertyOffset = stream.tellg();
DefaultProperties.clear();
size_t maxOffset = info.GetExportEntry(OwnerRef).SerialOffset + info.GetExportEntry(OwnerRef).SerialSize;
size_t maxOffset = info.GetExportEntry(owner).SerialOffset + info.GetExportEntry(owner).SerialSize;
UDefaultProperty Property;
do
{
Property = UDefaultProperty{};
Property.SetOwner(OwnerRef);
ss << Property.Deserialize(stream, info, maxOffset);
ss << Property.Deserialize(stream, info, owner, unsafe, quick);
DefaultProperties.push_back(Property);
} while (Property.GetName() != "None" && stream.good() && stream.tellg() < maxOffset);
PropertySize = (unsigned)stream.tellg() - (unsigned)PropertyOffset;
return ss.str();
}

std::string UDefaultProperty::Deserialize(std::istream& stream, UPKInfo& info, size_t maxOffset)
std::string UDefaultProperty::Deserialize(std::istream& stream, UPKInfo& info, UObjectReference owner, bool unsafe, bool quick)
{
Init(owner, unsafe, quick);
size_t maxOffset = info.GetExportEntry(owner).SerialOffset + info.GetExportEntry(owner).SerialSize;
std::ostringstream ss;
ss << "UDefaultProperty:\n";
stream.read(reinterpret_cast<char*>(&NameIdx), sizeof(NameIdx));
Name = info.IndexToName(NameIdx);
ss << "\tNameIdx: " << FormatHEX(NameIdx) << " -> " << info.IndexToName(NameIdx) << std::endl;
Expand Down Expand Up @@ -52,13 +54,18 @@ std::string UDefaultProperty::Deserialize(std::istream& stream, UPKInfo& info, s
{
stream.read(reinterpret_cast<char*>(&InnerNameIdx), sizeof(InnerNameIdx));
ss << "\tInnerNameIdx: " << FormatHEX(InnerNameIdx) << " -> " << info.IndexToName(InnerNameIdx) << std::endl;
if (Type == "StructProperty")
Type = info.IndexToName(InnerNameIdx);
}
if (PropertySize > 0)
{
size_t offset = stream.tellg();
stream.read(InnerValue.data(), InnerValue.size());
stream.seekg(offset);
ss << DeserializeValue(stream, info);
if (QuickMode == false)
{
stream.seekg(offset);
ss << DeserializeValue(stream, info);
}
}
}
return ss.str();
Expand All @@ -69,9 +76,9 @@ std::string UDefaultProperty::DeserializeValue(std::istream& stream, UPKInfo& in
std::ostringstream ss;
if (Type == "IntProperty")
{
uint32_t value;
int32_t value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
ss << "\tInteger: " << FormatHEX(value) << " = " << value << std::endl;
ss << "\tInteger: " << FormatHEX((uint32_t)value) << " = " << value << std::endl;
}
else if (Type == "FloatProperty")
{
Expand Down Expand Up @@ -110,38 +117,48 @@ std::string UDefaultProperty::DeserializeValue(std::istream& stream, UPKInfo& in
ss << "\tString = " << str << std::endl;
}
}
//else if (Type == "StructProperty")
//{
// UDefaultProperty StructProperty;
// StructProperty.OwnerRef = 0; /// stub!!!
// ss << std::endl << StructProperty.Deserialize(stream, info);
//}
else if (Type == "ArrayProperty")
{
uint32_t NumElements;
stream.read(reinterpret_cast<char*>(&NumElements), sizeof(NumElements));
ss << "\tNumElements = " << FormatHEX(NumElements) << " = " << NumElements << std::endl;
if ((NumElements > 0) && (PropertySize > 4))
{
std::string ArrayInnerType = FindArrayType(info.IndexToName(NameIdx), stream, info);
//if (ArrayInnerType == "None")
//{
// ArrayInnerType = GuessArrayType(info.IndexToName(NameIdx));
//}
std::string ArrayInnerType = FindArrayType(Name, stream, info);
if (TryUnsafe == true && ArrayInnerType == "None")
{
ArrayInnerType = GuessArrayType(Name);
if (ArrayInnerType != "None")
ss << "\tUnsafe type guess:\n";
}
ss << "\tArrayInnerType = " << ArrayInnerType << std::endl;
UDefaultProperty InnerProperty;
InnerProperty.OwnerRef = 0; /// stub!!!
InnerProperty.OwnerRef = OwnerRef;
InnerProperty.TryUnsafe = TryUnsafe;
InnerProperty.Type = ArrayInnerType;
InnerProperty.PropertySize = PropertySize - 4;
if (ArrayInnerType == "None")
{
ss << InnerProperty.DeserializeValue(stream, info);
if (TryUnsafe == true && InnerProperty.PropertySize/NumElements <= 24)
{
InnerProperty.PropertySize /= NumElements;
for (unsigned i = 0; i < NumElements; ++i)
{
ss << "\t" << Name << "[" << i << "]:\n";
ss << InnerProperty.DeserializeValue(stream, info);
}
}
else
{
ss << InnerProperty.DeserializeValue(stream, info);
}
}
else
{
InnerProperty.PropertySize /= NumElements;
for (unsigned i = 0; i < NumElements; ++i)
{
ss << "\t" << info.IndexToName(NameIdx) << "[" << i << "]: ";
ss << "\t" << Name << "[" << i << "]:\n";
ss << InnerProperty.DeserializeValue(stream, info);
}
}
Expand Down Expand Up @@ -176,10 +193,35 @@ std::string UDefaultProperty::DeserializeValue(std::istream& stream, UPKInfo& in
<< FormatHEX((uint32_t)X) << ", " << FormatHEX((uint32_t)Y) << ") = ("
<< X << ", " << Y << ")" << std::endl;
}
/// if it is big, it might be inner property list
else if(TryUnsafe == true && PropertySize > 24)
{
UDefaultPropertiesList SomeProperties;
ss << "Unsafe guess (it's a Property List):\n" << SomeProperties.Deserialize(stream, info, OwnerRef, true, false);
}
/// if it is small, it might be NameIndex
else if(TryUnsafe == true && PropertySize == 8)
{
UNameIndex value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
ss << "\tUnsafe guess:\n";
ss << "\tName: " << FormatHEX(value) << " = " << info.IndexToName(value) << std::endl;
}
/// if it is even smaller, it might be integer (or float) or object reference
else if(TryUnsafe == true && PropertySize == 4)
{
int32_t value;
stream.read(reinterpret_cast<char*>(&value), sizeof(value));
ss << "\tUnsafe guess: "
<< "It's an Integer: " << FormatHEX((uint32_t)value) << " = " << value
<< " or a Reference: " << FormatHEX((uint32_t)value) << " -> " << info.ObjRefToName(value) << std::endl;
}
else
{
stream.seekg(PropertySize, std::ios::cur);
ss << "\tUnknown property!\n";
//stream.seekg(PropertySize, std::ios::cur);
std::vector<char> unk(PropertySize);
stream.read(unk.data(), unk.size());
ss << "\tUnknown property: " << FormatHEX(unk) << std::endl;
}
return ss.str();
}
Expand All @@ -196,15 +238,19 @@ std::string UDefaultProperty::FindArrayType(std::string ArrName, std::istream& s
OwnerName = OwnerName.substr(pos + 9);
}
std::string FullName = OwnerName + "." + ArrName;
UObjectReference ObjRef = info.FindObject(FullName, true);
UObjectReference ObjRef = info.FindObject(FullName);
if (ObjRef <= 0)
return "None";
FObjectExport ArrayEntry = info.GetExportEntry(ObjRef);
if (ArrayEntry.Type == "ArrayProperty")
{
size_t StreamPos = stream.tellg();
UArrayProperty ArrProperty;
size_t StreamPos = stream.tellg();
stream.seekg(ArrayEntry.SerialOffset);
/// quick-deserialize property, as we need only it's inner type info
ArrProperty.SetRef(ObjRef);
ArrProperty.SetUnsafe(false);
ArrProperty.SetQuickMode(true);
ArrProperty.Deserialize(stream, info);
stream.seekg(StreamPos);
if (ArrProperty.GetInner() <= 0)
Expand Down Expand Up @@ -244,13 +290,12 @@ std::string UObject::Deserialize(std::istream& stream, UPKInfo& info)
ss << "\tPrevObjRef = " << FormatHEX((uint32_t)ObjRef) << " -> " << info.ObjRefToName(ObjRef) << std::endl;
if (Type != GlobalType::UClass)
{
/*FObjectExport ThisTableEntry = info.GetExportEntry(ThisRef);
if (ThisRef > 0 && (ThisTableEntry.ObjectFlagsL & (uint32_t)UObjectFlagsL::HasStack))
FObjectExport ThisTableEntry = info.GetExportEntry(ThisRef);
if (TryUnsafe == true && ThisRef > 0 && (ThisTableEntry.ObjectFlagsL & (uint32_t)UObjectFlagsL::HasStack))
{
stream.seekg(22, std::ios::cur);
}*/
DefaultProperties.SetOwner(ThisRef);
ss << DefaultProperties.Deserialize(stream, info);
}
ss << DefaultProperties.Deserialize(stream, info, ThisRef, TryUnsafe, QuickMode);
}
return ss.str();
}
Expand Down Expand Up @@ -350,8 +395,7 @@ std::string UScriptStruct::Deserialize(std::istream& stream, UPKInfo& info)
stream.read(reinterpret_cast<char*>(&StructFlags), sizeof(StructFlags));
ss << "\tStructFlags = " << FormatHEX(StructFlags) << std::endl;
ss << FormatStructFlags(StructFlags);
StructDefaultProperties.SetOwner(ThisRef);
ss << StructDefaultProperties.Deserialize(stream, info);
ss << StructDefaultProperties.Deserialize(stream, info, ThisRef, TryUnsafe, QuickMode);
ScriptStructSize = (unsigned)stream.tellg() - (unsigned)ScriptStructOffset;
return ss.str();
}
Expand Down Expand Up @@ -700,7 +744,8 @@ std::string UObjectUnknown::Deserialize(std::istream& stream, UPKInfo& info)
{
std::ostringstream ss;
/// to be on a safe side: don't deserialize unknown objects
//ss << UObject::Deserialize(stream, info);
if (TryUnsafe == true)
ss << UObject::Deserialize(stream, info);
ss << "UObjectUnknown:\n";
ss << "\tObject unknown, can't deserialize!\n";
return ss.str();
Expand Down
24 changes: 13 additions & 11 deletions UObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,10 @@ enum class GlobalType
class UDefaultProperty
{
public:
UDefaultProperty(): OwnerRef(0) {}
UDefaultProperty(): Name("None"), Type("None"), OwnerRef(0), TryUnsafe(0), QuickMode(0) {}
~UDefaultProperty() {}
std::string Deserialize(std::istream& stream, UPKInfo& info, size_t maxOffset);
std::string Format(std::istream& stream, UPKInfo& info);
void SetOwner(UObjectReference Owner) { OwnerRef = Owner; }
std::string Deserialize(std::istream& stream, UPKInfo& info, UObjectReference owner, bool unsafe = false, bool quick = false);
void Init(UObjectReference owner, bool unsafe = false, bool quick = false) { OwnerRef = owner; TryUnsafe = unsafe; QuickMode = quick; }
std::string GetName() { return Name; }
std::string DeserializeValue(std::istream& stream, UPKInfo& info);
std::string FindArrayType(std::string ArrName, std::istream& stream, UPKInfo& info);
Expand All @@ -63,22 +62,21 @@ class UDefaultProperty
UNameIndex InnerNameIdx; /// for StructProperty and ByteProperty only
std::vector<char> InnerValue;
/// memory
UObjectReference OwnerRef;
std::string Name;
std::string Type;
UObjectReference OwnerRef;
bool TryUnsafe;
bool QuickMode;
};

class UDefaultPropertiesList
{
public:
UDefaultPropertiesList(): OwnerRef(0) {}
UDefaultPropertiesList() {}
~UDefaultPropertiesList() {}
UDefaultPropertiesList(UObjectReference owner): OwnerRef(owner) {}
void SetOwner(UObjectReference owner) { OwnerRef = owner; }
std::string Deserialize(std::istream& stream, UPKInfo& info);
std::string Deserialize(std::istream& stream, UPKInfo& info, UObjectReference owner, bool unsafe = false, bool quick = false);
protected:
std::vector<UDefaultProperty> DefaultProperties;
UObjectReference OwnerRef;
size_t PropertyOffset;
size_t PropertySize;
};
Expand All @@ -87,10 +85,12 @@ class UDefaultPropertiesList
class UObject
{
public:
UObject(): Type(GlobalType::UObject), ThisRef(0), FlagsOffset(0) {}
UObject(): Type(GlobalType::UObject), ThisRef(0), FlagsOffset(0), TryUnsafe(0), QuickMode(0) {}
virtual ~UObject() {}
virtual std::string Deserialize(std::istream& stream, UPKInfo& info);
void SetRef(UObjectReference thisRef) { ThisRef = thisRef; }
void SetUnsafe(bool val) { TryUnsafe = val; }
void SetQuickMode(bool val) { QuickMode = val; }
virtual bool IsStructure() { return false; }
virtual bool IsProperty() { return false; }
virtual bool IsState() { return false; }
Expand All @@ -102,6 +102,8 @@ class UObject
GlobalType Type;
UObjectReference ThisRef;
size_t FlagsOffset;
bool TryUnsafe;
bool QuickMode;
};

class UObjectNone: public UObject
Expand Down
21 changes: 21 additions & 0 deletions UPKInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,27 @@ UObjectReference UPKInfo::FindObject(std::string FullName, bool isExport)
return 0;
}

UObjectReference UPKInfo::FindObjectByName(std::string Name, bool isExport)
{
/// Import object
if (isExport == false)
{
for (unsigned i = 1; i < ImportTable.size(); ++i)
{
if (ImportTable[i].Name == Name)
return -i;
}
}
/// Export object
for (unsigned i = 1; i < ExportTable.size(); ++i)
{
if (ExportTable[i].Name == Name)
return i;
}
/// Object not found
return 0;
}

const FObjectExport& UPKInfo::GetExportEntry(uint32_t idx)
{
if (idx < ExportTable.size())
Expand Down
1 change: 1 addition & 0 deletions UPKInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class UPKInfo
UObjectReference GetOwnerRef(UObjectReference ObjRef);
int FindName(std::string name);
UObjectReference FindObject(std::string FullName, bool isExport = true);
UObjectReference FindObjectByName(std::string Name, bool isExport = true);
bool IsNoneIdx(UNameIndex idx) { return (idx.NameTableIdx == NoneIdx); }
/// Getters
const FObjectExport& GetExportEntry(uint32_t idx);
Expand Down
4 changes: 3 additions & 1 deletion UPKUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ bool UPKUtils::UndoMoveResizeObject(uint32_t idx)
return UndoMoveExportData(idx);
}

std::string UPKUtils::Deserialize(UObjectReference ObjRef)
std::string UPKUtils::Deserialize(UObjectReference ObjRef, bool TryUnsafe, bool QuickMode)
{
if (ObjRef < 1 || ObjRef >= (int)ExportTable.size())
return "Bad object reference!\n";
Expand All @@ -205,6 +205,8 @@ std::string UPKUtils::Deserialize(UObjectReference ObjRef)
std::string res;
UPKFile.seekg(ExportTable[ObjRef].SerialOffset);
Obj->SetRef(ObjRef);
Obj->SetUnsafe(TryUnsafe);
Obj->SetQuickMode(QuickMode);
res = Obj->Deserialize(UPKFile, *dynamic_cast<UPKInfo*>(this));
delete Obj;
return res;
Expand Down
2 changes: 1 addition & 1 deletion UPKUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class UPKUtils: public UPKInfo
bool MoveResizeObject(uint32_t idx, int newObjectSize = -1);
bool UndoMoveResizeObject(uint32_t idx);
/// Deserialize
std::string Deserialize(UObjectReference ObjRef);
std::string Deserialize(UObjectReference ObjRef, bool TryUnsafe = false, bool QuickMode = false);
/// Write data
bool CheckValidFileOffset(size_t offset);
bool CheckValidRelOffset(size_t relOffset, UPKScope scope = UPKScope::Package, uint32_t idx = 0);
Expand Down

0 comments on commit a2d8de6

Please sign in to comment.