diff --git a/source/utility/CMakeLists.txt b/source/utility/CMakeLists.txt index 4047ff8..5111e21 100644 --- a/source/utility/CMakeLists.txt +++ b/source/utility/CMakeLists.txt @@ -16,6 +16,11 @@ ADD_EXECUTABLE (asset_unpacker asset_unpacker.cpp) TARGET_LINK_LIBRARIES (asset_unpacker ${STAR_EXT_LIBS}) +ADD_EXECUTABLE (btree_repacker + $ $ $ + btree_repacker.cpp) +TARGET_LINK_LIBRARIES (btree_repacker ${STAR_EXT_LIBS}) + ADD_EXECUTABLE (dump_versioned_json $ $ $ $ dump_versioned_json.cpp) diff --git a/source/utility/btree_repacker.cpp b/source/utility/btree_repacker.cpp new file mode 100644 index 0000000..14f0fb1 --- /dev/null +++ b/source/utility/btree_repacker.cpp @@ -0,0 +1,58 @@ +#include "StarBTreeDatabase.hpp" +#include "StarTime.hpp" +#include "StarFile.hpp" +#include "StarVersionOptionParser.hpp" + +using namespace Star; + +int main(int argc, char** argv) { + try { + double startTime = Time::monotonicTime(); + + VersionOptionParser optParse; + optParse.setSummary("Repacks a Starbound BTree file to shrink its file size"); + optParse.addArgument("input file path", OptionParser::Required, "Path to the BTree to be repacked"); + optParse.addArgument("output filename", OptionParser::Optional, "Output BTree file"); + + auto opts = optParse.commandParseOrDie(argc, argv); + + String bTreePath = opts.arguments.at(0); + String outputFilename = opts.arguments.get(1, bTreePath + ".repack"); + + outputFilename = File::relativeTo(File::fullPath(File::dirName(outputFilename)), File::baseName(outputFilename)); + //open the old db + BTreeDatabase db; + db.setIODevice(std::move(File::open(bTreePath, IOMode::Read))); + db.open(); + + //make a new db + BTreeDatabase newDb; + newDb.setBlockSize(db.blockSize()); + newDb.setContentIdentifier(db.contentIdentifier()); + newDb.setKeySize(db.keySize()); + newDb.setAutoCommit(false); + + newDb.setIODevice(std::move(File::open(outputFilename, IOMode::ReadWrite | IOMode::Truncate))); + newDb.open(); + coutf("Repacking %s...\n", bTreePath); + //copy the data over + unsigned count = 0; + db.forAll([&count, &newDb](ByteArray key, ByteArray data) { + newDb.insert(key, data); + ++count; + }); + + //close the old db + db.close(); + //commit and close the new db + newDb.commit(); + newDb.close(); + + coutf("Repacked BTree to %s in %ss\n", outputFilename, Time::monotonicTime() - startTime); + return 0; + + } catch (std::exception const& e) { + cerrf("Exception caught: %s\n", outputException(e, true)); + return 1; + } +}