File indexing completed on 2025-01-05 04:01:13

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 #pragma once
0007 
0008 #include <QDomDocument>
0009 #include "aep_riff.hpp"
0010 #include "io/svg/detail.hpp"
0011 
0012 namespace glaxnimate::io::aep {
0013 
0014 class AepxConverter
0015 {
0016 public:
0017 
0018     RiffChunk aepx_to_chunk(const QDomElement& element)
0019     {
0020         QString header = element.tagName();
0021 
0022         if ( header == "ProjectXMPMetadata" )
0023         {
0024             return chunk("XMPM", text(element.text()));
0025         }
0026         else if ( header == "string" )
0027         {
0028             return chunk("Utf8", text(element.text()));
0029         }
0030         else if ( header == "numS" )
0031         {
0032             std::uint32_t val = element.firstChildElement().text().toUInt();
0033             auto data = buffer(Endianness::Big().write_uint(val));
0034             return chunk(header, data);
0035         }
0036         else if ( header == "ppSn" )
0037         {
0038             std::uint32_t val = element.firstChildElement().text().toDouble();
0039             auto data = buffer(Endianness::Big().write_float64(val));
0040             return chunk(header, data);
0041         }
0042         else if ( element.hasAttribute("bdata") )
0043         {
0044             return chunk(header, hex(element.attribute("bdata")));
0045         }
0046 
0047         ChunkId riff_header = header.toLatin1();
0048         ChunkId subheader = {""};
0049         if ( header == "AfterEffectsProject" )
0050         {
0051             riff_header = {"RIFX"};
0052         }
0053         else if ( !AepRiff::is_fake_list(riff_header) )
0054         {
0055             subheader = riff_header;
0056             riff_header = {"LIST"};
0057         }
0058 
0059         return {riff_header, 0, subheader, {}, read_chunk_list(svg::detail::ElementRange(element))};
0060     }
0061 
0062     std::vector<std::unique_ptr<RiffChunk>> read_chunk_list(const svg::detail::ElementRange& range)
0063     {
0064         std::vector<std::unique_ptr<RiffChunk>> out;
0065         out.reserve(range.size());
0066         for ( const auto& el : range )
0067             out.push_back(std::make_unique<RiffChunk>(aepx_to_chunk(el)));
0068         return out;
0069     }
0070 
0071 private:
0072     struct BinaryData
0073     {
0074         QByteArray data;
0075         QBuffer file;
0076         std::uint32_t length;
0077     };
0078 
0079     RiffChunk chunk(const QString& header, BinaryData* data, const QString& subheader = {})
0080     {
0081         return {
0082             header.toLatin1(), data->length, subheader.toLatin1(),
0083             {Endianness::Big(), &data->file, data->length, 0}
0084         };
0085     }
0086 
0087     BinaryData* buffer(QByteArray&& content)
0088     {
0089         data.push_back(std::make_unique<BinaryData>());
0090         data.back()->length = content.size();
0091         data.back()->data = std::move(content);
0092         data.back()->file.setBuffer(&data.back()->data);
0093         data.back()->file.open(QIODevice::ReadOnly);
0094         return data.back().get();
0095     }
0096 
0097     BinaryData* hex(const QString& hex)
0098     {
0099         return buffer(QByteArray::fromHex(hex.toLatin1()));
0100     }
0101 
0102     BinaryData* text(const QString& string)
0103     {
0104         return buffer(string.toUtf8());
0105     }
0106 
0107     std::vector<std::unique_ptr<BinaryData>> data;
0108 };
0109 
0110 } // namespace glaxnimate::io::aep