size_t Gft::Leanify(size_t size_leanified /*= 0*/) { // header uint32_t header_size; if (size_ < 0x14 || size_ <= (header_size = *(uint32_t*)(fp_ + 0x10))) { std::cerr << "Not a valid GFT file." << std::endl; return Format::Leanify(size_leanified); } // move header if (size_leanified) { memmove(fp_ - size_leanified, fp_, header_size); fp_ -= size_leanified; } return header_size + LeanifyFile(fp_ + size_leanified + header_size, size_ - header_size, size_leanified); }
int ProcessFile(const wchar_t *file_path) { char mbs[MAX_PATH] = { 0 }; WideCharToMultiByte(CP_ACP, 0, file_path, -1, mbs, sizeof(mbs) - 1, nullptr, nullptr); std::cout << "Processing: " << mbs << std::endl; std::string filename(mbs); #else // written like this in order to be callback funtion of ftw() int ProcessFile(const char file_path[], const struct stat *sb = nullptr, int typeflag = FTW_F) { if (typeflag != FTW_F) { return 0; } std::cout << "Processing: " << file_path << std::endl; std::string filename(file_path); #endif // _WIN32 File input_file(file_path); if (input_file.IsOK()) { size_t original_size = input_file.GetSize(); size_t new_size = LeanifyFile(input_file.GetFilePionter(), original_size, 0, filename); PrintSize(original_size); std::cout << " -> "; PrintSize(new_size); std::cout << "\tLeanified: "; PrintSize(original_size - new_size); std::cout << " (" << 100 - 100.0 * new_size / original_size << "%)" << std::endl; input_file.UnMapFile(new_size); } return 0; } void PauseIfNotTerminal() { // pause if Leanify is not started in terminal // so that user can see the output instead of just a flash of a black box #ifdef _WIN32 if (is_pause) { system("pause"); } #endif // _WIN32 } void PrintInfo() { std::cerr << "Leanify\t" << VERSION_STR << std::endl << std::endl; std::cerr << "Usage: leanify [options] paths\n" " -i, --iteration <iteration> More iterations produce better result, but\n" " use more time, default is 15.\n" " -d, --max_depth <max depth> Maximum recursive depth, unlimited by default.\n" " Set to 1 will disable recursive minifying.\n" " -f, --fastmode Fast mode, no recompression.\n" " -q, --quiet No output to stdout.\n" " -v, --verbose Verbose output.\n" " --keep-exif Do not remove Exif.\n"; PauseIfNotTerminal(); }
size_t Rdb::Leanify(size_t size_leanified /*= 0*/) { if (size <= 0x20) { std::cerr << "Not a valid RDB file." << std::endl; return Format::Leanify(size_leanified); } depth++; char *p_read; size_t rdb_size_leanified = 0; // header p_read = fp; fp -= size_leanified; // total number of files including directory uint32_t file_num = *(uint32_t *)(p_read + 0x10); uint64_t index_offset = *(uint64_t *)(p_read + 0x14); uint64_t content_offset = index_offset + *(uint64_t *)(p_read + 0x1C); // move header and indexes if (size_leanified) { memmove(fp, p_read, (size_t)content_offset); } char *p_index = fp + index_offset; p_read += content_offset; for (uint32_t i = 0; i < file_num; i++) { // index wchar_t *file_name = (wchar_t *)p_index; // note that on Linux wchar_t is 4 bytes instead of 2 // so I can't use wcslen // p_index += (wcslen(file_name) + 1) * 2; while (*(uint16_t *)p_index) { p_index += 2; } p_index += 2; uint64_t file_size = *(uint64_t *)(p_index + 8); *(uint64_t *)p_index -= rdb_size_leanified; // skip directories if (!file_size) { p_index += 16; continue; } if (depth <= max_depth) { // output filename for (int i = 1; i < depth; i++) { std::cout << "-> "; } char mbs[256] = { 0 }; UTF16toMBS(file_name, p_index - (char *)file_name, mbs, sizeof(mbs)); std::cout << mbs << std::endl; // Leanify inner file size_t new_size = LeanifyFile(p_read, (size_t)file_size, rdb_size_leanified + size_leanified, std::string(mbs)); if (new_size != file_size) { // update the size in index *(uint64_t *)(p_index + 8) = new_size; rdb_size_leanified += (size_t)file_size - new_size; } } else { memmove(p_read - rdb_size_leanified - size_leanified, p_read, (size_t)file_size); } p_read += file_size; p_index += 16; } size = p_read - fp - size_leanified - rdb_size_leanified; depth--; return size; }
size_t Gz::Leanify(size_t size_leanified /*= 0*/) { // written according to this specification // http://www.gzip.org/zlib/rfc-gzip.html if (size <= 18) { std::cerr << "Not a valid GZ file." << std::endl; return Format::Leanify(size_leanified); } depth++; char flags = *(fp + 3); // set the flags to 0, remove all unnecessary section *(fp + 3 - size_leanified) = 0; char *p_read = fp + 10; char *p_write = p_read - size_leanified; *(p_write - 2) = 2; // XFL if (flags & (1 << 2)) // FEXTRA { p_read += *(uint16_t *)p_read + 2; } std::string filename; if (flags & (1 << 3)) // FNAME { for (int i = 1; i < depth; i++) { std::cout << "-> "; } std::cout << p_read << std::endl; filename = std::string(p_read); while (p_read < fp + size && *p_read++) { // skip string } } if (flags & (1 << 4)) // FCOMMENT { while (p_read < fp + size && *p_read++) { // skip string } } if (flags & (1 << 1)) // FHCRC { p_read += 2; } if (p_read >= fp + size) { return Format::Leanify(size_leanified); } if (size_leanified) { memmove(fp - size_leanified, fp, 10); } if (is_fast) { memmove(p_write, p_read, fp + size - p_read); return size - (p_read - p_write); } uint32_t uncompressed_size = *(uint32_t *)(fp + size - 4); uint32_t crc = *(uint32_t *)(fp + size - 8); size_t original_size = fp + size - 8 - p_read; size_t s = 0; unsigned char *buffer = (unsigned char *)tinfl_decompress_mem_to_heap(p_read, original_size, &s, 0); if (!buffer || s != uncompressed_size || crc != mz_crc32(0, buffer, uncompressed_size)) { std::cerr << "GZ corrupted!" << std::endl; mz_free(buffer); memmove(p_write, p_read, original_size + 8); return size - (p_read - p_write); } uncompressed_size = LeanifyFile(buffer, uncompressed_size, 0, filename); ZopfliOptions options; ZopfliInitOptions(&options); options.numiterations = iterations; unsigned char bp = 0, *out = NULL; size_t outsize = 0; ZopfliDeflate(&options, 2, 1, buffer, uncompressed_size, &bp, &out, &outsize); if (outsize < original_size) { memcpy(p_write, out, outsize); p_write += outsize; *(uint32_t *)p_write = mz_crc32(0, buffer, uncompressed_size); *(uint32_t *)(p_write + 4) = uncompressed_size; } else { memmove(p_write, p_read, original_size + 8); p_write += original_size; } mz_free(buffer); delete[] out; depth--; fp -= size_leanified; return p_write + 8 - fp; }