Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155
// The following program merges contents of several object catalogs
// stored in "geners" binary metafiles

#include <fstream>
#include <iostream>
#include <vector>

#include <memory>
#include "Alignment/Geners/interface/CatalogIO.hh"
#include "Alignment/Geners/interface/ContiguousCatalog.hh"
#include "Alignment/Geners/interface/uriUtils.hh"

#include "CmdLine.hh"

using namespace gs;
using namespace std;

static void print_usage(const char *progname) {
  cout << "\nUsage: " << progname << " -o output_file input_file0 input_file1 ...\n\n"
       << "This program merges the contents of several object catalogs stored "
          "in \"geners\"\n"
       << "binary metafiles. The output metafile can be used as a single "
          "\"geners\" archive\n"
       << "which includes all items from the merged catalogs.\n"
       << endl;
}

static const char *update_uri(const char *inputfile, const std::string &originalUri) {
  static std::string result, old_inputfile, old_URI;

  if (old_inputfile != inputfile || old_URI != originalUri) {
    old_inputfile = inputfile;
    old_URI = originalUri;
    result = joinDir1WithName2(inputfile, originalUri.c_str());
  }
  return result.c_str();
}

static ItemLocation update_location(const char *inputfile, const ItemLocation &original) {
  ItemLocation loc(original);
  loc.setURI(update_uri(inputfile, original.URI()));
  return loc;
}

int main(int argc, char const *argv[]) {
  CmdLine cmdline(argc, argv);

  if (argc == 1) {
    print_usage(cmdline.progname());
    return 0;
  }

  std::string outputfile;
  std::vector<std::string> inputfiles;

  try {
    cmdline.require("-o") >> outputfile;
    cmdline.optend();

    while (cmdline) {
      std::string s;
      cmdline >> s;
      inputfiles.push_back(s);
    }

    if (inputfiles.empty())
      throw CmdLineError("must specify at least one input file");
  } catch (CmdLineError &e) {
    cerr << "Error in " << cmdline.progname() << ": " << e.str() << endl;
    print_usage(cmdline.progname());
    return 1;
  }

  // Before we perform any significant data processing,
  // make sure that we can open all input files
  const unsigned nfiles = inputfiles.size();
  for (unsigned ifile = 0; ifile < nfiles; ++ifile) {
    const std::string &inputfile(inputfiles[ifile]);
    ifstream in(inputfile.c_str(), ios_base::binary);
    if (!in.is_open()) {
      cerr << "Error: failed to open file \"" << inputfile << "\"" << endl;
      return 1;
    }
  }

  // Variables which summarize the combined catalog
  unsigned totalMergeLevel = 0, lastCompressionCode = 0;
  bool compressionCodeMixed = false;
  std::vector<std::string> allAnnotations;
  ContiguousCatalog merged;

  // Now, do the real cycle over the input files
  for (unsigned ifile = 0; ifile < nfiles; ++ifile) {
    const std::string &inputfile(inputfiles[ifile]);
    const unsigned long long fileOffset = merged.size();

    ifstream in(inputfile.c_str(), ios_base::binary);
    if (!in.is_open()) {
      cerr << "Error: failed to open file \"" << inputfile << "\"" << endl;
      return 1;
    }

    unsigned compressionCode = 0, mergeLevel = 0;
    std::vector<std::string> annotations;
    std::unique_ptr<ContiguousCatalog> cat;
    try {
      cat = std::unique_ptr<ContiguousCatalog>(
          readBinaryCatalog<ContiguousCatalog>(in, &compressionCode, &mergeLevel, &annotations, true));
    } catch (std::exception &e) {
      cerr << "Failed to read catalog from file \"" << inputfile << "\". " << e.what() << endl;
      return 1;
    }

    // Update compression code info
    if (ifile)
      if (compressionCode != lastCompressionCode)
        compressionCodeMixed = true;
    lastCompressionCode = compressionCode;

    // Update merge level
    if (mergeLevel == 0)
      ++mergeLevel;
    totalMergeLevel += mergeLevel;

    // Update annotations
    std::copy(annotations.begin(), annotations.end(), std::back_inserter(allAnnotations));

    const unsigned long long last = cat->largestId();
    for (unsigned long long id = cat->smallestId(); id <= last; ++id) {
      if (!cat->itemExists(id))
        continue;
      std::shared_ptr<const CatalogEntry> e = cat->retrieveEntry(id);
      const unsigned long long newid = merged.makeEntry(*e,
                                                        e->compressionCode(),
                                                        e->itemLength(),
                                                        update_location(inputfile.c_str(), e->location()),
                                                        e->offset() + fileOffset);
      assert(newid);
    }
  }

  ofstream of(outputfile.c_str(), ios_base::binary);
  if (!of.is_open()) {
    cerr << "Error: failed to open file \"" << outputfile << "\"" << endl;
    return 1;
  }
  const unsigned compress = compressionCodeMixed ? 1 : lastCompressionCode;
  if (!writeBinaryCatalog(of, compress, totalMergeLevel, allAnnotations, merged)) {
    cerr << "Error: failed to write merged catalog to file \"" << outputfile << "\"" << endl;
    return 1;
  }
  of.close();

  return 0;
}