#include #include #include #include #include #include #include #include static inline void Formatter(IOutputStream& stream, std::string_view fmt, TVector&& views) { constexpr auto INF = std::string::npos; size_t pos = 0; auto view = views.begin(); while (pos != INF && pos < fmt.size()) { size_t found = fmt.find("{}", pos); stream << fmt.substr(pos, found == INF ? INF : found - pos); pos = found == INF ? INF : found + 2; if (view != views.end()) { stream << *view; ++view; } } } using namespace NResource; static inline void EmitHex(IOutputStream& stream, const TString& view) { const unsigned char* data = reinterpret_cast(view.data()); size_t len = view.size(); constexpr size_t CHAR2HEX = 5; // len('0x??,') == 5 constexpr size_t MAX_STEP = 16; constexpr size_t STEPS[] = {MAX_STEP, 1}; auto print = [](char* out, const unsigned char* iter, const unsigned char* end) { char templ[CHAR2HEX + 1] = "0x??,"; while (iter != end) { HexEncode(iter, 1ULL, templ + 2ULL); memcpy(out, templ, CHAR2HEX); iter++; out += CHAR2HEX; } }; char buf[CHAR2HEX * MAX_STEP + 4] = {}; for (size_t step : STEPS) { while (len >= step) { print(buf, data, data + step); buf[CHAR2HEX * step] = 0; len -= step; data += step; stream << buf << (step > 1 ? "\n" : ""); } } stream << '\n'; } static inline void EmitHexArray(const TString& data, const TString& varName, IOutputStream& out) { const TString c = Compress(data); out << "static const unsigned char " << varName << "[] = {\n"; EmitHex(out, c); out << "};\n"; } static inline void GenOne(const TString& data, const TString& key, IOutputStream& out, bool isFile, bool useSections) { const TString name = "name" + ToString(CityHash64(key.data(), key.size())); if (useSections) { if (isFile) { Formatter(out, R"__( extern "C" const char {}[]; extern "C" const char {}_end[]; static const int REG_{} = NResource::LightRegisterI("{}", {}, {}_end); )__", {data, data, name, key, data, data}); } else { EmitHexArray(data, name, out); Formatter(out, R"__( static const int REG_{} = NResource::LightRegisterS("{}", (const char*){}, sizeof({})); )__", {name, key, name, name}); } return; } EmitHexArray(data, name, out); Formatter(out, R"__( static const NResource::TRegHelper REG_{}("{}", TStringBuf((const char*){}, sizeof({}))); )__", {name, key, name, name}); } static inline void EmitHeader(IOutputStream& out, bool useSections) { if (useSections) { out << R"__( // This function are defined in "library/cpp/resource/registry.cpp" namespace NResource { int LightRegisterS(const char*, const char*, unsigned long); int LightRegisterI(const char*, const char*, const char*); } )__"; } else { out << "#include \n"; } } int main(int argc, char** argv) { if (argc < 4) { Cerr << "usage: " << argv[0] << " outfile [?--use-sections] [infile path]+ [- key=value]+" << Endl; return 1; } TFixedBufferFileOutput out(argv[1]); bool useSections = false; if (TStringBuf(argv[2]) == "--use-sections") { useSections = true; argv += 3; } else { argv += 2; } EmitHeader(out, useSections); while (*argv) { if ("-"sv == *argv) { TVector items = StringSplitter(TString(*(argv + 1))).Split('=').Limit(2).ToList(); GenOne(TString(items[1]), TString(items[0]), out, false /*isFile*/, useSections); } else { const char* key = *(argv + 1); if (*key == '-') { ++key; } TString data = useSections ? *argv : TUnbufferedFileInput(*argv).ReadAll(); GenOne(data, key, out, true /*isFile*/, useSections); } argv += 2; } }