bool BSDiff::Patch(char8 *origData, uint32 origSize, char8 *newData, uint32 newSize, File *patchFile) { bool ret = false; ZLibIStream inStream(patchFile); // read BS type uint32 typeToRead = -1; patchFile->Read(&typeToRead); bspatch_stream patchStream; patchStream.read = &BSDiff::BSRead; patchStream.type = (BSType) typeToRead; switch(typeToRead) { case BS_ZLIB: patchStream.opaque = &inStream; break; case BS_PLAIN: patchStream.opaque = patchFile; break; default: DVASSERT(0 && "Unknow BS-type"); break; } // apply bsdiff if(0 == bspatch((uint8_t *) origData, origSize, (uint8_t *) newData, newSize, &patchStream)) { ret = true; } return ret; }
JNIEXPORT jbyteArray JNICALL Java_cn_reactnative_modules_update_DownloadTask_bsdiffPatch (JNIEnv *env, jobject self, jbyteArray origin, jbyteArray patch){ jclass newExcCls; jbyte* outPtr; struct bspatch_stream stream; bz_stream zip; jbyte* originPtr = (*env)->GetByteArrayElements(env, origin, NULL); size_t originLength = (*env)->GetArrayLength(env, origin); jbyte* patchPtr = (*env)->GetByteArrayElements(env, patch, NULL); size_t patchLength = (*env)->GetArrayLength(env, patch); jbyteArray ret = NULL; if (patchLength < 32) { newExcCls = (*env)->FindClass(env,"java/lang/Error"); if (newExcCls != NULL) /* Unable to find the new exception class, give up. */ (*env)->ThrowNew(env,newExcCls, "Corrupt patch"); (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT); return NULL; } int64_t newsize=offtin((uint8_t*)patchPtr + 16); if (memcmp(patchPtr, "ENDSLEY/BSDIFF43", 16) != 0 || newsize<0) { newExcCls = (*env)->FindClass(env, "java/lang/Error"); if (newExcCls != NULL) /* Unable to find the new exception class, give up. */ (*env)->ThrowNew(env, newExcCls, "Corrupt patch"); (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT); return NULL; } ret = (*env)->NewByteArray(env, newsize); if (ret == NULL) { return NULL; // out of memory error thrown } outPtr = (*env)->GetByteArrayElements(env, ret, NULL); zip.bzalloc = NULL; zip.bzfree = NULL; zip.opaque = NULL; BZ2_bzDecompressInit(&zip, 0, 1); zip.next_in = (char*)patchPtr + 32; zip.avail_in = patchLength - 32; stream.read = bz2_read; stream.opaque = &zip; if (bspatch((const uint8_t*)originPtr, originLength, (uint8_t*)outPtr, newsize, &stream)) { newExcCls = (*env)->FindClass(env, "java/lang/Error"); if (newExcCls != NULL) /* Unable to find the new exception class, give up. */ (*env)->ThrowNew(env, newExcCls, "bspatch"); } BZ2_bzDecompressEnd(&zip); (*env)->ReleaseByteArrayElements(env, ret, outPtr, 0); (*env)->ReleaseByteArrayElements(env, origin, originPtr, JNI_ABORT); (*env)->ReleaseByteArrayElements(env, patch, patchPtr, JNI_ABORT); return ret; }
static gboolean dispatch_bspatch (OstreeRepo *repo, StaticDeltaExecutionState *state, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; guint64 offset, length; g_autoptr(GInputStream) in_stream = NULL; g_autoptr(GMappedFile) input_mfile = NULL; g_autofree guchar *buf = NULL; struct bspatch_stream stream; struct bzpatch_opaque_s opaque; gsize bytes_written; if (!read_varuint64 (state, &offset, error)) goto out; if (!read_varuint64 (state, &length, error)) goto out; if (!state->have_obj) { input_mfile = g_mapped_file_new_from_fd (state->read_source_fd, FALSE, error); if (!input_mfile) goto out; buf = g_malloc0 (state->content_size); opaque.state = state; opaque.offset = offset; opaque.length = length; stream.read = bspatch_read; stream.opaque = &opaque; if (bspatch ((const guint8*)g_mapped_file_get_contents (input_mfile), g_mapped_file_get_length (input_mfile), buf, state->content_size, &stream) < 0) goto out; if (!g_output_stream_write_all (state->content_out, buf, state->content_size, &bytes_written, cancellable, error)) goto out; g_assert (bytes_written == state->content_size); } ret = TRUE; out: return ret; }
jstring Java_com_jackwang_patchapk_PatchJNI_bspatch(JNIEnv* env, jobject thiz, jstring oldFilePath, jstring newFilePath, jstring patchFilePath) { const char* oldFilePathChar = (*env)->GetStringUTFChars(env, oldFilePath, 0); const char* newFilePathChar = (*env)->GetStringUTFChars(env, newFilePath, 0); const char* patchFilePathChar = (*env)->GetStringUTFChars(env, patchFilePath, 0); LOGI("oldFilePath = %s", oldFilePathChar); LOGI("newFilePath = %s", newFilePathChar); LOGI("patchFilePath = %s", patchFilePathChar); bspatch(oldFilePathChar, newFilePathChar, patchFilePathChar); //releaseString (*env)->ReleaseStringUTFChars(env, oldFilePath, oldFilePathChar); (*env)->ReleaseStringUTFChars(env, newFilePath, newFilePathChar); (*env)->ReleaseStringUTFChars(env, patchFilePath, patchFilePathChar); return (*env)->NewStringUTF(env, "patch success"); }
bool ApplyPatch(const char* patch_file, const char* path) { FILE* patch = fopen(patch_file, "rb"); int bzerror; FILE* tmp_file = NULL; FILE* src_file = NULL; BZFILE* bzs = NULL; BZFILE* bzf = NULL; if(!patch) { goto error; } char header[16]; fread(header, 1, 16, patch); if(memcmp(header, "JPATCH10", 8)!=0) { goto error; } unsigned int ctrl_offset = (unsigned int)(*((unsigned int*)(header+8 ))); unsigned int data_offset = (unsigned int)(*((unsigned int*)(header+12))); bzs = NULL; bzf = BZ2_bzReadOpen(&bzerror, patch, 0, 0, NULL, 0); if(!bzf) { goto error; } for(;;) { unsigned short len; char fname[500], src_md5[60], dst_md5[60]; BZ2_bzRead(&bzerror, bzf, &len, sizeof(len)); if(bzerror!=BZ_OK) { goto error; } BZ2_bzRead(&bzerror, bzf, &fname, len); if(bzerror!=BZ_OK) { if(bzerror==BZ_STREAM_END) { break; } else { goto error; } } fname[len] = '\0'; BZ2_bzRead(&bzerror, bzf, &len, sizeof(len)); if(bzerror!=BZ_OK) { goto error; } if(len>=sizeof(src_md5)) { goto error; } BZ2_bzRead(&bzerror, bzf, &src_md5, len); if(bzerror!=BZ_OK) { goto error; } src_md5[len] = '\0'; BZ2_bzRead(&bzerror, bzf, &len, sizeof(len)); if(bzerror!=BZ_OK) { goto error; } if(len>=sizeof(dst_md5)) { goto error; } BZ2_bzRead(&bzerror, bzf, &dst_md5, len); if(bzerror!=BZ_OK) { goto error; } dst_md5[len] = '\0'; char dst_filename[400]; sprintf(dst_filename, "%s%s", path, fname); char tmp_filename[400]; sprintf(tmp_filename, "%s.tmp", dst_filename); bool skip = false; src_file = fopen(dst_filename, "rb"); if(src_file) { char md5[60]; if(!GetMD5(src_file, md5)) { goto error; } if(strcmp(md5, dst_md5)==0) { skip = true; } else { if(src_md5[0]!='\0' && strcmp(md5, src_md5)!=0) { goto error; } } } else { if(src_md5[0]!='\0') { goto error; } MakeDir_P(tmp_filename); tmp_file = fopen(tmp_filename, "wb"); if(!tmp_file) { goto error; } } for(;;) { unsigned char code; BZ2_bzRead(&bzerror, bzf, &code, sizeof(code)); if(bzerror!=BZ_OK) { goto error; } if(code==OPERATOR_END) break; if(code==OPERATOR_APPEND) { printf("%s\n", fname); unsigned int size, offset; BZ2_bzRead(&bzerror, bzf, &size, sizeof(size)); if(bzerror!=BZ_OK) { goto error; } BZ2_bzRead(&bzerror, bzf, &offset, sizeof(offset)); if(bzerror!=BZ_OK) { goto error; } printf("- append %d %d\n", size, offset); if(!skip) { fseek(patch, offset+data_offset, SEEK_SET); bzs = BZ2_bzReadOpen(&bzerror, patch, 0, 0, NULL, 0); if(!bzs) { goto error; } while(size>0) { char mem[1000]; size_t rsize = size>sizeof(mem)?sizeof(mem):size; BZ2_bzRead(&bzerror, bzs, mem, rsize); if(bzerror!=BZ_OK && size!=rsize && bzerror!=BZ_STREAM_END) { goto error; } if(fwrite(mem, 1, rsize, tmp_file)!=rsize) { goto error; } size -= rsize; } BZ2_bzReadClose(&bzerror, bzs); bzs = NULL; if(bzerror!=BZ_OK) { goto error; } } continue; } if(code==OPERATOR_PATCH) { printf("%s\n", fname); unsigned int offset, size, patch_offset; BZ2_bzRead(&bzerror, bzf, &offset, sizeof(offset)); if(bzerror!=BZ_OK) { goto error; } BZ2_bzRead(&bzerror, bzf, &size, sizeof(size)); if(bzerror!=BZ_OK) { goto error; } BZ2_bzRead(&bzerror, bzf, &patch_offset, sizeof(patch_offset)); if(bzerror!=BZ_OK) { goto error; } if(!skip) { void* mem; mem = ReadFile(src_file, size, offset); if(!mem) { goto error; } fseek(patch, patch_offset+data_offset, SEEK_SET); u_char* newp; off_t newsize; if(bspatch((u_char*)mem, (off_t)size, patch, &newp, &newsize)!=0) { free(mem); goto error; } if(fwrite(newp, 1, newsize, tmp_file)!=newsize) { free(newp); free(mem); goto error; } free(newp); free(mem); } continue; } if(code==OPERATOR_COPY) { unsigned int size, offset; BZ2_bzWrite(&bzerror, bzf, &size, 4); if(bzerror!=BZ_OK) { goto error; } BZ2_bzWrite(&bzerror, bzf, &offset, 4); if(bzerror!=BZ_OK) { goto error; } fseek(src_file, offset, SEEK_SET); while(size>0) { char data[10*1024]; unsigned int s = size; if(s>sizeof(data)) s = sizeof(data); if(fread(data, 1, s, src_file)!=s) { goto error; } if(fwrite(data, 1, s, tmp_file)!=s) { goto error; } size -= s; } continue; } goto error; } if(src_file) { fclose(src_file); src_file = NULL; } fclose(tmp_file); tmp_file = NULL; if(_unlink(dst_filename)!=0 && errno!=ENOENT) goto error; if(rename(tmp_filename, dst_filename)!=0) goto error; } BZ2_bzReadClose(&bzerror, bzf); fclose(patch); return true; error: if(bzs) BZ2_bzReadClose(&bzerror, bzs); if(bzf) BZ2_bzReadClose(&bzerror, bzf); if(patch) fclose(patch); if(tmp_file) fclose(tmp_file); if(src_file) fclose(src_file); return false; }
int main(int argc,char * argv[]) { FILE * f; int fd; int bz2err; uint8_t header[24]; uint8_t *olddata, *newdata; int64_t oldsize, newsize; BZFILE* bz2; struct bspatch_stream stream; if(argc!=4) errx(1,"usage: %s oldfile newfile patchfile\n",argv[0]); /* Open patch file */ if ((f = fopen(argv[3], "r")) == NULL) err(1, "fopen(%s)", argv[3]); /* Read header */ if (fread(header, 1, 16, f) != 16) { if (feof(f)) errx(1, "Corrupt patch\n"); err(1, "fread(%s)", argv[3]); } /* Check for appropriate magic */ if (memcmp(header, "ENDSLEY/BSDIFF43", 16) != 0) errx(1, "Corrupt patch\n"); /* Read lengths from header */ newsize=offtin(header+16) if(newsize<0) errx(1,"Corrupt patch\n"); /* Close patch file and re-open it via libbzip2 at the right places */ if(((fd=open(argv[1],O_RDONLY,0))<0) || ((oldsize=lseek(fd,0,SEEK_END))==-1) || ((olddata=malloc(oldsize+1))==NULL) || (lseek(fd,0,SEEK_SET)!=0) || (read(fd,olddata,oldsize)!=oldsize) || (close(fd)==-1)) err(1,"%s",argv[1]); if((newdata=malloc(newsize+1))==NULL) err(1,NULL); if (NULL == (bz2 = BZ2_bzReadOpen(&bz2err, f, 0, 0, NULL, 0))) errx(1, "BZ2_bzReadOpen, bz2err=%d", bz2err); stream.read = bz2_read; stream.opaque = bz2; if (bspatch(olddata, oldsize, newdata, newsize, &stream)) errx(1, "bspatch"); /* Clean up the bzip2 reads */ BZ2_bzReadClose(&bz2err, bz2); fclose(f); /* Write the newdata file */ if(((fd=open(argv[2],O_CREAT|O_TRUNC|O_WRONLY,0666))<0) || (write(fd,newdata,newsize)!=newsize) || (close(fd)==-1)) err(1,"%s",argv[2]); free(newdata); free(olddata); return 0; }
void testPatch(const char *baseFile, const char *variantFile, const char *patchFile) { uint8_t *base = NULL; size_t baseSize; uint8_t *patch = NULL; size_t patchSize; off_t result; FILE *fbase = NULL; FILE *fpatch = NULL; FILE *fvariant = NULL; fbase = fopen(baseFile, "r"); //get baseSize if (fseek(fbase, 0, SEEK_END) != 0) { goto fail; } result = ftello(fbase); if (result == -1) { goto fail; } baseSize = (size_t) result; // allocate base buffer base = (uint8_t *) malloc(baseSize + 1); if (fseek(fbase, 0, SEEK_SET) != 0) { goto fail; } fread(base, sizeof(uint8_t), baseSize, fbase); fclose(fbase); fbase = NULL; fpatch = fopen(patchFile, "r"); if (fpatch == NULL) { fprintf(stderr, "Failed to open patch file\n"); return; } // get patch size if (fseek(fpatch, 0, SEEK_END) != 0) { goto fail; } result = ftello(fpatch); if (result == -1) { goto fail; } patchSize = (size_t) result; // allocate patch buffer patch = (uint8_t *) malloc(patchSize); fseek(fpatch, 0, SEEK_SET); fread(patch, sizeof(uint8_t), patchSize, fpatch); fclose(fpatch); fpatch = NULL; fvariant = fopen(variantFile, "w"); PatchStream stream; stream.write = writeStream; stream.init = initStream; stream.end = endStream; stream.opaque = fvariant; bspatch(base, baseSize, patch, patchSize, &stream); fclose(fvariant); fvariant = NULL; fail: if (fbase != NULL) { fclose(fbase); } if (base != NULL) { free(base); } if (patch != NULL) { free(patch); } if (fpatch != NULL) { fclose(fpatch); } }