#include #include #include #include #include #include #include #include #include #include constexpr size_t block_size = 4096; const uint8_t zeros[block_size] = {}; template static void die(std::format_string fmt, Args &&...args) { auto msg = std::format(fmt, std::forward(args)...); perror(msg.c_str()); exit(EXIT_FAILURE); } static void writeBuffer(const void *data, size_t size) { std::cout.write(reinterpret_cast(data), size); } int main(int argc, char *argv[]) { if (argc < 2) { std::println(stderr, "usage: {} \n", argv[0]); return EXIT_FAILURE; } else if (argc > 1000) { std::println(stderr, "Only a maximum of 1000 apps are supported\n"); return EXIT_FAILURE; } // HEADER: Number of apps + size of each app std::array size{0}; size[0] = static_cast(argc - 1); for (size_t i = 1; i < argc; ++i) { struct stat sb; if (stat(argv[i], &sb) != 0) die("stat"); // 4 GB Limit if (sb.st_size >= UINT32_MAX) { errno = EFBIG; die("stat"); } size[i] = sb.st_size; } writeBuffer(size.data(), block_size); // DATA: Each App for (size_t i = 1; i < argc; ++i) { std::vector buf(size[i]); std::ifstream input(argv[i], std::ios::binary); if (!input) die("fopen"); input.read(buf.data(), size[i]); writeBuffer(buf.data(), size[i]); // Fill to block size, if required if (size[i] % block_size != 0) writeBuffer(zeros, block_size - (size[i] % block_size)); } std::cout.flush(); return EXIT_SUCCESS; }