blob: 4b38cbef87103fed216fe150c8286e73e4d924e9 [file] [log] [blame]
/*-
* 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;
}