Skip to content

Commit

Permalink
add 二进制文件差异算法和打补丁的方法
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaominghe2014 committed May 10, 2024
1 parent 02b78c2 commit 2e86345
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 0 deletions.
2 changes: 2 additions & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ executable("test_main") {
"include/base/XFileUtil.h",
"include/base/XString.h",
"include/base/XRandom.h",
"include/diff/patch.h",
"src/crypto/md5.cpp",
"src/crypto/base64.cpp",
"src/crypto/url.cpp",
Expand All @@ -69,6 +70,7 @@ executable("test_main") {
"src/base/XUtf8.cpp",
"src/base/XRandom.cpp",
"src/base/XTime.cpp",
"src/diff/patch.cpp",
]
}

35 changes: 35 additions & 0 deletions include/diff/patch.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// patch.h
// com.xm.xlib
//
// Created by xiaominghe2014@gmail.com on 2024/5/10.
//

#ifndef patch_h
#define patch_h
#include <iostream>
#include <fstream>
#include <vector>
#include "macro/XBase.h"

namespace xlib {
namespace patch{
// 二进制文件差异数据结构
struct Difference {
size_t position;
bool is_deleted;
uint8 modified;
};

//Binary Difference Algorithm 二进制差异算法的实现
std::vector<Difference> binary_difference(const std::string& old_file, const std::string& new_file);

// create patch file from differences 通过差异创建补丁文件
void create_patch(const std::string& patch_file, const std::vector<Difference>& differences);

// 打补丁
void apply_patch(const std::string& original_file, const std::string& patch_file, const std::string& output_file);
}
}

#endif /* patch_h */
1 change: 1 addition & 0 deletions include/xlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@
#include "parser/SgfParser.h"
#include "parser/xml.h"
#include "math/math.h"
#include "diff/patch.h"
#endif /* xlib_h */
11 changes: 11 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,16 @@ void testFile()
LOG_I("decodeFile md5=%s", md5DecodeFile.c_str());
}

void testPatch(){
const std::string newFile = std::string(originPath).append("newFile");
const std::string oldFile = std::string(originPath).append("oldFile");
const std::string patchFile = std::string(originPath).append("patch.bin");
const std::string outPutFile = std::string(originPath).append("patch_out_put");
auto diff = patch::binary_difference(oldFile, newFile);
patch::create_patch(patchFile, diff);
patch::apply_patch(oldFile, patchFile, outPutFile);
}

void testSHA()
{
crypto::SHA1 sha1;
Expand Down Expand Up @@ -701,6 +711,7 @@ int main(int argc, char *argv[])
{
std::cout <<XString::toStringAddEnter(XString::lettersShape("xlib-test"))<< std::endl;
setLog();
// testPatch();
testAStar();
testMath();
testMatrix();
Expand Down
109 changes: 109 additions & 0 deletions src/diff/patch.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
//
// patch.cpp
// com.xm.xlib
//
// Created by apple on 2024/5/10.
//

#include "diff/patch.h"
#include <iostream>
#include <fstream>
#include <vector>
namespace xlib {
namespace patch {

std::vector<Difference> binary_difference(const std::string& old_file, const std::string& new_file) {
std::ifstream f1(old_file, std::ios::binary);
std::ifstream f2(new_file, std::ios::binary);

std::vector<Difference> differences;

if (!f1.is_open() || !f2.is_open()) {
std::cerr << "Error opening files!" << std::endl;
return differences;
}

size_t index = 0;
uint8 byte1, byte2;
while (f1.read(reinterpret_cast<char*>(&byte1), 1) && f2.read(reinterpret_cast<char*>(&byte2), 1)) {
if (byte1 != byte2) {
differences.push_back({index, false, byte2});
}
index++;
}

// Check if file1 has extra bytes
while (f1.read(reinterpret_cast<char*>(&byte1), 1)) {
differences.push_back({index, true, 0}); // Mark as deleted
return differences;
}

// Check if file2 has extra bytes
while (f2.read(reinterpret_cast<char*>(&byte2), 1)) {
differences.push_back({index, false, byte2});
index++;
}

return differences;
}

void create_patch(const std::string& patch_file, const std::vector<Difference>& differences) {
std::ofstream out(patch_file, std::ios::binary);
if (!out.is_open()) {
std::cerr << "Error opening patch file!" << std::endl;
return;
}

for (const auto& diff : differences) {
out.write(reinterpret_cast<const char*>(&diff.position), sizeof(diff.position));
out.write(reinterpret_cast<const char*>(&diff.is_deleted), sizeof(diff.is_deleted));
if (!diff.is_deleted) {
out.write(reinterpret_cast<const char*>(&diff.modified), sizeof(diff.modified));
}
}
}

void apply_patch(const std::string& original_file, const std::string& patch_file, const std::string& output_file) {
std::ifstream original(original_file, std::ios::binary);
std::ifstream patch(patch_file, std::ios::binary);
std::ofstream output(output_file, std::ios::binary);

if (!original.is_open() || !patch.is_open() || !output.is_open()) {
std::cerr << "Error opening files for patching!"<< std::endl;
return;
}

std::vector<uint8> file_contents((std::istreambuf_iterator<char>(original)), std::istreambuf_iterator<char>());
size_t position;
bool is_deleted;
uint8 modified_byte;
size_t fileSize = 0;
std::cout << "Applying patch..."<< std::endl;
while (patch.read(reinterpret_cast<char*>(&position), sizeof(position)) &&
patch.read(reinterpret_cast<char*>(&is_deleted), sizeof(is_deleted))) {
std::cout << "Position: "<< position << ", is_deleted: "<< is_deleted<< std::endl;

if (is_deleted) {
if (position< file_contents.size()) {
file_contents.erase(file_contents.begin() + position);
fileSize = position -1;
break;
}
} else {
patch.read(reinterpret_cast<char*>(&modified_byte), sizeof(modified_byte));
if (position >= file_contents.size()) {
file_contents.resize(position + 1);
}
file_contents[position] = modified_byte;
fileSize = position + 1;
}
// 跳过已经读取的字节
// patch.ignore(sizeof(position) + sizeof(modified_byte));
}

std::cout << "Patch applied. Writing output file..."<< std::endl;
auto data = file_contents.data();
output.write(reinterpret_cast<const char*>(data), fileSize);
}
}
}

0 comments on commit 2e86345

Please sign in to comment.