| /*- |
| * Copyright 2003-2005 Colin Percival |
| * Copyright 2012 Matthew Endsley |
| * All rights reserved |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted providing that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
| * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
| * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
| * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
| * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
| * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "bspatch.h" |
| #include "bsport.h" |
| #include "bsfile.h" |
| #include "bzlib.h" |
| |
| //8 more bytes is to store old file size |
| #define HEADER_EXT |
| |
| #ifdef HEADER_EXT |
| #define HEADER_SIZE 40 |
| #else |
| #define HEADER_SIZE 32 |
| #endif |
| |
| static int64_t offtin(uint8_t *buf) |
| { |
| int64_t y; |
| |
| y=buf[7]&0x7F; |
| y=y*256;y+=buf[6]; |
| y=y*256;y+=buf[5]; |
| y=y*256;y+=buf[4]; |
| y=y*256;y+=buf[3]; |
| y=y*256;y+=buf[2]; |
| y=y*256;y+=buf[1]; |
| y=y*256;y+=buf[0]; |
| |
| if(buf[7]&0x80) y=-y; |
| |
| return y; |
| } |
| |
| /* Using control info in patch to calculate oldfile size */ |
| int get_oldsize(char *patch) |
| { |
| #ifdef HEADER_EXT |
| uint32_t oldlen; |
| if(memcmp(patch, "BSDIFF40", 8) != 0){ |
| printf("Corrupt patch\n\r"); |
| return 0; |
| } |
| |
| oldlen = offtin(patch + 32); |
| // obm_printf("get_oldsize: %d\n\r", oldlen); |
| |
| return oldlen; |
| #else |
| uint32_t ctr_len; |
| char *header; |
| BZFILE *cpfbz2; |
| int cbz2err; |
| int ctrl[3]; |
| int i, j, lenread; |
| int oldpos = 0, newpos=0, newsize; |
| BFILE *cpf; |
| uint8_t buf[8]; |
| |
| header = patch; |
| if(memcmp(header, "BSDIFF40", 8) != 0){ |
| printf("Corrupt patch\n\r"); |
| return 0; |
| } |
| |
| ctr_len = offtin(header + 8); |
| newsize = offtin(header + 24); |
| |
| cpf = bfopen(patch+32, ctr_len); |
| if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL){ |
| printf("BZ2_bzReadOpen, bz2err = %d\n\r", cbz2err); |
| return 0; |
| } |
| |
| while (newpos < newsize) { |
| /* Read control data */ |
| for (i = 0;i <= 2;i++) { |
| lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8); |
| if ((lenread < 8) || ((cbz2err != BZ_OK) && |
| (cbz2err != BZ_STREAM_END))) |
| { |
| printf("Corrupt patch %d %d\n\r", __LINE__, cbz2err); |
| return 0; |
| } |
| ctrl[i] = offtin(buf); |
| }; |
| |
| /* Sanity-check */ |
| if (newpos + ctrl[0] > newsize){ |
| printf("Corrupt patch %d\n\r", __LINE__); |
| return 0; |
| } |
| |
| /* Adjust pointers */ |
| newpos += ctrl[0]; |
| oldpos += ctrl[0]; |
| |
| /* Sanity-check */ |
| if (newpos + ctrl[1] > newsize){ |
| printf("Corrupt patch %d\n\r", __LINE__); |
| return 0; |
| } |
| |
| /* Adjust pointers */ |
| newpos += ctrl[1]; |
| oldpos += ctrl[2]; |
| }; |
| BZ2_bzReadClose(&cbz2err, cpfbz2); |
| bfclose(cpf); |
| oldpos -= ctrl[2]; |
| return oldpos; |
| #endif |
| } |
| |
| int get_newsize(char *patch) { |
| uint32_t newlen; |
| if(memcmp(patch, "BSDIFF40", 8) != 0){ |
| printf("Corrupt patch\n\r"); |
| return 0; |
| } |
| |
| newlen = offtin(patch + 24); |
| |
| return newlen; |
| |
| } |
| |
| int is_patch_empty(char *patch) |
| { |
| char *header; |
| uint32_t newsize, lenread, ctr_len; |
| long ctrl[3]; |
| BFILE *cpf; |
| BZFILE * cpfbz2; |
| header = patch; |
| int cbz2err, i; |
| uint8_t buf[8]; |
| |
| if(memcmp(header, "BSDIFF40", 8) != 0){ |
| return 0; |
| } |
| |
| ctr_len = offtin(header + 8); |
| newsize = offtin(header + 24); |
| |
| cpf = bfopen(patch+HEADER_SIZE, ctr_len); |
| if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL){ |
| printf("BZ2_bzReadOpen, cbz2err = %d\n\r", cbz2err); |
| return 0; |
| } |
| |
| /* Read control data */ |
| for (i = 0;i <= 2;i++) { |
| lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8); |
| if ((lenread < 8) || ((cbz2err != BZ_OK) && |
| (cbz2err != BZ_STREAM_END))) |
| return 0; |
| ctrl[i] = offtin(buf); |
| }; |
| |
| if( (ctrl[0] == newsize) && ((ctrl[0] + ctrl[2]) == 0) && |
| (ctrl[1] == 0) ) |
| return 1; //newfile == oldfile, patch is empty |
| |
| return 0; |
| } |
| |
| int bzpacth(char* in, int in_len, char* out, int *out_len, char* patch, int patch_len) |
| { |
| uint32_t ctr_len, data_len, extra_len, new_size; |
| char *header, *newfile, *pctrl, *pdata, *pextra; |
| BFILE *cpf, *dpf, *epf; |
| BZFILE * cpfbz2, *dpfbz2, *epfbz2; |
| int cbz2err, dbz2err, ebz2err; |
| long ctrl[3]; |
| uint8_t buf[8]; |
| int ret, i; |
| uint32_t oldpos, newpos; |
| uint32_t lenread; |
| cpf = dpf = epf = NULL; |
| cpfbz2 = dpfbz2 = epfbz2 = NULL; |
| |
| header = patch; |
| if(memcmp(header, "BSDIFF40", 8) != 0){ |
| goto err_corrupt_patch; |
| } |
| |
| ctr_len = offtin(header + 8); |
| data_len = offtin(header + 16); |
| new_size = offtin(header + 24); |
| extra_len = patch_len - ctr_len - data_len; |
| //printf("ctr_len: %d, data_len: %d, extra_len: %d, new_size: %d\n\r", ctr_len, data_len, extra_len, new_size); |
| |
| newfile = out; |
| if(*out_len < new_size){ |
| printf("outbuf too small\n\r"); |
| goto err; |
| } |
| |
| cpf = bfopen(patch+HEADER_SIZE, ctr_len); |
| if ((cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0)) == NULL){ |
| printf("BZ2_bzReadOpen, cbz2err = %d\n\r", cbz2err); |
| goto err; |
| } |
| |
| dpf = bfopen(patch+HEADER_SIZE+ctr_len, data_len); |
| if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL){ |
| printf("BZ2_bzReadOpen, dbz2err = %d\n\r", dbz2err); |
| goto err; |
| } |
| |
| epf = bfopen(patch+HEADER_SIZE+ctr_len+data_len, extra_len); |
| if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL){ |
| printf("BZ2_bzReadOpen, ebz2err = %d\n\r", ebz2err); |
| goto err; |
| } |
| |
| oldpos = 0;newpos = 0; |
| while (newpos < new_size) { |
| /* Read control data */ |
| for (i = 0;i <= 2;i++) { |
| lenread = BZ2_bzRead(&cbz2err, cpfbz2, buf, 8); |
| if ((lenread < 8) || ((cbz2err != BZ_OK) && |
| (cbz2err != BZ_STREAM_END))) |
| goto err_corrupt_patch; |
| ctrl[i] = offtin(buf); |
| }; |
| |
| /* Sanity-check */ |
| if (newpos + ctrl[0] > new_size) |
| goto err_corrupt_patch; |
| |
| /* Read diff string */ |
| lenread = BZ2_bzRead(&dbz2err, dpfbz2, newfile + newpos, ctrl[0]); |
| if ((lenread < ctrl[0]) || |
| ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) |
| { |
| goto err_corrupt_patch; |
| } |
| |
| /* Add pold data to diff string */ |
| for (i = 0;i < ctrl[0];i++) |
| if ((oldpos + i >= 0) && (oldpos + i < in_len)) |
| newfile[newpos + i] += in[oldpos + i]; |
| |
| /* Adjust pointers */ |
| newpos += ctrl[0]; |
| oldpos += ctrl[0]; |
| |
| /* Sanity-check */ |
| if (newpos + ctrl[1] > new_size) |
| goto err_corrupt_patch; |
| |
| /* Read extra string */ |
| lenread = BZ2_bzRead(&ebz2err, epfbz2, newfile + newpos, ctrl[1]); |
| if ((lenread < ctrl[1]) || |
| ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) |
| { |
| goto err_corrupt_patch; |
| } |
| |
| /* Adjust pointers */ |
| newpos += ctrl[1]; |
| oldpos += ctrl[2]; |
| }; |
| |
| *out_len = new_size; |
| |
| BZ2_bzReadClose(&cbz2err, cpfbz2); |
| BZ2_bzReadClose(&dbz2err, dpfbz2); |
| BZ2_bzReadClose(&ebz2err, epfbz2); |
| bfclose(cpf); |
| bfclose(dpf); |
| bfclose(epf); |
| |
| return 0; |
| |
| err_corrupt_patch: |
| printf("Bspatch: corrupt patch\n\r"); |
| err: |
| if(cpfbz2) BZ2_bzReadClose(&cbz2err, cpfbz2); |
| if(dpfbz2) BZ2_bzReadClose(&dbz2err, dpfbz2); |
| if(epfbz2) BZ2_bzReadClose(&ebz2err, epfbz2); |
| if(cpf) bfclose(cpf); |
| if(dpf) bfclose(dpf); |
| if(epf) bfclose(epf); |
| |
| return -1; |
| } |