scraps

Abandon all hope, ye who enter here.
git clone https://git.neptards.moe/neptards/scraps.git
Log | Files | Refs | Submodules | README | LICENSE

sql_importer_file.cpp (4677B)


      1 #include "scraps/format/rags_sql/sql_importer_private.hpp" // IWYU pragma: associated
      2 
      3 #include "scraps/format/archive.hpp"
      4 #include "scraps/format/rags_sql/test_helper/sql_helper.hpp"
      5 
      6 #include <libshit/doctest.hpp>
      7 #include <libshit/except.hpp>
      8 #include <libshit/low_io.hpp>
      9 #include <libshit/memory_utils.hpp>
     10 #include <libshit/utils.hpp>
     11 #include <libshit/nonowning_string.hpp>
     12 
     13 #include <capnp/list.h>
     14 
     15 #include <sstream>
     16 #include <string>
     17 
     18 // IWYU pragma: no_forward_declare capnp::List
     19 
     20 namespace Scraps::Format::RagsSql
     21 {
     22   TEST_SUITE_BEGIN("Scraps::Format::RagsSql");
     23 
     24   template <typename T, typename U, typename V>
     25   static void ImportFileCommon(Importer& imp, T init, U append, V fini)
     26   {
     27     auto [file_orphan, groups] = imp.ImportGroups("MediaGroups");
     28     imp.game.AdoptFileGroups(Libshit::Move(file_orphan));
     29 
     30     Importer::NameSet id_set;
     31     auto file = imp.game.InitFiles(SCRAPS_CAPNP_LIST_LEN(imp.file_ids.size()));
     32     imp.sql.Query("SELECT [Name], [GroupName], [Data] FROM [Media];", 3);
     33     for (std::uint32_t i = 0, n = imp.file_ids.size(); i < n; ++i)
     34     {
     35       imp.sql.AssertHasRow();
     36       auto name = Importer::GetUniqueName(id_set, imp.sql.GetWString());
     37       file[i].SetId(imp.file_ids.at(name));
     38       file[i].SetName(imp.sp.InternCopy(name));
     39       file[i].SetGroupId(
     40         Importer::FindId(groups, imp.sql.GetWString(), "file group", ""));
     41 
     42       auto data_info = imp.sql.GetCellInfo();
     43       if (data_info.status != Sql::DbStatus::OK)
     44         LIBSHIT_THROW(SqlError, "Failed to get file data",
     45                       "Status", Sql::ToString(data_info.status));
     46       if (data_info.len != Sql::CellInfo::STREAM)
     47         LIBSHIT_THROW(SqlError, "Media is not blob", "Length", data_info.len);
     48 
     49       init(file[i], name);
     50 
     51       char buf[4096];
     52       while (auto got = imp.sql.GetChunk(buf, sizeof(buf)))
     53         append(Libshit::StringView{buf, got});
     54       fini(file[i]);
     55     }
     56     imp.sql.AssertNoRow();
     57   }
     58 
     59   void Importer::ImportFile(ArchiveWriter& aw)
     60   {
     61     std::uint64_t len;
     62     ImportFileCommon(
     63       *this, [&](Proto::File::Builder file, const auto& name)
     64       {
     65         file.InitData();
     66         file.GetData().SetOffset(aw.Tell());
     67         len = 0;
     68       }, [&](auto chunk) { aw.Append(chunk); len += chunk.size(); },
     69       [&](auto media) { media.GetData().SetSize(len); });
     70   }
     71 
     72   TEST_CASE("ImportFile to archive")
     73   {
     74     TestHelper::TestSqls([](Sql& sql, Memory::DB& db)
     75     {
     76       using C = Memory::Cell;
     77       std::string big(4096*4 + 123, 'a');
     78       db.tables["Media"] = {
     79         {
     80           { "Name", Memory::Type::NVARCHAR, 250 },
     81           { "Data", Memory::Type::IMAGE },
     82           { "GroupName", Memory::Type::NVARCHAR, 255 },
     83         }, {
     84           { C::Ntext("foo.jpg"), C::Image("jpeg data..."), C::Ntext("") },
     85           { C::Ntext(u8"bar 猫.mp4"), C::Image(big), C::Ntext("gggrp") },
     86         }
     87       };
     88       db.tables["MediaGroups"] = {
     89         {
     90           { "Name", Memory::Type::NVARCHAR, 255 },
     91           { "Parent", Memory::Type::NVARCHAR, 255 },
     92         }, {
     93           { C::Ntext("gggrp"), C::Ntext("") },
     94         }
     95       };
     96 
     97       Importer imp{sql};
     98       imp.GenIds(imp.file_ids, "Media", "Name"); // 2-3
     99       auto sstream_moved = Libshit::MakeUnique<std::stringstream>();
    100       auto ss = sstream_moved.get();
    101       ArchiveWriter aw{Libshit::Move(sstream_moved)};
    102       imp.ImportFile(aw); // group: 4
    103 
    104       std::string expected_content(3*8, '\0');
    105       expected_content += "jpeg data...";
    106       expected_content += big;
    107       CHECK(ss->str() == expected_content);
    108 
    109       auto file = imp.game.GetFiles();
    110       REQUIRE(file.size() == 2);
    111 
    112       CHECK(file[0].GetId() == 2);
    113       CHECK(imp.sp.Get(file[0].GetName()) == "foo.jpg");
    114       CHECK(file[0].GetGroupId() == 0);
    115       REQUIRE(file[0].IsData());
    116       CHECK(file[0].GetData().GetOffset() == 3*8);
    117       CHECK(file[0].GetData().GetSize() ==  12);
    118 
    119       CHECK(file[1].GetId() == 3);
    120       CHECK(imp.sp.Get(file[1].GetName()) == u8"bar 猫.mp4");
    121       CHECK(file[1].GetGroupId() == 4);
    122       REQUIRE(file[1].IsData());
    123       CHECK(file[1].GetData().GetOffset() == 3*8 + 12);
    124       CHECK(file[1].GetData().GetSize() == 4096*4 + 123);
    125     });
    126   }
    127 
    128   void Importer::ImportFile(Libshit::StringView dirname)
    129   {
    130     Libshit::LowIo io;
    131     ImportFileCommon(
    132       *this, [&](Proto::File::Builder file, auto&& name)
    133       {
    134         auto [new_name, io2] = UniqueName(
    135           dirname, NormalizeFilename(Libshit::Move(name)));
    136         io = Libshit::Move(io2);
    137         file.SetFileName(sp.InternString(Libshit::Move(new_name)));
    138       }, [&](auto chunk) { io.Write(chunk.data(), chunk.size()); },
    139       [](auto) {});
    140   }
    141 
    142   TEST_SUITE_END();
    143 }