163 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			163 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#include <asset_parser/assets/text.hpp>
 | 
						|
#include <lz4.h>
 | 
						|
 | 
						|
namespace Assets {
 | 
						|
 | 
						|
/* static */ void TextAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
 | 
						|
{
 | 
						|
	const auto &[metadata, text_metadata, text] = data;
 | 
						|
 | 
						|
	auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
 | 
						|
	if (!stream.is_open())
 | 
						|
	{
 | 
						|
		throw std::runtime_error {
 | 
						|
			std::format("Failed to open ofstream for packing Text at: {}", out_path.string())
 | 
						|
		};
 | 
						|
	}
 | 
						|
	stream.seekp(0);
 | 
						|
 | 
						|
	// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
						|
	stream.write((char *)¤t_version, sizeof(current_version));
 | 
						|
	stream.write((char *)&metadata, sizeof(metadata));
 | 
						|
	stream.write((char *)&text_metadata, sizeof(text_metadata));
 | 
						|
 | 
						|
	constexpr auto number_of_blobs = uint32_t { 1 };
 | 
						|
	stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
 | 
						|
 | 
						|
	auto textblob_metadata = BlobMetadata {
 | 
						|
		.tag = BlobMetadata::Tag::text,
 | 
						|
		.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
 | 
						|
		.compression_type = CompressionType::None,
 | 
						|
		.compressed_size = text.size(),
 | 
						|
		.uncompressed_size = text.size(),
 | 
						|
	};
 | 
						|
 | 
						|
	stream.write((char *)&textblob_metadata, sizeof(textblob_metadata));
 | 
						|
	stream.write((char *)text.data(), static_cast<long>(text.size()));
 | 
						|
	// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
						|
}
 | 
						|
 | 
						|
TextAsset::TextAsset(const std::filesystem::path &path)
 | 
						|
{
 | 
						|
	m_stream = std::ifstream { path, std::ios::binary };
 | 
						|
	if (!m_stream.is_open())
 | 
						|
	{
 | 
						|
		throw std::runtime_error {
 | 
						|
			std::format("Failed to open ifstream for loading Text asset at: {}", path.string())
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
 | 
						|
	m_stream.read((char *)&version, sizeof(version));
 | 
						|
	m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
 | 
						|
	m_stream.read((char *)&m_metadata, sizeof(m_metadata));
 | 
						|
 | 
						|
	auto num_blobs = uint32_t {};
 | 
						|
	m_stream.read((char *)&num_blobs, sizeof(num_blobs));
 | 
						|
	if (num_blobs != 1)
 | 
						|
	{
 | 
						|
		throw std::runtime_error {
 | 
						|
			std::format("Failed to load Text asset: invalid number of blobs: {}", num_blobs)
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	m_stream.read((char *)&m_text_blob_metadata, sizeof(m_text_blob_metadata));
 | 
						|
	if (m_text_blob_metadata.tag != BlobMetadata::Tag::text)
 | 
						|
	{
 | 
						|
		throw std::runtime_error {
 | 
						|
			std::format(
 | 
						|
			    "Failed to load Text asset: invalid blob tag, expected {}, got {}",
 | 
						|
			    std::to_underlying(BlobMetadata::Tag::text),
 | 
						|
			    std::to_underlying(m_text_blob_metadata.tag)
 | 
						|
			),
 | 
						|
		};
 | 
						|
	}
 | 
						|
	// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
 | 
						|
}
 | 
						|
 | 
						|
void TextAsset::unpack_blob(
 | 
						|
    BlobMetadata::Tag tag,
 | 
						|
    std::byte *destination,
 | 
						|
    size_t destination_capacity
 | 
						|
) const
 | 
						|
{
 | 
						|
	if (tag != BlobMetadata::Tag::text)
 | 
						|
	{
 | 
						|
		throw std::runtime_error {
 | 
						|
			std::format("Invalid tag for unpack_blob of TextAsset: {}", std::to_underlying(tag))
 | 
						|
		};
 | 
						|
	}
 | 
						|
 | 
						|
	m_stream.seekg(static_cast<long>(m_text_blob_metadata.offset));
 | 
						|
	switch (m_text_blob_metadata.compression_type)
 | 
						|
	{
 | 
						|
	case Assets::CompressionType::None:
 | 
						|
		if (m_text_blob_metadata.uncompressed_size != m_text_blob_metadata.compressed_size)
 | 
						|
		{
 | 
						|
			throw std::runtime_error(
 | 
						|
			    "Failed to unpack blob from TextAsset: "
 | 
						|
			    "compressed/uncompressed size mismatch for no compression "
 | 
						|
			    "type"
 | 
						|
			);
 | 
						|
		}
 | 
						|
 | 
						|
		if (m_text_blob_metadata.uncompressed_size > destination_capacity)
 | 
						|
		{
 | 
						|
			throw std::runtime_error(
 | 
						|
			    "Failed to unpack blob from TextAsset: "
 | 
						|
			    "uncompressed_size > destination_capacity, unpacking "
 | 
						|
			    "would result in segfault"
 | 
						|
			);
 | 
						|
		}
 | 
						|
 | 
						|
		if (!m_stream.is_open())
 | 
						|
		{
 | 
						|
			throw std::runtime_error(
 | 
						|
			    "Failed to unpack blob from TextAsset: ifstream is "
 | 
						|
			    "closed"
 | 
						|
			);
 | 
						|
		}
 | 
						|
 | 
						|
		m_stream.read(
 | 
						|
		    // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
 | 
						|
		    (char *)destination,
 | 
						|
		    static_cast<long>(m_text_blob_metadata.uncompressed_size)
 | 
						|
		);
 | 
						|
 | 
						|
		return;
 | 
						|
 | 
						|
	default:
 | 
						|
		throw std::runtime_error(
 | 
						|
		    std::format(
 | 
						|
		        "Failed to unpack blob from TextAsset: unsupported "
 | 
						|
		        "compression type: {}",
 | 
						|
		        std::to_underlying(m_text_blob_metadata.compression_type)
 | 
						|
		    )
 | 
						|
		);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
[[nodiscard]] auto TextAsset::get_asset_metadata() const -> const Asset::Metadata &
 | 
						|
{
 | 
						|
	return m_asset_metadata;
 | 
						|
}
 | 
						|
 | 
						|
[[nodiscard]] auto TextAsset::get_metadata() const -> const Metadata &
 | 
						|
{
 | 
						|
	return m_metadata;
 | 
						|
}
 | 
						|
 | 
						|
[[nodiscard]] auto TextAsset::get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &
 | 
						|
{
 | 
						|
	if (tag != BlobMetadata::Tag::text)
 | 
						|
	{
 | 
						|
		throw std::runtime_error { std::format(
 | 
						|
			"Invalid tag for get_blob_metadata of TextAsset: {}",
 | 
						|
			std::to_underlying(tag)
 | 
						|
		) };
 | 
						|
	}
 | 
						|
 | 
						|
	return m_text_blob_metadata;
 | 
						|
}
 | 
						|
 | 
						|
} // namespace Assets
 |