1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include <Dumper.h> // Moved to the top because AssetSerializer requires include for the SerializeContext
- #include <AzCore/Asset/AssetManager.h>
- #include <AzCore/Asset/AssetSerializer.h>
- #include <AzCore/Asset/AssetManagerBus.h>
- #include <AzFramework/Helpers/AssetHelpers.h>
- #include <AzCore/Casting/lossy_cast.h>
- #include <AzCore/Debug/Trace.h>
- #include <AzCore/IO/FileIO.h>
- #include <AzCore/IO/GenericStreams.h>
- #include <AzCore/IO/Path/Path.h>
- #include <AzCore/IO/SystemFile.h>
- #include <AzCore/JSON/stringbuffer.h>
- #include <AzCore/JSON/pointer.h>
- #include <AzCore/JSON/prettywriter.h>
- #include <AzCore/Serialization/EditContext.h>
- #include <AzCore/Serialization/Json/JsonSerialization.h>
- #include <AzCore/Serialization/Json/JsonSerializationSettings.h>
- #include <AzCore/Settings/TextParser.h>
- #include <AzCore/Settings/SettingsRegistryMergeUtils.h>
- #include <AzCore/std/algorithm.h>
- #include <AzCore/std/sort.h>
- #include <AzCore/StringFunc/StringFunc.h>
- #include <AzCore/Utils/Utils.h>
- #include <Application.h>
- #include <Utilities.h>
- #include <AzFramework/Asset/AssetSystemBus.h>
- namespace AZ::SerializeContextTools
- {
- inline namespace Streams
- {
- // Using an inline namespace for the Function Object Stream
- /*
- * Implementation of the GenericStream interface
- * that uses a function object for writing
- */
- class FunctorStream
- : public AZ::IO::GenericStream
- {
- public:
- using WriteCallback = AZStd::function<AZ::IO::SizeType(AZStd::span<AZStd::byte const>)>;
- FunctorStream() = default;
- FunctorStream(WriteCallback writeCallback);
- bool IsOpen() const override;
- bool CanSeek() const override;
- bool CanRead() const override;
- bool CanWrite() const override;
- void Seek(AZ::IO::OffsetType, SeekMode) override;
- AZ::IO::SizeType Read(AZ::IO::SizeType, void*) override;
- AZ::IO::SizeType Write(AZ::IO::SizeType bytes, const void* iBuffer) override;
- AZ::IO::SizeType GetCurPos() const override;
- AZ::IO::SizeType GetLength() const override;
- AZ::IO::OpenMode GetModeFlags() const override;
- const char* GetFilename() const override;
- private:
- WriteCallback m_streamWriter;
- };
- FunctorStream::FunctorStream(WriteCallback writeCallback)
- : m_streamWriter { AZStd::move(writeCallback)}
- {}
- bool FunctorStream::IsOpen() const
- {
- return static_cast<bool>(m_streamWriter);
- }
- bool FunctorStream::CanSeek() const
- {
- return false;
- }
- bool FunctorStream::CanRead() const
- {
- return false;
- }
- bool FunctorStream::CanWrite() const
- {
- return true;
- }
- void FunctorStream::Seek(AZ::IO::OffsetType, SeekMode)
- {
- AZ_Assert(false, "Cannot seek in stdout stream");
- }
- AZ::IO::SizeType FunctorStream::Read(AZ::IO::SizeType, void*)
- {
- AZ_Assert(false, "The stdout file handle cannot be read from");
- return 0;
- }
- AZ::IO::SizeType FunctorStream::Write(AZ::IO::SizeType bytes, const void* iBuffer)
- {
- if (m_streamWriter)
- {
- return m_streamWriter(AZStd::span(reinterpret_cast<const AZStd::byte*>(iBuffer), bytes));
- }
- return 0;
- }
- AZ::IO::SizeType FunctorStream::GetCurPos() const
- {
- return 0;
- }
- AZ::IO::SizeType FunctorStream::GetLength() const
- {
- return 0;
- }
- AZ::IO::OpenMode FunctorStream::GetModeFlags() const
- {
- return AZ::IO::OpenMode::ModeWrite;
- }
- const char* FunctorStream::GetFilename() const
- {
- return "<function object>";
- }
- }
- } // namespace AZ::SerializeContextTools::inline Stream
- namespace AZ::SerializeContextTools
- {
- static auto GetWriteBypassStdoutCapturerFunctor(Application& application)
- {
- return [&application](AZStd::span<AZStd::byte const> outputBytes)
- {
- // If the application is currently capturing stdout, use stdout capturer to write
- // directly to the file descriptor of stdout
- if (AZ::IO::FileDescriptorCapturer* stdoutCapturer = application.GetStdoutCapturer();
- stdoutCapturer != nullptr)
- {
- return stdoutCapturer->WriteBypassingCapture(outputBytes.data(), aznumeric_caster(outputBytes.size()));
- }
- else
- {
- constexpr int StdoutDescriptor = 1;
- return AZ::IO::PosixInternal::Write(StdoutDescriptor, outputBytes.data(), aznumeric_caster(outputBytes.size()));
- }
- };
- }
- const char* CleanupRelativePath(const char* path)
- {
- if (!path)
- {
- AZ_Assert(path, "(SerializeContextTools) - CleanupRelativePath(nullptr)!");
- }
- else
- {
- while (*path == '.' || *path == '/' || *path == '\\') // remove leading slashes in relative paths
- {
- ++path;
- }
- AZ_Warning("SerializeContextTools", *path, "CleanupRelativePath(path) Evaluates to empty path!");
- }
- return path;
- }
- bool Dumper::CreateDependencyList(Application& application)
- {
- SerializeContext* sc = application.GetSerializeContext();
- if (!sc)
- {
- AZ_Error("SerializeContextTools", false, "No serialize context found.");
- return false;
- }
- AZStd::string outputFolder = Utilities::ReadOutputTargetFromCommandLine(application);
- AZ::IO::Path sourceGameFolder;
- if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
- {
- settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
- }
- bool result = true;
- AZStd::vector<AZStd::string> fileList = Utilities::ReadFileListFromCommandLine(application, "files");
- for (const AZStd::string& filePath : fileList)
- {
- AZ::IO::FixedMaxPath outputPath{ AZStd::string_view{ outputFolder } };
- outputPath /= AZ::IO::PathView{ filePath }.Filename();
- outputPath.Native() += ".json";
- rapidjson::Document doc;
- rapidjson::Value& root = doc.SetObject();
- rapidjson::Value scObject;
- scObject.SetArray();
- IO::SystemFile outputFile;
- if (!outputFile.Open(outputPath.c_str(), IO::SystemFile::OpenMode::SF_OPEN_CREATE | IO::SystemFile::OpenMode::SF_OPEN_CREATE_PATH |
- IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY))
- {
- AZ_Error("SerializeContextTools", false, "Unable to open file '%s' for writing.", outputPath.c_str());
- result = false;
- continue;
- }
- auto relativePath = CleanupRelativePath(filePath.c_str());
- AZ::Data::AssetId assetId;
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetId, &AZ::Data::AssetCatalogRequestBus::Events::GetAssetIdByPath, relativePath, AZ::AzTypeInfo<AZ::DynamicSliceAsset>::Uuid(), false);
- AZStd::vector<AZ::Data::AssetInfo> dependencyInfoList;
- Outcome<AZStd::vector<AZ::Data::ProductDependency>, AZStd::string> dependenciesResult = Failure(AZStd::string());
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(dependenciesResult, &AZ::Data::AssetCatalogRequestBus::Events::GetAllProductDependencies, assetId);
- for (const auto& ass : dependenciesResult.GetValue())
- {
- AZStd::string assetPath;
- AZ::Data::AssetCatalogRequestBus::BroadcastResult(assetPath, &AZ::Data::AssetCatalogRequests::GetAssetPathById, ass.m_assetId);
- if (!assetPath.empty())
- {
- rapidjson::Value str(rapidjson::kStringType);
- str.SetString(assetPath.c_str(), doc.GetAllocator());
- scObject.PushBack(AZStd::move(str), doc.GetAllocator());
- }
- }
- root.AddMember("assets", AZStd::move(scObject), doc.GetAllocator());
- rapidjson::StringBuffer buffer;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
- doc.Accept(writer);
- outputFile.Write(buffer.GetString(), buffer.GetSize());
- outputFile.Close();
- }
- return result;
- }
- bool Dumper::DumpFiles(Application& application)
- {
- SerializeContext* sc = application.GetSerializeContext();
- if (!sc)
- {
- AZ_Error("SerializeContextTools", false, "No serialize context found.");
- return false;
- }
- AZStd::string outputFolder = Utilities::ReadOutputTargetFromCommandLine(application);
- AZ::IO::Path sourceGameFolder;
- if (auto settingsRegistry = AZ::SettingsRegistry::Get(); settingsRegistry != nullptr)
- {
- settingsRegistry->Get(sourceGameFolder.Native(), AZ::SettingsRegistryMergeUtils::FilePathKey_ProjectPath);
- }
- bool result = true;
- AZStd::vector<AZStd::string> fileList = Utilities::ReadFileListFromCommandLine(application, "files");
- for (const AZStd::string& filePath : fileList)
- {
- AZ_Printf("DumpFiles", "Dumping file '%.*s'\n", aznumeric_cast<int>(filePath.size()), filePath.data());
- AZ::IO::FixedMaxPath outputPath{ AZStd::string_view{ outputFolder }};
- outputPath /= AZ::IO::FixedMaxPath(filePath).LexicallyRelative(sourceGameFolder);
- outputPath.Native() += ".dump.txt";
- IO::SystemFile outputFile;
- if (!outputFile.Open(outputPath.c_str(),
- IO::SystemFile::OpenMode::SF_OPEN_CREATE |
- IO::SystemFile::OpenMode::SF_OPEN_CREATE_PATH |
- IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY))
- {
- AZ_Error("SerializeContextTools", false, "Unable to open file '%s' for writing.", outputPath.c_str());
- result = false;
- continue;
- }
- AZStd::string content;
- content.reserve(1 * 1024 * 1024); // Reserve 1mb to avoid frequently resizing the string.
- auto callback = [&content, &result](void* classPtr, const Uuid& classId, SerializeContext* context)
- {
- result = DumpClassContent(content, classPtr, classId, context) && result;
- const SerializeContext::ClassData* classData = context->FindClassData(classId);
- if (classData && classData->m_factory)
- {
- classData->m_factory->Destroy(classPtr);
- }
- else
- {
- AZ_Error("SerializeContextTools", false, "Missing class factory, so data will leak.");
- result = false;
- }
- };
- if (!Utilities::InspectSerializedFile(filePath.c_str(), sc, callback))
- {
- result = false;
- continue;
- }
- outputFile.Write(content.data(), content.length());
- }
- return result;
- }
- bool Dumper::DumpSerializeContext(Application& application)
- {
- AZStd::string outputPath = Utilities::ReadOutputTargetFromCommandLine(application, "SerializeContext.json");
- AZ_Printf("dumpsc", "Writing Serialize Context at '%s'.\n", outputPath.c_str());
- IO::SystemFile outputFile;
- if (!outputFile.Open(outputPath.c_str(),
- IO::SystemFile::OpenMode::SF_OPEN_CREATE |
- IO::SystemFile::OpenMode::SF_OPEN_CREATE_PATH |
- IO::SystemFile::OpenMode::SF_OPEN_WRITE_ONLY))
- {
- AZ_Error("SerializeContextTools", false, "Unable to open output file '%s'.", outputPath.c_str());
- return false;
- }
- SerializeContext* context = application.GetSerializeContext();
- AZStd::vector<Uuid> systemComponents = Utilities::GetSystemComponents(application);
- AZStd::sort(systemComponents.begin(), systemComponents.end());
- rapidjson::Document doc;
- rapidjson::Value& root = doc.SetObject();
- rapidjson::Value scObject;
- scObject.SetObject();
- AZStd::string temp;
- temp.reserve(256 * 1024); // Reserve 256kb of memory to avoid the string constantly resizing.
- bool result = true;
- auto callback = [context, &doc, &scObject, &temp, &systemComponents, &result](const SerializeContext::ClassData* classData, const Uuid& /*typeId*/) -> bool
- {
- if (!DumpClassContent(classData, scObject, doc, systemComponents, context, temp))
- {
- result = false;
- }
- return true;
- };
- context->EnumerateAll(callback, true);
- root.AddMember("SerializeContext", AZStd::move(scObject), doc.GetAllocator());
- rapidjson::StringBuffer buffer;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
- doc.Accept(writer);
- outputFile.Write(buffer.GetString(), buffer.GetSize());
- outputFile.Close();
- return result;
- }
- bool Dumper::DumpTypes(Application& application)
- {
- // outputStream defaults to writing to stdout
- AZStd::variant<FunctorStream, AZ::IO::SystemFileStream> outputStream(AZStd::in_place_type<FunctorStream>,
- GetWriteBypassStdoutCapturerFunctor(application));
- AZ::CommandLine& commandLine = *application.GetAzCommandLine();
- // If the output-file parameter has been supplied open the file path using FileIOStream
- if (size_t optionCount = commandLine.GetNumSwitchValues("output-file"); optionCount > 0)
- {
- AZ::IO::PathView outputPathView(commandLine.GetSwitchValue("output-file", optionCount - 1));
- // If the output file name is a single dash, use the default output stream value which writes to stdout
- if (outputPathView != "-")
- {
- AZ::IO::FixedMaxPath outputPath;
- if (outputPathView.IsRelative())
- {
- AZ::Utils::ConvertToAbsolutePath(outputPath, outputPathView.Native());
- }
- else
- {
- outputPath = outputPathView.LexicallyNormal();
- }
- constexpr AZ::IO::OpenMode openMode = AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath;
- if (auto& fileStream = outputStream.emplace<AZ::IO::SystemFileStream>(outputPath.c_str(), openMode);
- !fileStream.IsOpen())
- {
- AZ_Printf(
- "dumptypes",
- R"(Unable to open specified output-file "%s". Object will not be dumped)"
- "\n",
- outputPath.c_str());
- return false;
- }
- }
- }
- AZ::SerializeContext* context = application.GetSerializeContext();
- struct TypeNameIdPair
- {
- AZStd::string m_name;
- AZ::TypeId m_id;
- bool operator==(const TypeNameIdPair& other) const
- {
- return m_name == other.m_name && m_id == other.m_id;
- }
- bool operator!=(const TypeNameIdPair& other) const
- {
- return !operator==(other);
- }
- struct Hash
- {
- size_t operator()(const TypeNameIdPair& key) const
- {
- size_t hashValue{};
- AZStd::hash_combine(hashValue, key.m_name);
- AZStd::hash_combine(hashValue, key.m_id);
- return hashValue;
- }
- };
- };
- // Append the Type names and type ids to a unordered_set to filter out duplicates
- AZStd::unordered_set<TypeNameIdPair, TypeNameIdPair::Hash> typeNameIdPairsSet;
- auto AppendTypeInfo = [&typeNameIdPairsSet](const SerializeContext::ClassData* classData, const Uuid&) -> bool
- {
- typeNameIdPairsSet.emplace(TypeNameIdPair{ classData->m_name, classData->m_typeId });
- return true;
- };
- context->EnumerateAll(AppendTypeInfo, true);
- // Move over the unordered set over to an array for later
- // The array is potentially sorted depending on the sort option
- AZStd::vector<TypeNameIdPair> typeNameIdPairs(
- AZStd::make_move_iterator(typeNameIdPairsSet.begin()),
- AZStd::make_move_iterator(typeNameIdPairsSet.end())
- );
- // Clear out the Unordered set container
- typeNameIdPairsSet = {};
- // Sort the TypeNameIdPair based on the --sort option value or by type name if not supplied
- enum class SortOptions
- {
- Name,
- TypeId,
- None
- };
- SortOptions sortOption{ SortOptions::Name };
- if (size_t sortOptionCount = commandLine.GetNumSwitchValues("sort"); sortOptionCount > 0)
- {
- AZStd::string sortOptionString = commandLine.GetSwitchValue("sort", sortOptionCount - 1);
- if (sortOptionString == "name")
- {
- sortOption = SortOptions::Name;
- }
- if (sortOptionString == "typeid")
- {
- sortOption = SortOptions::TypeId;
- }
- else if (sortOptionString == "none")
- {
- sortOption = SortOptions::None;
- }
- else
- {
- AZ_Error(
- "dumptypes", false,
- R"(Invalid --sort option supplied "%s".)"
- " Sorting by type name will be used. See --help for valid values)",
- sortOptionString.c_str());
- }
- }
- switch (sortOption)
- {
- case SortOptions::Name:
- {
- auto SortByName = [](const TypeNameIdPair& lhs, const TypeNameIdPair& rhs)
- {
- return azstricmp(lhs.m_name.c_str(), rhs.m_name.c_str()) < 0;
- };
- AZStd::sort(typeNameIdPairs.begin(), typeNameIdPairs.end(), SortByName);
- break;
- }
- case SortOptions::TypeId:
- {
- auto SortByTypeId = [](const TypeNameIdPair& lhs, const TypeNameIdPair& rhs)
- {
- return lhs.m_id < rhs.m_id;
- };
- AZStd::sort(typeNameIdPairs.begin(), typeNameIdPairs.end(), SortByTypeId);
- break;
- }
- case SortOptions::None:
- [[fallthrough]];
- default:
- break;
- }
- auto GetOutputPathString = [](auto&& stream) -> const char*
- {
- return stream.GetFilename();
- };
- AZ_Printf(
- "dumptypes",
- R"(Writing reflected types to "%s".)"
- "\n",
- AZStd::visit(GetOutputPathString, outputStream));
- auto WriteReflectedTypes = [&typeNameIdPairs](auto&& stream) -> bool
- {
- AZStd::string typeListContents;
- for (auto&& [typeName, typeId] : typeNameIdPairs)
- {
- typeListContents += AZStd::string::format("%s %s\n", typeName.c_str(), typeId.ToFixedString().c_str());
- }
- stream.Write(typeListContents.size(), typeListContents.data());
- stream.Close();
- return true;
- };
- const bool result = AZStd::visit(WriteReflectedTypes, outputStream);
- return result;
- }
- bool Dumper::CreateType(Application& application)
- {
- // outputStream defaults to writing to stdout
- AZStd::variant<FunctorStream, AZ::IO::SystemFileStream> outputStream(AZStd::in_place_type<FunctorStream>,
- GetWriteBypassStdoutCapturerFunctor(application));
- AZ::CommandLine& commandLine = *application.GetAzCommandLine();
- // If the output-file parameter has been supplied open the file path using FileIOStream
- if (size_t optionCount = commandLine.GetNumSwitchValues("output-file"); optionCount > 0)
- {
- AZ::IO::PathView outputPathView(commandLine.GetSwitchValue("output-file", optionCount - 1));
- // If the output file name is a single dash, use the default output stream value which writes to stdout
- if (outputPathView != "-")
- {
- AZ::IO::FixedMaxPath outputPath;
- if (outputPathView.IsRelative())
- {
- AZ::Utils::ConvertToAbsolutePath(outputPath, outputPathView.Native());
- }
- else
- {
- outputPath = outputPathView.LexicallyNormal();
- }
- constexpr AZ::IO::OpenMode openMode = AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath;
- if (auto& fileStream = outputStream.emplace<AZ::IO::SystemFileStream>(outputPath.c_str(), openMode);
- !fileStream.IsOpen())
- {
- AZ_Printf(
- "createtype",
- R"(Unable to open specified output-file "%s". Object will not be dumped)"
- "\n",
- outputPath.c_str());
- return false;
- }
- }
- }
- size_t typeIdOptionCount = commandLine.GetNumSwitchValues("type-id");
- size_t typeNameOptionCount = commandLine.GetNumSwitchValues("type-name");
- if (typeIdOptionCount == 0 && typeNameOptionCount == 0)
- {
- AZ_Error("createtype", false, "One of the following options must be supplied: --type-id or --type-name");
- return false;
- }
- if (typeIdOptionCount > 0 && typeNameOptionCount > 0)
- {
- AZ_Error("createtype", false, "The --type-id and --type-name options are mutally exclusive. Only one can be specified");
- return false;
- }
- AZ::SerializeContext* context = application.GetSerializeContext();
- const AZ::SerializeContext::ClassData* classData = nullptr;
- if (typeIdOptionCount > 0)
- {
- AZStd::string typeIdValue = commandLine.GetSwitchValue("type-id", typeIdOptionCount - 1);
- classData = context->FindClassData(AZ::TypeId(typeIdValue.c_str(), typeIdValue.size()));
- if (classData == nullptr)
- {
- AZ_Error("createtype", false, "Type with ID %s is not registered with the SerializeContext", typeIdValue.c_str());
- return false;
- }
- }
- else
- {
- AZStd::string typeNameValue = commandLine.GetSwitchValue("type-name", typeNameOptionCount - 1);
- AZStd::vector<AZ::TypeId> classIds = context->FindClassId(AZ::Crc32{ AZStd::string_view{ typeNameValue } });
- if (classIds.size() != 1)
- {
- if (classIds.empty())
- {
- AZ_Error("createtype", false, "Type with name %s is not registered with the SerializeContext", typeNameValue.c_str());
- }
- else
- {
- const char* prependComma = "";
- AZStd::string classIdString;
- for (const AZ::TypeId& classId : classIds)
- {
- classIdString += prependComma + classId.ToString<AZStd::string>();
- prependComma = ", ";
- }
- AZ_Error(
- "createtype", classIds.size() < 2,
- "Multiple types with name %s have been registered with the SerializeContext,\n"
- "In order to disambiguate which type to use, the --type-id argument must be supplied with one of the following "
- "Uuids:\n",
- "%s", typeNameValue.c_str(), classIdString.c_str());
- }
- return false;
- }
- // Only one class with this typename has been registered with the serialize context, so look up its ClassData
- classData = context->FindClassData(classIds.front());
- }
- // Create a rapidjson document to store the default constructed object
- const AZStd::any typeInst = context->CreateAny(classData->m_typeId);
- rapidjson::Document document;
- rapidjson::Value& root = document.SetObject();
- AZ::JsonSerializerSettings serializerSettings;
- serializerSettings.m_serializeContext = context;
- serializerSettings.m_registrationContext = application.GetJsonRegistrationContext();
- serializerSettings.m_keepDefaults = true;
- using JsonResultCode = AZ::JsonSerializationResult::ResultCode;
- const JsonResultCode parseResult = AZ::JsonSerialization::Store(
- root, document.GetAllocator(), AZStd::any_cast<void>(&typeInst), nullptr, typeInst.type(), serializerSettings);
- if (parseResult.GetProcessing() == AZ::JsonSerializationResult::Processing::Halted)
- {
- AZ_Printf("createtype", " Failed to store type %s in JSON format.\n", classData->m_name);
- return false;
- }
- auto GetOutputPathString = [](auto&& stream)
- {
- using StreamType = AZStd::remove_cvref_t<decltype(stream)>;
- if constexpr (AZStd::is_same_v<StreamType, AZ::IO::StdoutStream>)
- {
- return AZ::IO::FixedMaxPath{ "<stdout>" };
- }
- else if (AZStd::is_same_v<StreamType, AZ::IO::FileIOStream>)
- {
- return AZ::IO::FixedMaxPath{ stream.GetFilename() };
- }
- else
- {
- AZ_Assert(false, "OutputStream has invalid stream type. It must be StdoutStream or FileIOStream");
- return AZ::IO::FixedMaxPath{};
- }
- };
- AZ_Printf(
- "createtype",
- R"(Writing Type "%s" to "%s" using Json Serialization.)"
- "\n",
- classData->m_name, AZStd::visit(GetOutputPathString, outputStream).c_str());
- AZStd::string jsonDocumentRootPrefix;
- if (commandLine.HasSwitch("json-prefix"))
- {
- jsonDocumentRootPrefix = commandLine.GetSwitchValue("json-prefix", 0);
- }
- auto VisitStream = [&document, &jsonDocumentRootPrefix](auto&& stream) -> bool
- {
- if (WriteDocumentToStream(stream, document, jsonDocumentRootPrefix))
- {
- // Write out a newline to the end of the stream
- constexpr AZStd::string_view newline = "\n";
- stream.Write(newline.size(), newline.data());
- return true;
- }
- return false;
- };
- const bool result = AZStd::visit(VisitStream, outputStream);
- return result;
- }
- bool Dumper::CreateUuid(Application& application)
- {
- // outputStream defaults to writing to stdout
- AZStd::variant<FunctorStream, AZ::IO::SystemFileStream> outputStream(AZStd::in_place_type<FunctorStream>,
- GetWriteBypassStdoutCapturerFunctor(application));
- AZ::CommandLine& commandLine = *application.GetAzCommandLine();
- // If the output-file parameter has been supplied open the file path using FileIOStream
- if (size_t optionCount = commandLine.GetNumSwitchValues("output-file"); optionCount > 0)
- {
- AZ::IO::PathView outputPathView(commandLine.GetSwitchValue("output-file", optionCount - 1));
- // If the output file name is a single dash, use the default output stream value which writes to stdout
- if (outputPathView != "-")
- {
- AZ::IO::FixedMaxPath outputPath;
- if (outputPathView.IsRelative())
- {
- AZ::Utils::ConvertToAbsolutePath(outputPath, outputPathView.Native());
- }
- else
- {
- outputPath = outputPathView.LexicallyNormal();
- }
- constexpr AZ::IO::OpenMode openMode = AZ::IO::OpenMode::ModeWrite | AZ::IO::OpenMode::ModeCreatePath;
- if (auto& fileStream = outputStream.emplace<AZ::IO::SystemFileStream>(outputPath.c_str(), openMode);
- !fileStream.IsOpen())
- {
- AZ_Printf(
- "createuuid",
- R"(Unable to open specified output-file "%s". Uuid will not be output to stream)"
- "\n",
- outputPath.c_str());
- return false;
- }
- }
- }
- size_t valuesOptionCount = commandLine.GetNumSwitchValues("values");
- size_t valuesFileOptionCount = commandLine.GetNumSwitchValues("values-file");
- if (valuesOptionCount == 0 && valuesFileOptionCount == 0)
- {
- AZ_Error("createuuid", false, "One of following options must be supplied: --values or --values-file");
- return false;
- }
- bool withCurlyBraces = true;
- if (size_t withCurlyBracesOptionCount = commandLine.GetNumSwitchValues("with-curly-braces");
- withCurlyBracesOptionCount > 0)
- {
- withCurlyBraces = AZ::StringFunc::ToBool(commandLine.GetSwitchValue("with-curly-braces", withCurlyBracesOptionCount - 1).c_str());
- }
- bool withDashes = true;
- if (size_t withDashesOptionCount = commandLine.GetNumSwitchValues("with-dashes");
- withDashesOptionCount > 0)
- {
- withDashes = AZ::StringFunc::ToBool(commandLine.GetSwitchValue("with-dashes", withDashesOptionCount - 1).c_str());
- }
- const bool quietOutput = commandLine.HasSwitch("q") || commandLine.HasSwitch("quiet");
- bool result = true;
- struct UuidStringPair
- {
- AZ::Uuid m_uuid;
- AZStd::string m_value;
- };
- AZStd::vector<UuidStringPair> uuidsToWrite;
- for (size_t i = 0; i < valuesOptionCount; ++i)
- {
- AZStd::string value = commandLine.GetSwitchValue("values", i);
- auto uuidFromName = AZ::Uuid::CreateName(value);
- uuidsToWrite.push_back({ AZStd::move(uuidFromName), AZStd::move(value) });
- }
- // Read string values from each --values-file argument
- for (size_t i = 0; i < valuesFileOptionCount; ++i)
- {
- AZ::IO::FixedMaxPath inputValuePath(AZ::IO::PathView(commandLine.GetSwitchValue("values-file", i)));
- AZ::IO::SystemFileStream valuesFileStream;
- if (inputValuePath == "-")
- {
- // If the input file is dash read from stdin
- valuesFileStream = AZ::IO::SystemFileStream(AZ::IO::SystemFile::GetStdin());
- }
- else
- {
- // Open the path from the values-file option
- constexpr AZ::IO::OpenMode openMode = AZ::IO::OpenMode::ModeRead;
- valuesFileStream.Open(inputValuePath.c_str(), openMode);
- }
- if (valuesFileStream.IsOpen())
- {
- // Use the text parser to parse plain text lines
- AZ::Settings::TextParserSettings textParserSettings;
- textParserSettings.m_parseTextEntryFunc = [&uuidsToWrite](AZStd::string_view token)
- {
- // Remove leading and surrounding spaces and carriage returns
- token = AZ::StringFunc::StripEnds(token, " \r");
- auto uuidFromName = AZ::Uuid::CreateName(token);
- uuidsToWrite.push_back({ AZStd::move(uuidFromName), token });
- return true;
- };
- AZ::Settings::ParseTextFile(valuesFileStream, textParserSettings);
- }
- }
- for (const UuidStringPair& uuidStringPair : uuidsToWrite)
- {
- auto VisitStream = [&uuidToWrite = uuidStringPair.m_uuid, &value = uuidStringPair.m_value,
- withCurlyBraces, withDashes, quietOutput](auto&& stream) -> bool
- {
- AZStd::fixed_string<256> uuidString;
- if (quietOutput)
- {
- uuidString = AZStd::fixed_string<256>::format("%s\n",
- uuidToWrite.ToFixedString(withCurlyBraces, withDashes).c_str());
- }
- else
- {
- uuidString = AZStd::fixed_string<256>::format(R"(%s %s)" "\n",
- uuidToWrite.ToFixedString(withCurlyBraces, withDashes).c_str(),
- value.c_str());
- }
- size_t bytesWritten = stream.Write(uuidString.size(), uuidString.c_str());
- return bytesWritten == uuidString.size();
- };
- result = AZStd::visit(VisitStream, outputStream) && result;
- }
- return result;
- }
- AZStd::vector<Uuid> Dumper::CreateFilterListByNames(SerializeContext* context, AZStd::string_view name)
- {
- AZStd::vector<AZStd::string_view> names;
- auto AppendNames = [&names](AZStd::string_view filename)
- {
- names.emplace_back(filename);
- };
- AZ::StringFunc::TokenizeVisitor(name, AppendNames, ';');
- AZStd::vector<Uuid> filterIds;
- filterIds.reserve(names.size());
- for (const AZStd::string_view& singleName : names)
- {
- AZStd::vector<Uuid> foundFilters = context->FindClassId(Crc32(singleName.data(), singleName.length(), true));
- filterIds.insert(filterIds.end(), foundFilters.begin(), foundFilters.end());
- }
- return filterIds;
- }
- AZStd::string_view Dumper::ExtractNamespace(const AZStd::string& name)
- {
- size_t offset = 0;
- const char* startChar = name.data();
- const char* currentChar = name.data();
- while (*currentChar != 0 && *currentChar != '<')
- {
- if (*currentChar != ':')
- {
- ++currentChar;
- }
- else
- {
- ++currentChar;
- if (*currentChar == ':')
- {
- AZ_Assert(currentChar - startChar >= 1, "Offset out of bounds while trying to extract namespace from name '%s'.", name.c_str());
- offset = currentChar - startChar - 1; // -1 to exclude the last "::"
- }
- }
- }
- return AZStd::string_view(startChar, offset);
- }
- rapidjson::Value Dumper::WriteToJsonValue(const Uuid& uuid, rapidjson::Document& document)
- {
- char buffer[Uuid::MaxStringBuffer];
- int writtenCount = uuid.ToString(buffer, AZ_ARRAY_SIZE(buffer));
- if (writtenCount > 0)
- {
- return rapidjson::Value(buffer, writtenCount - 1, document.GetAllocator()); //-1 as the null character shouldn't be written.
- }
- else
- {
- return rapidjson::Value(rapidjson::StringRef("{uuid conversion failed}"));
- }
- }
- bool Dumper::DumpClassContent(const SerializeContext::ClassData* classData, rapidjson::Value& parent, rapidjson::Document& document,
- const AZStd::vector<Uuid>& systemComponents, SerializeContext* context, AZStd::string& scratchStringBuffer)
- {
- AZ_Assert(scratchStringBuffer.empty(), "Provided scratch string buffer wasn't empty.");
- rapidjson::Value classNode(rapidjson::kObjectType);
- DumpClassName(classNode, context, classData, document, scratchStringBuffer);
- Edit::ClassData* editData = classData->m_editData;
- GenericClassInfo* genericClassInfo = context->FindGenericClassInfo(classData->m_typeId);
- if (editData && editData->m_description)
- {
- AZStd::string_view description = editData->m_description;
- // Skipping if there's only one character as there are several cases where a blank description is given.
- if (description.size() > 1)
- {
- classNode.AddMember("Description", rapidjson::Value(description.data(), document.GetAllocator()), document.GetAllocator());
- }
- }
- classNode.AddMember("Id", rapidjson::StringRef(classData->m_name), document.GetAllocator());
- classNode.AddMember("Version", classData->IsDeprecated() ?
- rapidjson::Value(rapidjson::StringRef("Deprecated")) : rapidjson::Value(classData->m_version), document.GetAllocator());
- auto systemComponentIt = AZStd::lower_bound(systemComponents.begin(), systemComponents.end(), classData->m_typeId);
- const bool isSystemComponent = systemComponentIt != systemComponents.end() && *systemComponentIt == classData->m_typeId;
- classNode.AddMember("IsSystemComponent", isSystemComponent, document.GetAllocator());
- const bool isComponent = isSystemComponent || (classData->m_azRtti != nullptr && classData->m_azRtti->IsTypeOf<AZ::Component>());
- classNode.AddMember("IsComponent", isComponent, document.GetAllocator());
- classNode.AddMember("IsPrimitive", Utilities::IsSerializationPrimitive(genericClassInfo ? genericClassInfo->GetGenericTypeId() : classData->m_typeId), document.GetAllocator());
- classNode.AddMember("IsContainer", classData->m_container != nullptr, document.GetAllocator());
- if (genericClassInfo)
- {
- classNode.AddMember("GenericUuid", WriteToJsonValue(genericClassInfo->GetGenericTypeId(), document), document.GetAllocator());
- classNode.AddMember("Generics", DumpGenericStructure(genericClassInfo, context, document, scratchStringBuffer), document.GetAllocator());
- }
- if (!classData->m_elements.empty())
- {
- rapidjson::Value fields(rapidjson::kArrayType);
- rapidjson::Value bases(rapidjson::kArrayType);
- for (const SerializeContext::ClassElement& element : classData->m_elements)
- {
- DumpElementInfo(element, classData, context, fields, bases, document, scratchStringBuffer);
- }
- if (!bases.Empty())
- {
- classNode.AddMember("Bases", AZStd::move(bases), document.GetAllocator());
- }
- if (!fields.Empty())
- {
- classNode.AddMember("Fields", AZStd::move(fields), document.GetAllocator());
- }
- }
- parent.AddMember(WriteToJsonValue(classData->m_typeId, document), AZStd::move(classNode), document.GetAllocator());
- return true;
- }
- bool Dumper::DumpClassContent(AZStd::string& output, void* classPtr, const Uuid& classId, SerializeContext* context)
- {
- const SerializeContext::ClassData* classData = context->FindClassData(classId);
- if (!classData)
- {
- AZ_Printf("", " Class data for '%s' is missing.\n", classId.ToString<AZStd::string>().c_str());
- return false;
- }
- size_t indention = 0;
- auto begin = [context, &output, &indention](void* /*instance*/, const SerializeContext::ClassData* classData, const SerializeContext::ClassElement* classElement) -> bool
- {
- for (size_t i = 0; i < indention; ++i)
- {
- output += ' ';
- }
- if (classData)
- {
- output += classData->m_name;
- }
- DumpElementInfo(output, classElement, context);
- DumpPrimitiveTag(output, classData, classElement);
- output += '\n';
- indention += 2;
- return true;
- };
- auto end = [&indention]() -> bool
- {
- indention = indention > 0 ? indention - 2 : 0;
- return true;
- };
- SerializeContext::EnumerateInstanceCallContext callContext(begin, end, context, SerializeContext::ENUM_ACCESS_FOR_WRITE, nullptr);
- context->EnumerateInstance(&callContext, classPtr, classId, classData, nullptr);
- return true;
- }
- void Dumper::DumpElementInfo(const SerializeContext::ClassElement& element, const SerializeContext::ClassData* classData, SerializeContext* context,
- rapidjson::Value& fields, rapidjson::Value& bases, rapidjson::Document& document, AZStd::string& scratchStringBuffer)
- {
- AZ_Assert(fields.IsArray(), "Expected 'fields' to be an array.");
- AZ_Assert(bases.IsArray(), "Expected 'bases' to be an array.");
- AZ_Assert(scratchStringBuffer.empty(), "Provided scratch string buffer wasn't empty.");
- const SerializeContext::ClassData* elementClass = context->FindClassData(element.m_typeId, classData);
- AppendTypeName(scratchStringBuffer, elementClass, element.m_typeId);
- Uuid elementTypeId = element.m_typeId;
- if (element.m_genericClassInfo)
- {
- DumpGenericStructure(scratchStringBuffer, element.m_genericClassInfo, context);
- elementTypeId = element.m_genericClassInfo->GetSpecializedTypeId();
- }
- if ((element.m_flags & SerializeContext::ClassElement::FLG_POINTER) != 0)
- {
- scratchStringBuffer += '*';
- }
- rapidjson::Value elementTypeString(scratchStringBuffer.c_str(), document.GetAllocator());
- scratchStringBuffer.clear();
- if ((element.m_flags & SerializeContext::ClassElement::FLG_BASE_CLASS) != 0)
- {
- rapidjson::Value baseNode(rapidjson::kObjectType);
- baseNode.AddMember("Type", AZStd::move(elementTypeString), document.GetAllocator());
- baseNode.AddMember("Uuid", WriteToJsonValue(elementTypeId, document), document.GetAllocator());
- bases.PushBack(AZStd::move(baseNode), document.GetAllocator());
- }
- else
- {
- rapidjson::Value elementNode(rapidjson::kObjectType);
- elementNode.AddMember("Name", rapidjson::StringRef(element.m_name), document.GetAllocator());
- elementNode.AddMember("Type", AZStd::move(elementTypeString), document.GetAllocator());
- elementNode.AddMember("Uuid", WriteToJsonValue(elementTypeId, document), document.GetAllocator());
- elementNode.AddMember("HasDefault", (element.m_flags & SerializeContext::ClassElement::FLG_NO_DEFAULT_VALUE) == 0, document.GetAllocator());
- elementNode.AddMember("IsDynamic", (element.m_flags & SerializeContext::ClassElement::FLG_DYNAMIC_FIELD) != 0, document.GetAllocator());
- elementNode.AddMember("IsPointer", (element.m_flags & SerializeContext::ClassElement::FLG_POINTER) != 0, document.GetAllocator());
- elementNode.AddMember("IsUiElement", (element.m_flags & SerializeContext::ClassElement::FLG_UI_ELEMENT) != 0, document.GetAllocator());
- elementNode.AddMember("DataSize", static_cast<uint64_t>(element.m_dataSize), document.GetAllocator());
- elementNode.AddMember("Offset", static_cast<uint64_t>(element.m_offset), document.GetAllocator());
- Edit::ElementData* elementEditData = element.m_editData;
- if (elementEditData)
- {
- elementNode.AddMember("Description", rapidjson::StringRef(elementEditData->m_description), document.GetAllocator());
- }
- if (element.m_genericClassInfo)
- {
- rapidjson::Value genericArray(rapidjson::kArrayType);
- rapidjson::Value classObject(rapidjson::kObjectType);
- const SerializeContext::ClassData* genericClassData = element.m_genericClassInfo->GetClassData();
- classObject.AddMember("Type", rapidjson::StringRef(genericClassData->m_name), document.GetAllocator());
- classObject.AddMember("GenericUuid", WriteToJsonValue(element.m_genericClassInfo->GetGenericTypeId(), document), document.GetAllocator());
- classObject.AddMember("SpecializedUuid", WriteToJsonValue(element.m_genericClassInfo->GetSpecializedTypeId(), document), document.GetAllocator());
- classObject.AddMember("Generics", DumpGenericStructure(element.m_genericClassInfo, context, document, scratchStringBuffer), document.GetAllocator());
- genericArray.PushBack(AZStd::move(classObject), document.GetAllocator());
- elementNode.AddMember("Generics", AZStd::move(genericArray), document.GetAllocator());
- }
- fields.PushBack(AZStd::move(elementNode), document.GetAllocator());
- }
- }
- void Dumper::DumpElementInfo(AZStd::string& output, const SerializeContext::ClassElement* classElement, SerializeContext* context)
- {
- if (classElement)
- {
- if (classElement->m_genericClassInfo)
- {
- DumpGenericStructure(output, classElement->m_genericClassInfo, context);
- }
- if ((classElement->m_flags & SerializeContext::ClassElement::FLG_POINTER) != 0)
- {
- output += '*';
- }
- output += ' ';
- output += classElement->m_name;
- if ((classElement->m_flags & SerializeContext::ClassElement::FLG_BASE_CLASS) != 0)
- {
- output += " [Base]";
- }
- }
- }
- void Dumper::DumpGenericStructure(AZStd::string& output, GenericClassInfo* genericClassInfo, SerializeContext* context)
- {
- output += '<';
- const SerializeContext::ClassData* classData = genericClassInfo->GetClassData();
- if (classData && classData->m_container)
- {
- bool firstArgument = true;
- auto callback = [&output, context, &firstArgument](const Uuid& elementClassId, const SerializeContext::ClassElement* genericClassElement) -> bool
- {
- if (!firstArgument)
- {
- output += ',';
- }
- else
- {
- firstArgument = false;
- }
- const SerializeContext::ClassData* argClassData = context->FindClassData(elementClassId);
- AppendTypeName(output, argClassData, elementClassId);
- if (genericClassElement->m_genericClassInfo)
- {
- DumpGenericStructure(output, genericClassElement->m_genericClassInfo, context);
- }
- if ((genericClassElement->m_flags & SerializeContext::ClassElement::FLG_POINTER) != 0)
- {
- output += '*';
- }
- return true;
- };
- classData->m_container->EnumTypes(callback);
- }
- else
- {
- // No container information available, so as much as possible through other means, although
- // this might not be complete information.
- size_t numArgs = genericClassInfo->GetNumTemplatedArguments();
- for (size_t i = 0; i < numArgs; ++i)
- {
- if (i != 0)
- {
- output += ',';
- }
- const Uuid& argClassId = genericClassInfo->GetTemplatedTypeId(i);
- const SerializeContext::ClassData* argClass = context->FindClassData(argClassId);
- AppendTypeName(output, argClass, argClassId);
- }
- }
- output += '>';
- }
- rapidjson::Value Dumper::DumpGenericStructure(GenericClassInfo* genericClassInfo, SerializeContext* context,
- rapidjson::Document& parentDoc, AZStd::string& scratchStringBuffer)
- {
- AZ_Assert(scratchStringBuffer.empty(), "Provided scratch string buffer still contains data.");
- rapidjson::Value result(rapidjson::kArrayType);
- const SerializeContext::ClassData* classData = genericClassInfo->GetClassData();
- if (classData && classData->m_container)
- {
- auto callback = [&result, context, &parentDoc, &scratchStringBuffer](const Uuid& elementClassId,
- const SerializeContext::ClassElement* genericClassElement) -> bool
- {
- rapidjson::Value classObject(rapidjson::kObjectType);
- const SerializeContext::ClassData* argClassData = context->FindClassData(elementClassId);
- AppendTypeName(scratchStringBuffer, argClassData, elementClassId);
- classObject.AddMember("Type", rapidjson::Value(scratchStringBuffer.c_str(), parentDoc.GetAllocator()), parentDoc.GetAllocator());
- scratchStringBuffer.clear();
- classObject.AddMember("IsPointer", (genericClassElement->m_flags & SerializeContext::ClassElement::FLG_POINTER) != 0, parentDoc.GetAllocator());
- if (genericClassElement->m_genericClassInfo)
- {
- GenericClassInfo* genericClassInfo = genericClassElement->m_genericClassInfo;
- classObject.AddMember("GenericUuid", WriteToJsonValue(genericClassInfo->GetGenericTypeId(), parentDoc), parentDoc.GetAllocator());
- classObject.AddMember("SpecializedUuid", WriteToJsonValue(genericClassInfo->GetSpecializedTypeId(), parentDoc), parentDoc.GetAllocator());
- classObject.AddMember("Generics", DumpGenericStructure(genericClassInfo, context, parentDoc, scratchStringBuffer), parentDoc.GetAllocator());
- }
- else
- {
- classObject.AddMember("GenericUuid", WriteToJsonValue(elementClassId, parentDoc), parentDoc.GetAllocator());
- classObject.AddMember("SpecializedUuid", WriteToJsonValue(elementClassId, parentDoc), parentDoc.GetAllocator());
- }
- result.PushBack(AZStd::move(classObject), parentDoc.GetAllocator());
- return true;
- };
- classData->m_container->EnumTypes(callback);
- }
- else
- {
- // No container information available, so as much as possible through other means, although
- // this might not be complete information.
- size_t numArgs = genericClassInfo->GetNumTemplatedArguments();
- for (size_t i = 0; i < numArgs; ++i)
- {
- const Uuid& elementClassId = genericClassInfo->GetTemplatedTypeId(i);
- rapidjson::Value classObject(rapidjson::kObjectType);
- const SerializeContext::ClassData* argClassData = context->FindClassData(elementClassId);
- AppendTypeName(scratchStringBuffer, argClassData, elementClassId);
- classObject.AddMember("Type", rapidjson::Value(scratchStringBuffer.c_str(), parentDoc.GetAllocator()), parentDoc.GetAllocator());
- scratchStringBuffer.clear();
- classObject.AddMember("GenericUuid",
- WriteToJsonValue(argClassData ? argClassData->m_typeId : elementClassId, parentDoc), parentDoc.GetAllocator());
- classObject.AddMember("SpecializedUuid", WriteToJsonValue(elementClassId, parentDoc), parentDoc.GetAllocator());
- classObject.AddMember("IsPointer", false, parentDoc.GetAllocator());
- result.PushBack(AZStd::move(classObject), parentDoc.GetAllocator());
- }
- }
- return result;
- }
- void Dumper::DumpPrimitiveTag(AZStd::string& output, const SerializeContext::ClassData* classData, const SerializeContext::ClassElement* classElement)
- {
- if (classData)
- {
- Uuid classId = classData->m_typeId;
- if (classElement && classElement->m_genericClassInfo)
- {
- classId = classElement->m_genericClassInfo->GetGenericTypeId();
- }
- if (Utilities::IsSerializationPrimitive(classId))
- {
- output += " [Primitive]";
- }
- }
- }
- void Dumper::DumpClassName(rapidjson::Value& parent, SerializeContext* context, const SerializeContext::ClassData* classData,
- rapidjson::Document& parentDoc, AZStd::string& scratchStringBuffer)
- {
- AZ_Assert(scratchStringBuffer.empty(), "Scratch string buffer is not empty.");
- Edit::ClassData* editData = classData->m_editData;
- GenericClassInfo* genericClassInfo = context->FindGenericClassInfo(classData->m_typeId);
- if (genericClassInfo)
- {
- // If the type itself is a generic, dump it's information.
- scratchStringBuffer = classData->m_name;
- DumpGenericStructure(scratchStringBuffer, genericClassInfo, context);
- }
- else
- {
- bool hasEditName = editData && editData->m_name && strlen(editData->m_name) > 0;
- scratchStringBuffer = hasEditName ? editData->m_name : classData->m_name;
- }
- AZStd::string_view namespacePortion = ExtractNamespace(scratchStringBuffer);
- if (!namespacePortion.empty())
- {
- parent.AddMember("Namespace",
- rapidjson::Value(namespacePortion.data(), azlossy_caster(namespacePortion.length()), parentDoc.GetAllocator()),
- parentDoc.GetAllocator());
- parent.AddMember("Name", rapidjson::Value(scratchStringBuffer.c_str() + namespacePortion.length() + 2, parentDoc.GetAllocator()), parentDoc.GetAllocator());
- }
- else
- {
- parent.AddMember("Name", rapidjson::Value(scratchStringBuffer.c_str(), parentDoc.GetAllocator()), parentDoc.GetAllocator());
- }
- scratchStringBuffer.clear();
- }
- void Dumper::AppendTypeName(AZStd::string& output, const SerializeContext::ClassData* classData, const Uuid& classId)
- {
- if (classData)
- {
- output += classData->m_name;
- }
- else if (classId == GetAssetClassId())
- {
- output += "Asset";
- }
- else
- {
- output += classId.ToString<AZStd::string>();
- }
- }
- bool Dumper::WriteDocumentToStream(AZ::IO::GenericStream& outputStream, const rapidjson::Document& document,
- AZStd::string_view pointerRoot)
- {
- rapidjson::StringBuffer scratchBuffer;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(scratchBuffer);
- // rapidjson::Pointer constructor attempts to dereference the const char* index 0 even if the size is 0
- // so make sure the string_view isn't referencing a nullptr
- rapidjson::Pointer jsonPointerAnchor(pointerRoot.data() ? pointerRoot.data() : "", pointerRoot.size());
- // Anchor the content in the Json Document under the Json Pointer root path
- rapidjson::Document rootDocument;
- rapidjson::SetValueByPointer(rootDocument, jsonPointerAnchor, document);
- rootDocument.Accept(writer);
- outputStream.Write(scratchBuffer.GetSize(), scratchBuffer.GetString());
- scratchBuffer.Clear();
- return true;
- }
- // namespace AZ::SerializeContextTools
- }
|