#include #include #include #include #include #include #include #include #include #include constexpr std::streamsize 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, std::streamsize 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 in bytes std::array sizes{0}; sizes[0] = static_cast(argc - 1); for (size_t i = 1; i < argc; ++i) { struct stat file; if (stat(argv[i], &file) != 0) die("stat"); if (file.st_size >= UINT32_MAX) { // 4 GB Limit errno = EFBIG; die("stat"); } sizes[i] = file.st_size; } writeBuffer(sizes.data(), block_size); // DATA: Each App for (size_t i = 1; i < argc; ++i) { std::vector buf(sizes[i]); std::ifstream input(argv[i], std::ios::binary); if (!input) die("fopen"); input.read(buf.data(), sizes[i]); writeBuffer(buf.data(), sizes[i]); // Fill to block size, if required if (sizes[i] % block_size != 0) writeBuffer(zeros, block_size - (sizes[i] % block_size)); } std::cout.flush(); return EXIT_SUCCESS; }