zoukankan      html  css  js  c++  java
  • 手把手实现andriod应用增量升级

    近期研究了android应用增量升级的应用。当中用到了android NDK编程,先说下为什么要使用增量升级。当我们的应用达到一定大小的时候,比方眼下有30M。假设新版本号35M仅仅是添加了几个功能,而之前都保持不变,那么这个时候我们能够生成一个差分包,这个差分包一般就6M左右大小,大大的为用户节省了流量。

    增量升级原理

    android增量升级,首先在server端生成差分包,然后用户下载差分包。在手机端,将该差分包和旧版本号的apk合成为新的版本号。

    使用到的开源项目

    bsdiff :是一个二进制差分工具。 用于生成差分包
    bspatch :是一个开源的合成工具,android通过ndk将其编译为so文件然后调用其代码就可以实现:差分包和旧版本号apk的合成。
    另外还须要下载:bzip2-1.0.6
    http://www.bzip.org/downloads.html
    这里写图片描写叙述

    增量升级的实现

    increaseone1.0.apk

    在正式实现之前,当然是先准备我们的apk了,这里我编写一个简单的project,执行效果例如以下:
    这里写图片描写叙述
    将该该projectbin文件夹下生成的apk复制到”D:increase”文件夹下。而且又一次命名为”increaseone1.0.apk”

    increaseone2.0.apk

    如今加入一个activity,而且在该projectmainactivity中加入一个button能够跳转到该activity。主要是为了差别。此时执行后的效果例如以下:
    这里写图片描写叙述
    相同将bin文件夹下的最新的apk文件拷贝至”d:increase”文件夹下。重命名为”increaseone2.0.apk”

    生成差分包

    准备好不同版本号的apk后,就须要生成差分包。这里通常是在服务端来实现的。这里用到了”bsdiff4.3-win32”工具:
    进入命令行下输入例如以下命令:”bsdiff.exe 旧版本号的apk路径 新版本号的apk路径 生成的差分包的路径”,例如以下图:
    这里写图片描写叙述
    此时在”d:increase”文件夹下回生成一个increase.patch的差分包。
    这里写图片描写叙述

    手机端实现patch合成

    创建androidproject

    新建一个androidprojectselfincrease
    新建类:”PatchUpdate.java”用来调用底层的c代码实现patch的合成。

    package com.example.selfincrease;
    
    public class PatchUpdate {
        public  native  int patch(String oldApkPath,    String  newApkPath, String  patchPath);
    }
    

    调用javac和javah生成头文件:
    这里写图片描写叙述
    具体的步骤能够參考一步一步学习androidNDK编程(hello world)

    创建jni实现c代码

    在该androidproject文件夹下,新建一个jni文件夹,将中的例如以下文件复制到该文件夹下:
    blocksort.c
    bzip2.c
    bzip2recover.c
    bzlib_private.h
    bzlib.c
    bzlib.h
    com_example_selfincrease_PatchUpdate.h
    compress.c
    crctable.c
    decompress.c
    dlltest.c
    huffman.c
    mk251.c
    randtable.c
    spewG.c
    unzcrash.c
    这里写图片描写叙述
    这里写图片描写叙述
    这里写图片描写叙述
    期中”com_example_selfincrease_PatchUpdate.h”是刚才生成的头文件。
    在jni文件夹下新建”com_example_selfincrease_PatchUpdate.c”文件,内容例如以下:

    #include <stdio.h>
    
    #include "bzlib_private.h"
    #include "bzlib.h"
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <err.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <android/log.h>
    #include <jni.h>
    #include "com_example_selfincrease_PatchUpdate.h"
    
    /*---------------------------------------------------*/
    void BZ2_hbCreateDecodeTables ( Int32 *limit,
                                    Int32 *base,
                                    Int32 *perm,
                                    UChar *length,
                                    Int32 minLen,
                                    Int32 maxLen,
                                    Int32 alphaSize )
    {
       Int32 pp, i, j, vec;
    
       pp = 0;
       for (i = minLen; i <= maxLen; i++)
          for (j = 0; j < alphaSize; j++)
             if (length[j] == i) { perm[pp] = j; pp++; };
    
       for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0;
       for (i = 0; i < alphaSize; i++) base[length[i]+1]++;
    
       for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1];
    
       for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0;
       vec = 0;
    
       for (i = minLen; i <= maxLen; i++) {
          vec += (base[i+1] - base[i]);
          limit[i] = vec-1;
          vec <<= 1;
       }
       for (i = minLen + 1; i <= maxLen; i++)
          base[i] = ((limit[i-1] + 1) << 1) - base[i];
    }
    
    
    static
    void makeMaps_d ( DState* s )
    {
       Int32 i;
       s->nInUse = 0;
       for (i = 0; i < 256; i++)
          if (s->inUse[i]) {
             s->seqToUnseq[s->nInUse] = i;
             s->nInUse++;
          }
    }
    
    /*---------------------------------------------------*/
    #define RETURN(rrr)                               
       { retVal = rrr; goto save_state_and_return; };
    
    #define GET_BITS(lll,vvv,nnn)                     
    {                                                 
       case lll: s->state = lll;                      
       while (True) {                                 
          if (s->bsLive >= nnn) {                     
             UInt32 v;                                
             v = (s->bsBuff >>                        
                 (s->bsLive-nnn)) & ((1 << nnn)-1);   
             s->bsLive -= nnn;                        
             vvv = v;                                 
             break;                                   
          }                                           
          if (s->strm->avail_in == 0) RETURN(BZ_OK);  
          s->bsBuff                                   
             = (s->bsBuff << 8) |                     
               ((UInt32)                              
                  (*((UChar*)(s->strm->next_in))));   
          s->bsLive += 8;                             
          s->strm->next_in++;                         
          s->strm->avail_in--;                        
          s->strm->total_in_lo32++;                   
          if (s->strm->total_in_lo32 == 0)            
             s->strm->total_in_hi32++;                
       }                                              
    }
    
    #define GET_UCHAR(lll,uuu)                        
       GET_BITS(lll,uuu,8)
    
    #define GET_BIT(lll,uuu)                          
       GET_BITS(lll,uuu,1)
    
    /*---------------------------------------------------*/
    #define GET_MTF_VAL(label1,label2,lval)           
    {                                                 
       if (groupPos == 0) {                           
          groupNo++;                                  
          if (groupNo >= nSelectors)                  
             RETURN(BZ_DATA_ERROR);                   
          groupPos = BZ_G_SIZE;                       
          gSel = s->selector[groupNo];                
          gMinlen = s->minLens[gSel];                 
          gLimit = &(s->limit[gSel][0]);              
          gPerm = &(s->perm[gSel][0]);                
          gBase = &(s->base[gSel][0]);                
       }                                              
       groupPos--;                                    
       zn = gMinlen;                                  
       GET_BITS(label1, zvec, zn);                    
       while (1) {                                    
          if (zn > 20 /* the longest code */)         
             RETURN(BZ_DATA_ERROR);                   
          if (zvec <= gLimit[zn]) break;              
          zn++;                                       
          GET_BIT(label2, zj);                        
          zvec = (zvec << 1) | zj;                    
       };                                             
       if (zvec - gBase[zn] < 0                       
           || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE)  
          RETURN(BZ_DATA_ERROR);                      
       lval = gPerm[zvec - gBase[zn]];                
    }
    
    
    //#define BZ_OK                0
    
    Int32 BZ2_rNums[512] = {
       619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
       985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
       733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
       419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
       878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
       862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
       150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
       170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
       73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
       909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
       641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
       161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
       382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
       98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
       227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
       469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
       184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
       715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
       951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
       652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
       645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
       609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
       653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
       411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
       170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
       857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
       669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
       944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
       344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
       897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
       433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
       686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
       946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
       978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
       680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
       707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
       297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
       134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
       343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
       140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
       170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
       369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
       804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
       896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
       661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
       768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
       61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
       372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
       780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
       920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
       645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
       936, 638
    };
    
    Int32 BZ2_decompress ( DState* s )
    {
       UChar      uc;
       Int32      retVal;
       Int32      minLen, maxLen;
       bz_stream* strm = s->strm;
    
       /* stuff that needs to be saved/restored */
       Int32  i;
       Int32  j;
       Int32  t;
       Int32  alphaSize;
       Int32  nGroups;
       Int32  nSelectors;
       Int32  EOB;
       Int32  groupNo;
       Int32  groupPos;
       Int32  nextSym;
       Int32  nblockMAX;
       Int32  nblock;
       Int32  es;
       Int32  N;
       Int32  curr;
       Int32  zt;
       Int32  zn;
       Int32  zvec;
       Int32  zj;
       Int32  gSel;
       Int32  gMinlen;
       Int32* gLimit;
       Int32* gBase;
       Int32* gPerm;
    
       if (s->state == BZ_X_MAGIC_1) {
          /*initialise the save area*/
          s->save_i           = 0;
          s->save_j           = 0;
          s->save_t           = 0;
          s->save_alphaSize   = 0;
          s->save_nGroups     = 0;
          s->save_nSelectors  = 0;
          s->save_EOB         = 0;
          s->save_groupNo     = 0;
          s->save_groupPos    = 0;
          s->save_nextSym     = 0;
          s->save_nblockMAX   = 0;
          s->save_nblock      = 0;
          s->save_es          = 0;
          s->save_N           = 0;
          s->save_curr        = 0;
          s->save_zt          = 0;
          s->save_zn          = 0;
          s->save_zvec        = 0;
          s->save_zj          = 0;
          s->save_gSel        = 0;
          s->save_gMinlen     = 0;
          s->save_gLimit      = NULL;
          s->save_gBase       = NULL;
          s->save_gPerm       = NULL;
       }
    
       /*restore from the save area*/
       i           = s->save_i;
       j           = s->save_j;
       t           = s->save_t;
       alphaSize   = s->save_alphaSize;
       nGroups     = s->save_nGroups;
       nSelectors  = s->save_nSelectors;
       EOB         = s->save_EOB;
       groupNo     = s->save_groupNo;
       groupPos    = s->save_groupPos;
       nextSym     = s->save_nextSym;
       nblockMAX   = s->save_nblockMAX;
       nblock      = s->save_nblock;
       es          = s->save_es;
       N           = s->save_N;
       curr        = s->save_curr;
       zt          = s->save_zt;
       zn          = s->save_zn;
       zvec        = s->save_zvec;
       zj          = s->save_zj;
       gSel        = s->save_gSel;
       gMinlen     = s->save_gMinlen;
       gLimit      = s->save_gLimit;
       gBase       = s->save_gBase;
       gPerm       = s->save_gPerm;
    
       retVal = BZ_OK;
    
       switch (s->state) {
    
          GET_UCHAR(BZ_X_MAGIC_1, uc);
          if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC);
    
          GET_UCHAR(BZ_X_MAGIC_2, uc);
          if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC);
    
          GET_UCHAR(BZ_X_MAGIC_3, uc);
          if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC);
    
          GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8);
          if (s->blockSize100k < (BZ_HDR_0 + 1) ||
              s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC);
          s->blockSize100k -= BZ_HDR_0;
    
          if (s->smallDecompress) {
             s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) );
             s->ll4  = BZALLOC(
                          ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar)
                       );
             if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR);
          } else {
             s->tt  = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) );
             if (s->tt == NULL) RETURN(BZ_MEM_ERROR);
          }
    
          GET_UCHAR(BZ_X_BLKHDR_1, uc);
    
          if (uc == 0x17) goto endhdr_2;
          if (uc != 0x31) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_BLKHDR_2, uc);
          if (uc != 0x41) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_BLKHDR_3, uc);
          if (uc != 0x59) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_BLKHDR_4, uc);
          if (uc != 0x26) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_BLKHDR_5, uc);
          if (uc != 0x53) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_BLKHDR_6, uc);
          if (uc != 0x59) RETURN(BZ_DATA_ERROR);
    
          s->currBlockNo++;
          if (s->verbosity >= 2)
             VPrintf1 ( "
        [%d: huff+mtf ", s->currBlockNo );
    
          s->storedBlockCRC = 0;
          GET_UCHAR(BZ_X_BCRC_1, uc);
          s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
          GET_UCHAR(BZ_X_BCRC_2, uc);
          s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
          GET_UCHAR(BZ_X_BCRC_3, uc);
          s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
          GET_UCHAR(BZ_X_BCRC_4, uc);
          s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc);
    
          GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1);
    
          s->origPtr = 0;
          GET_UCHAR(BZ_X_ORIGPTR_1, uc);
          s->origPtr = (s->origPtr << 8) | ((Int32)uc);
          GET_UCHAR(BZ_X_ORIGPTR_2, uc);
          s->origPtr = (s->origPtr << 8) | ((Int32)uc);
          GET_UCHAR(BZ_X_ORIGPTR_3, uc);
          s->origPtr = (s->origPtr << 8) | ((Int32)uc);
    
          if (s->origPtr < 0)
             RETURN(BZ_DATA_ERROR);
          if (s->origPtr > 10 + 100000*s->blockSize100k)
             RETURN(BZ_DATA_ERROR);
    
          /*--- Receive the mapping table ---*/
          for (i = 0; i < 16; i++) {
             GET_BIT(BZ_X_MAPPING_1, uc);
             if (uc == 1)
                s->inUse16[i] = True; else
                s->inUse16[i] = False;
          }
    
          for (i = 0; i < 256; i++) s->inUse[i] = False;
    
          for (i = 0; i < 16; i++)
             if (s->inUse16[i])
                for (j = 0; j < 16; j++) {
                   GET_BIT(BZ_X_MAPPING_2, uc);
                   if (uc == 1) s->inUse[i * 16 + j] = True;
                }
          makeMaps_d ( s );
          if (s->nInUse == 0) RETURN(BZ_DATA_ERROR);
          alphaSize = s->nInUse+2;
    
          /*--- Now the selectors ---*/
          GET_BITS(BZ_X_SELECTOR_1, nGroups, 3);
          if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR);
          GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15);
          if (nSelectors < 1) RETURN(BZ_DATA_ERROR);
          for (i = 0; i < nSelectors; i++) {
             j = 0;
             while (True) {
                GET_BIT(BZ_X_SELECTOR_3, uc);
                if (uc == 0) break;
                j++;
                if (j >= nGroups) RETURN(BZ_DATA_ERROR);
             }
             s->selectorMtf[i] = j;
          }
    
          /*--- Undo the MTF values for the selectors. ---*/
          {
             UChar pos[BZ_N_GROUPS], tmp, v;
             for (v = 0; v < nGroups; v++) pos[v] = v;
    
             for (i = 0; i < nSelectors; i++) {
                v = s->selectorMtf[i];
                tmp = pos[v];
                while (v > 0) { pos[v] = pos[v-1]; v--; }
                pos[0] = tmp;
                s->selector[i] = tmp;
             }
          }
    
          /*--- Now the coding tables ---*/
          for (t = 0; t < nGroups; t++) {
             GET_BITS(BZ_X_CODING_1, curr, 5);
             for (i = 0; i < alphaSize; i++) {
                while (True) {
                   if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR);
                   GET_BIT(BZ_X_CODING_2, uc);
                   if (uc == 0) break;
                   GET_BIT(BZ_X_CODING_3, uc);
                   if (uc == 0) curr++; else curr--;
                }
                s->len[t][i] = curr;
             }
          }
    
          /*--- Create the Huffman decoding tables ---*/
          for (t = 0; t < nGroups; t++) {
             minLen = 32;
             maxLen = 0;
             for (i = 0; i < alphaSize; i++) {
                if (s->len[t][i] > maxLen) maxLen = s->len[t][i];
                if (s->len[t][i] < minLen) minLen = s->len[t][i];
             }
             BZ2_hbCreateDecodeTables (
                &(s->limit[t][0]),
                &(s->base[t][0]),
                &(s->perm[t][0]),
                &(s->len[t][0]),
                minLen, maxLen, alphaSize
             );
             s->minLens[t] = minLen;
          }
    
          /*--- Now the MTF values ---*/
    
          EOB      = s->nInUse+1;
          nblockMAX = 100000 * s->blockSize100k;
          groupNo  = -1;
          groupPos = 0;
    
          for (i = 0; i <= 255; i++) s->unzftab[i] = 0;
    
          /*-- MTF init --*/
          {
             Int32 ii, jj, kk;
             kk = MTFA_SIZE-1;
             for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) {
                for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
                   s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj);
                   kk--;
                }
                s->mtfbase[ii] = kk + 1;
             }
          }
          /*-- end MTF init --*/
    
          nblock = 0;
          GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym);
    
          while (True) {
    
             if (nextSym == EOB) break;
    
             if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) {
    
                es = -1;
                N = 1;
                do {
                   /* Check that N doesn't get too big, so that es doesn't
                      go negative.  The maximum value that can be
                      RUNA/RUNB encoded is equal to the block size (post
                      the initial RLE), viz, 900k, so bounding N at 2
                      million should guard against overflow without
                      rejecting any legitimate inputs. */
                   if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR);
                   if (nextSym == BZ_RUNA) es = es + (0+1) * N; else
                   if (nextSym == BZ_RUNB) es = es + (1+1) * N;
                   N = N * 2;
                   GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym);
                }
                   while (nextSym == BZ_RUNA || nextSym == BZ_RUNB);
    
                es++;
                uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ];
                s->unzftab[uc] += es;
    
                if (s->smallDecompress)
                   while (es > 0) {
                      if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
                      s->ll16[nblock] = (UInt16)uc;
                      nblock++;
                      es--;
                   }
                else
                   while (es > 0) {
                      if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
                      s->tt[nblock] = (UInt32)uc;
                      nblock++;
                      es--;
                   };
    
                continue;
    
             } else {
    
                if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR);
    
                /*-- uc = MTF ( nextSym-1 ) --*/
                {
                   Int32 ii, jj, kk, pp, lno, off;
                   UInt32 nn;
                   nn = (UInt32)(nextSym - 1);
    
                   if (nn < MTFL_SIZE) {
                      /* avoid general-case expense */
                      pp = s->mtfbase[0];
                      uc = s->mtfa[pp+nn];
                      while (nn > 3) {
                         Int32 z = pp+nn;
                         s->mtfa[(z)  ] = s->mtfa[(z)-1];
                         s->mtfa[(z)-1] = s->mtfa[(z)-2];
                         s->mtfa[(z)-2] = s->mtfa[(z)-3];
                         s->mtfa[(z)-3] = s->mtfa[(z)-4];
                         nn -= 4;
                      }
                      while (nn > 0) {
                         s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--;
                      };
                      s->mtfa[pp] = uc;
                   } else {
                      /* general case */
                      lno = nn / MTFL_SIZE;
                      off = nn % MTFL_SIZE;
                      pp = s->mtfbase[lno] + off;
                      uc = s->mtfa[pp];
                      while (pp > s->mtfbase[lno]) {
                         s->mtfa[pp] = s->mtfa[pp-1]; pp--;
                      };
                      s->mtfbase[lno]++;
                      while (lno > 0) {
                         s->mtfbase[lno]--;
                         s->mtfa[s->mtfbase[lno]]
                            = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1];
                         lno--;
                      }
                      s->mtfbase[0]--;
                      s->mtfa[s->mtfbase[0]] = uc;
                      if (s->mtfbase[0] == 0) {
                         kk = MTFA_SIZE-1;
                         for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) {
                            for (jj = MTFL_SIZE-1; jj >= 0; jj--) {
                               s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj];
                               kk--;
                            }
                            s->mtfbase[ii] = kk + 1;
                         }
                      }
                   }
                }
                /*-- end uc = MTF ( nextSym-1 ) --*/
    
                s->unzftab[s->seqToUnseq[uc]]++;
                if (s->smallDecompress)
                   s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else
                   s->tt[nblock]   = (UInt32)(s->seqToUnseq[uc]);
                nblock++;
    
                GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym);
                continue;
             }
          }
    
          /* Now we know what nblock is, we can do a better sanity
             check on s->origPtr.
          */
          if (s->origPtr < 0 || s->origPtr >= nblock)
             RETURN(BZ_DATA_ERROR);
    
          /*-- Set up cftab to facilitate generation of T^(-1) --*/
          /* Check: unzftab entries in range. */
          for (i = 0; i <= 255; i++) {
             if (s->unzftab[i] < 0 || s->unzftab[i] > nblock)
                RETURN(BZ_DATA_ERROR);
          }
          /* Actually generate cftab. */
          s->cftab[0] = 0;
          for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1];
          for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1];
          /* Check: cftab entries in range. */
          for (i = 0; i <= 256; i++) {
             if (s->cftab[i] < 0 || s->cftab[i] > nblock) {
                /* s->cftab[i] can legitimately be == nblock */
                RETURN(BZ_DATA_ERROR);
             }
          }
          /* Check: cftab entries non-descending. */
          for (i = 1; i <= 256; i++) {
             if (s->cftab[i-1] > s->cftab[i]) {
                RETURN(BZ_DATA_ERROR);
             }
          }
    
          s->state_out_len = 0;
          s->state_out_ch  = 0;
          BZ_INITIALISE_CRC ( s->calculatedBlockCRC );
          s->state = BZ_X_OUTPUT;
          if (s->verbosity >= 2) VPrintf0 ( "rt+rld" );
    
          if (s->smallDecompress) {
    
             /*-- Make a copy of cftab, used in generation of T --*/
             for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i];
    
             /*-- compute the T vector --*/
             for (i = 0; i < nblock; i++) {
                uc = (UChar)(s->ll16[i]);
                SET_LL(i, s->cftabCopy[uc]);
                s->cftabCopy[uc]++;
             }
    
             /*-- Compute T^(-1) by pointer reversal on T --*/
             i = s->origPtr;
             j = GET_LL(i);
             do {
                Int32 tmp = GET_LL(j);
                SET_LL(j, i);
                i = j;
                j = tmp;
             }
                while (i != s->origPtr);
    
             s->tPos = s->origPtr;
             s->nblock_used = 0;
             if (s->blockRandomised) {
                BZ_RAND_INIT_MASK;
                BZ_GET_SMALL(s->k0); s->nblock_used++;
                BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
             } else {
                BZ_GET_SMALL(s->k0); s->nblock_used++;
             }
    
          } else {
    
             /*-- compute the T^(-1) vector --*/
             for (i = 0; i < nblock; i++) {
                uc = (UChar)(s->tt[i] & 0xff);
                s->tt[s->cftab[uc]] |= (i << 8);
                s->cftab[uc]++;
             }
    
             s->tPos = s->tt[s->origPtr] >> 8;
             s->nblock_used = 0;
             if (s->blockRandomised) {
                BZ_RAND_INIT_MASK;
                BZ_GET_FAST(s->k0); s->nblock_used++;
                BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK;
             } else {
                BZ_GET_FAST(s->k0); s->nblock_used++;
             }
    
          }
    
          RETURN(BZ_OK);
    
    
    
        endhdr_2:
    
          GET_UCHAR(BZ_X_ENDHDR_2, uc);
          if (uc != 0x72) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_ENDHDR_3, uc);
          if (uc != 0x45) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_ENDHDR_4, uc);
          if (uc != 0x38) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_ENDHDR_5, uc);
          if (uc != 0x50) RETURN(BZ_DATA_ERROR);
          GET_UCHAR(BZ_X_ENDHDR_6, uc);
          if (uc != 0x90) RETURN(BZ_DATA_ERROR);
    
          s->storedCombinedCRC = 0;
          GET_UCHAR(BZ_X_CCRC_1, uc);
          s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
          GET_UCHAR(BZ_X_CCRC_2, uc);
          s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
          GET_UCHAR(BZ_X_CCRC_3, uc);
          s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
          GET_UCHAR(BZ_X_CCRC_4, uc);
          s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc);
    
          s->state = BZ_X_IDLE;
          RETURN(BZ_STREAM_END);
    
          default: AssertH ( False, 4001 );
    //      default:RETURN(BZ_OK);
       }
    
       AssertH ( False, 4002 );
    
       save_state_and_return:
    
       s->save_i           = i;
       s->save_j           = j;
       s->save_t           = t;
       s->save_alphaSize   = alphaSize;
       s->save_nGroups     = nGroups;
       s->save_nSelectors  = nSelectors;
       s->save_EOB         = EOB;
       s->save_groupNo     = groupNo;
       s->save_groupPos    = groupPos;
       s->save_nextSym     = nextSym;
       s->save_nblockMAX   = nblockMAX;
       s->save_nblock      = nblock;
       s->save_es          = es;
       s->save_N           = N;
       s->save_curr        = curr;
       s->save_zt          = zt;
       s->save_zn          = zn;
       s->save_zvec        = zvec;
       s->save_zj          = zj;
       s->save_gSel        = gSel;
       s->save_gMinlen     = gMinlen;
       s->save_gLimit      = gLimit;
       s->save_gBase       = gBase;
       s->save_gPerm       = gPerm;
    
       return retVal;
    }
    
    #define BZ_SETERR(eee)                    
    {                                         
       if (bzerror != NULL) *bzerror = eee;   
       if (bzf != NULL) bzf->lastErr = eee;   
    }
    
    typedef
       struct {
          FILE*     handle;
          Char      buf[BZ_MAX_UNUSED];
          Int32     bufN;
          Bool      writing;
          bz_stream strm;
          Int32     lastErr;
          Bool      initialisedOk;
       }
       bzFile;
    
       static
       void* default_bzalloc ( void* opaque, Int32 items, Int32 size )
       {
          void* v = malloc ( items * size );
          return v;
       }
    
       static
       void default_bzfree ( void* opaque, void* addr )
       {
          if (addr != NULL) free ( addr );
       }
    
       static Bool myfeof ( FILE* f )
       {
          Int32 c = fgetc ( f );
          if (c == EOF) return True;
          ungetc ( c, f );
          return False;
       }
    
       static
       int bz_config_ok ( void )
       {
          if (sizeof(int)   != 4) return 0;
          if (sizeof(short) != 2) return 0;
          if (sizeof(char)  != 1) return 0;
          return 1;
       }
    
       UInt32 BZ2_crc32Table[256] = {
    
          /*-- Ugly, innit?

    --*/ 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L }; const char * BZ_API(BZ2_bzlibVersion)(void) { return BZ_VERSION; } __inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) { Int32 nb, na, mid; nb = 0; na = 256; do { mid = (nb + na) >> 1; if (indx >= cftab[mid]) nb = mid; else na = mid; } while (na - nb != 1); return nb; } static Bool unRLE_obuf_to_output_SMALL ( DState* s ) { UChar k1; if (s->blockRandomised) { while (True) { /* try to finish existing run */ while (True) { if (s->strm->avail_out == 0) return False; if (s->state_out_len == 0) break; *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); s->state_out_len--; s->strm->next_out++; s->strm->avail_out--; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } /* can a new run be started?

    */ if (s->nblock_used == s->save_nblock+1) return False; /* Only caused by corrupt data stream? */ if (s->nblock_used > s->save_nblock+1) return True; s->state_out_len = 1; s->state_out_ch = s->k0; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 2; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 3; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; s->state_out_len = ((Int32)k1) + 4; BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; s->nblock_used++; } } else { while (True) { /* try to finish existing run */ while (True) { if (s->strm->avail_out == 0) return False; if (s->state_out_len == 0) break; *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); s->state_out_len--; s->strm->next_out++; s->strm->avail_out--; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } /* can a new run be started? */ if (s->nblock_used == s->save_nblock+1) return False; /* Only caused by corrupt data stream? */ if (s->nblock_used > s->save_nblock+1) return True; s->state_out_len = 1; s->state_out_ch = s->k0; BZ_GET_SMALL(k1); s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 2; BZ_GET_SMALL(k1); s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 3; BZ_GET_SMALL(k1); s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; BZ_GET_SMALL(k1); s->nblock_used++; s->state_out_len = ((Int32)k1) + 4; BZ_GET_SMALL(s->k0); s->nblock_used++; } } } jint JNI_OnLoad(JavaVM* vm, void* reserved) { JNIEnv* env = NULL; jint result = -1; if ((*vm)->GetEnv(vm,(void**) &env, JNI_VERSION_1_4) != JNI_OK) { //if (vm->GetEnv(vm,(void**) &env, JNI_VERSION_1_4) != JNI_OK) { __android_log_print(ANDROID_LOG_INFO, "JNIMsg", "ERROR: GetEnv failed"); goto bail; } // assert(env != NULL); // if (register_android_boa(env) < 0) { // __android_log_print(ANDROID_LOG_INFO,"JNIMsg", "ERROR: Boa Server native registration failed"); // goto bail; // } /* success -- return valid version number */ result = JNI_VERSION_1_4; bail: return result; } int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) { DState* s; if (strm == NULL) return BZ_PARAM_ERROR; s = strm->state; if (s == NULL) return BZ_PARAM_ERROR; if (s->strm != strm) return BZ_PARAM_ERROR; if (s->tt != NULL) BZFREE(s->tt); if (s->ll16 != NULL) BZFREE(s->ll16); if (s->ll4 != NULL) BZFREE(s->ll4); BZFREE(strm->state); strm->state = NULL; return BZ_OK; } void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) { bzFile* bzf = (bzFile*)b; BZ_SETERR(BZ_OK); if (bzf == NULL) { BZ_SETERR(BZ_OK); return; }; if (bzf->writing) { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; if (bzf->initialisedOk) (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); free ( bzf ); } static Bool unRLE_obuf_to_output_FAST ( DState* s ) { UChar k1; if (s->blockRandomised) { while (True) { /* try to finish existing run */ while (True) { if (s->strm->avail_out == 0) return False; if (s->state_out_len == 0) break; *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); s->state_out_len--; s->strm->next_out++; s->strm->avail_out--; s->strm->total_out_lo32++; if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; } /* can a new run be started? */ if (s->nblock_used == s->save_nblock+1) return False; /* Only caused by corrupt data stream? */ if (s->nblock_used > s->save_nblock+1) return True; s->state_out_len = 1; s->state_out_ch = s->k0; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 2; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; s->state_out_len = 3; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; if (s->nblock_used == s->save_nblock+1) continue; if (k1 != s->k0) { s->k0 = k1; continue; }; BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; k1 ^= BZ_RAND_MASK; s->nblock_used++; s->state_out_len = ((Int32)k1) + 4; BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; s->nblock_used++; } } else { /* restore */ UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; UChar c_state_out_ch = s->state_out_ch; Int32 c_state_out_len = s->state_out_len; Int32 c_nblock_used = s->nblock_used; Int32 c_k0 = s->k0; UInt32* c_tt = s->tt; UInt32 c_tPos = s->tPos; char* cs_next_out = s->strm->next_out; unsigned int cs_avail_out = s->strm->avail_out; Int32 ro_blockSize100k = s->blockSize100k; /* end restore */ UInt32 avail_out_INIT = cs_avail_out; Int32 s_save_nblockPP = s->save_nblock+1; unsigned int total_out_lo32_old; while (True) { /* try to finish existing run */ if (c_state_out_len > 0) { while (True) { if (cs_avail_out == 0) goto return_notr; if (c_state_out_len == 1) break; *( (UChar*)(cs_next_out) ) = c_state_out_ch; BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); c_state_out_len--; cs_next_out++; cs_avail_out--; } s_state_out_len_eq_one: { if (cs_avail_out == 0) { c_state_out_len = 1; goto return_notr; }; *( (UChar*)(cs_next_out) ) = c_state_out_ch; BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); cs_next_out++; cs_avail_out--; } } /* Only caused by corrupt data stream?

    */ if (c_nblock_used > s_save_nblockPP) return True; /* can a new run be started?

    */ if (c_nblock_used == s_save_nblockPP) { c_state_out_len = 0; goto return_notr; }; c_state_out_ch = c_k0; BZ_GET_FAST_C(k1); c_nblock_used++; if (k1 != c_k0) { c_k0 = k1; goto s_state_out_len_eq_one; }; if (c_nblock_used == s_save_nblockPP) goto s_state_out_len_eq_one; c_state_out_len = 2; BZ_GET_FAST_C(k1); c_nblock_used++; if (c_nblock_used == s_save_nblockPP) continue; if (k1 != c_k0) { c_k0 = k1; continue; }; c_state_out_len = 3; BZ_GET_FAST_C(k1); c_nblock_used++; if (c_nblock_used == s_save_nblockPP) continue; if (k1 != c_k0) { c_k0 = k1; continue; }; BZ_GET_FAST_C(k1); c_nblock_used++; c_state_out_len = ((Int32)k1) + 4; BZ_GET_FAST_C(c_k0); c_nblock_used++; } return_notr: total_out_lo32_old = s->strm->total_out_lo32; s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); if (s->strm->total_out_lo32 < total_out_lo32_old) s->strm->total_out_hi32++; /* save */ s->calculatedBlockCRC = c_calculatedBlockCRC; s->state_out_ch = c_state_out_ch; s->state_out_len = c_state_out_len; s->nblock_used = c_nblock_used; s->k0 = c_k0; s->tt = c_tt; s->tPos = c_tPos; s->strm->next_out = cs_next_out; s->strm->avail_out = cs_avail_out; /* end save */ } return False; } void BZ2_bz__AssertH__fail ( int errcode ) { fprintf(stderr, " bzip2/libbzip2: internal error number %d. " "This is a bug in bzip2/libbzip2, %s. " "Please report it to me at: jseward@bzip.org. If this happened " "when you were using some program which uses libbzip2 as a " "component, you should also report this bug to the author(s) " "of that program. Please make an effort to report this bug; " "timely and accurate bug reports eventually lead to higher " "quality software. Thanks. Julian Seward, 10 December 2007. ", errcode, BZ2_bzlibVersion() ); if (errcode == 1007) { fprintf(stderr, " *** A special note about internal error number 1007 *** " " " "Experience suggests that a common cause of i.e. 1007 " "is unreliable memory or other hardware. The 1007 assertion " "just happens to cross-check the results of huge numbers of " "memory reads/writes, and so acts (unintendedly) as a stress " "test of your memory system. " " " "I suggest the following: try compressing the file again, " "possibly monitoring progress in detail with the -vv flag. " " " "* If the error cannot be reproduced, and/or happens at different " " points in compression, you may have a flaky memory system. " " Try a memory-test program. I have used Memtest86 " " (www.memtest86.com). At the time of writing it is free (GPLd). " " Memtest86 tests memory much more thorougly than your BIOSs " " power-on test, and may find failures that the BIOS doesn't. " " " "* If the error can be repeatably reproduced, this is a bug in " " bzip2, and I would very much like to hear about it. Please " " let me know, and, ideally, save a copy of the file causing the " " problem -- without which I will be unable to investigate it. " " " ); } exit(3); } int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) { Bool corrupt; DState* s; if (strm == NULL) return BZ_PARAM_ERROR; s = strm->state; if (s == NULL) return BZ_PARAM_ERROR; if (s->strm != strm) return BZ_PARAM_ERROR; while (True) { if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; if (s->state == BZ_X_OUTPUT) { if (s->smallDecompress) corrupt = unRLE_obuf_to_output_SMALL ( s ); else corrupt = unRLE_obuf_to_output_FAST ( s ); if (corrupt) return BZ_DATA_ERROR; if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { BZ_FINALISE_CRC ( s->calculatedBlockCRC ); if (s->verbosity >= 3) VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, s->calculatedBlockCRC ); if (s->verbosity >= 2) VPrintf0 ( "]" ); if (s->calculatedBlockCRC != s->storedBlockCRC) return BZ_DATA_ERROR; s->calculatedCombinedCRC = (s->calculatedCombinedCRC << 1) | (s->calculatedCombinedCRC >> 31); s->calculatedCombinedCRC ^= s->calculatedBlockCRC; s->state = BZ_X_BLKHDR_1; } else { return BZ_OK; } } if (s->state >= BZ_X_MAGIC_1) { Int32 r = BZ2_decompress ( s ); if (r == BZ_STREAM_END) { if (s->verbosity >= 3) VPrintf2 ( " combined CRCs: stored = 0x%08x, computed = 0x%08x", s->storedCombinedCRC, s->calculatedCombinedCRC ); if (s->calculatedCombinedCRC != s->storedCombinedCRC) return BZ_DATA_ERROR; return r; } if (s->state != BZ_X_OUTPUT) return r; } } AssertH ( 0, 6001 ); return 0; /*NOTREACHED*/ } int BZ_API(BZ2_bzDecompressInit) ( bz_stream* strm, int verbosity, int small ) { DState* s; if (!bz_config_ok()) return BZ_CONFIG_ERROR; if (strm == NULL) return BZ_PARAM_ERROR; if (small != 0 && small != 1) return BZ_PARAM_ERROR; if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; if (strm->bzfree == NULL) strm->bzfree = default_bzfree; s = BZALLOC( sizeof(DState) ); if (s == NULL) return BZ_MEM_ERROR; s->strm = strm; strm->state = s; s->state = BZ_X_MAGIC_1; s->bsLive = 0; s->bsBuff = 0; s->calculatedCombinedCRC = 0; strm->total_in_lo32 = 0; strm->total_in_hi32 = 0; strm->total_out_lo32 = 0; strm->total_out_hi32 = 0; s->smallDecompress = (Bool)small; s->ll4 = NULL; s->ll16 = NULL; s->tt = NULL; s->currBlockNo = 0; s->verbosity = verbosity; return BZ_OK; } int BZ_API(BZ2_bzRead) ( int* bzerror, BZFILE* b, void* buf, int len ) { Int32 n, ret; bzFile* bzf = (bzFile*)b; BZ_SETERR(BZ_OK); if (bzf == NULL || buf == NULL || len < 0) { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; if (bzf->writing) { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; if (len == 0) { BZ_SETERR(BZ_OK); return 0; }; bzf->strm.avail_out = len; bzf->strm.next_out = buf; while (1) { if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return 0; }; if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { n = fread ( bzf->buf, sizeof(UChar), BZ_MAX_UNUSED, bzf->handle ); if (ferror(bzf->handle)) { BZ_SETERR(BZ_IO_ERROR); return 0; }; bzf->bufN = n; bzf->strm.avail_in = bzf->bufN; bzf->strm.next_in = bzf->buf; } ret = BZ2_bzDecompress ( &(bzf->strm) ); if (ret != BZ_OK && ret != BZ_STREAM_END) { BZ_SETERR(ret); return 0; }; if (ret == BZ_OK && myfeof(bzf->handle) && bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; if (ret == BZ_STREAM_END) { BZ_SETERR(BZ_STREAM_END); return len - bzf->strm.avail_out; }; if (bzf->strm.avail_out == 0) { BZ_SETERR(BZ_OK); return len; }; } return -1; /*not reached*/ } BZFILE* BZ_API(BZ2_bzReadOpen) ( int* bzerror, FILE* f, int verbosity, int small, void* unused, int nUnused ) { bzFile* bzf = NULL; int ret; BZ_SETERR(BZ_OK); if (f == NULL || (small != 0 && small != 1) || (verbosity < 0 || verbosity > 4) || (unused == NULL && nUnused != 0) || (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; if (ferror(f)) { BZ_SETERR(BZ_IO_ERROR); return NULL; }; bzf = malloc ( sizeof(bzFile) ); if (bzf == NULL) { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; BZ_SETERR(BZ_OK); bzf->initialisedOk = False; bzf->handle = f; bzf->bufN = 0; bzf->writing = False; bzf->strm.bzalloc = NULL; bzf->strm.bzfree = NULL; bzf->strm.opaque = NULL; while (nUnused > 0) { bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; unused = ((void*)( 1 + ((UChar*)(unused)) )); nUnused--; } ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); if (ret != BZ_OK) { BZ_SETERR(ret); free(bzf); return NULL; }; bzf->strm.avail_in = bzf->bufN; bzf->strm.next_in = bzf->buf; bzf->initialisedOk = True; return bzf; } static off_t offtin(u_char *buf) { off_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; } int applypatch(int argc,char * argv[]) { FILE * f, * cpf, * dpf, * epf; BZFILE * cpfbz2, * dpfbz2, * epfbz2; int cbz2err, dbz2err, ebz2err; int fd; ssize_t oldsize,newsize; ssize_t bzctrllen,bzdatalen; u_char header[32],buf[8]; u_char *old, *new; off_t oldpos,newpos; off_t ctrl[3]; off_t lenread; off_t i; /* Open patch file */ if ((f = fopen(argv[3], "r")) == NULL) err(1, "fopen(%s)", argv[3]); /* Read header */ if (fread(header, 1, 32, f) < 32) { if (feof(f)) errx(1, "Corrupt patch "); err(1, "fread(%s)", argv[3]); } /* Check for appropriate magic */ if (memcmp(header, "BSDIFF40", 8) != 0) errx(1, "Corrupt patch "); /* Read lengths from header */ bzctrllen=offtin(header+8); bzdatalen=offtin(header+16); newsize=offtin(header+24); if((bzctrllen<0) || (bzdatalen<0) || (newsize<0)) errx(1,"Corrupt patch "); /* Close patch file and re-open it via libbzip2 at the right places */ if (fclose(f)) err(1, "fclose(%s)", argv[3]); if ((cpf = fopen(argv[3], "r")) == NULL) err(1, "fopen(%s)", argv[3]); if (fseeko(cpf, 32, SEEK_SET)) err(1, "fseeko(%s, %lld)", argv[3], (long long)32); cpfbz2 = BZ2_bzReadOpen(&cbz2err, cpf, 0, 0, NULL, 0); if ((cpfbz2) == NULL) errx(1, "BZ2_bzReadOpen, bz2err = %d", cbz2err); if ((dpf = fopen(argv[3], "r")) == NULL) err(1, "fopen(%s)", argv[3]); if (fseeko(dpf, 32 + bzctrllen, SEEK_SET)) err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen)); if ((dpfbz2 = BZ2_bzReadOpen(&dbz2err, dpf, 0, 0, NULL, 0)) == NULL) errx(1, "BZ2_bzReadOpen, bz2err = %d", dbz2err); if ((epf = fopen(argv[3], "r")) == NULL) err(1, "fopen(%s)", argv[3]); if (fseeko(epf, 32 + bzctrllen + bzdatalen, SEEK_SET)) err(1, "fseeko(%s, %lld)", argv[3], (long long)(32 + bzctrllen + bzdatalen)); if ((epfbz2 = BZ2_bzReadOpen(&ebz2err, epf, 0, 0, NULL, 0)) == NULL) errx(1, "BZ2_bzReadOpen, bz2err = %d", ebz2err); if(((fd=open(argv[1],O_RDONLY,0))<0) || ((oldsize=lseek(fd,0,SEEK_END))==-1) || ((old=malloc(oldsize+1))==NULL) || (lseek(fd,0,SEEK_SET)!=0) || (read(fd,old,oldsize)!=oldsize) || (close(fd)==-1)) err(1,"%s",argv[1]); if((new=malloc(newsize+1))==NULL) err(1,NULL); oldpos=0;newpos=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))) errx(1, "Corrupt patch "); ctrl[i]=offtin(buf); } /* Sanity-check */ if(newpos+ctrl[0]>newsize) errx(1,"Corrupt patch "); /* Read diff string */ lenread = BZ2_bzRead(&dbz2err, dpfbz2, new + newpos, ctrl[0]); if ((lenread < ctrl[0]) || ((dbz2err != BZ_OK) && (dbz2err != BZ_STREAM_END))) errx(1, "Corrupt patch "); /* Add old data to diff string */ for(i=0;i<ctrl[0];i++) if((oldpos+i>=0) && (oldpos+i<oldsize)) new[newpos+i]+=old[oldpos+i]; /* Adjust pointers */ newpos+=ctrl[0]; oldpos+=ctrl[0]; /* Sanity-check */ if(newpos+ctrl[1]>newsize) errx(1,"Corrupt patch "); /* Read extra string */ lenread = BZ2_bzRead(&ebz2err, epfbz2, new + newpos, ctrl[1]); if ((lenread < ctrl[1]) || ((ebz2err != BZ_OK) && (ebz2err != BZ_STREAM_END))) errx(1, "Corrupt patch "); /* Adjust pointers */ newpos+=ctrl[1]; oldpos+=ctrl[2]; } /* Clean up the bzip2 reads */ BZ2_bzReadClose(&cbz2err, cpfbz2); BZ2_bzReadClose(&dbz2err, dpfbz2); BZ2_bzReadClose(&ebz2err, epfbz2); if (fclose(cpf) || fclose(dpf) || fclose(epf)){ err(1, "fclose(%s)", argv[3]); } if((fd=open(argv[2],O_CREAT|O_RDWR|O_TRUNC,0777))<0){ } if(write(fd,new,newsize)!=newsize){ } if(close(fd)==-1){ } free(new); free(old); return 0; } JNIEXPORT jint JNICALL Java_com_example_selfincrease_PatchUpdate_patch(JNIEnv *env, jobject obj, jstring old, jstring new , jstring patch) { char * ch[4]; ch[0]="bspatch"; ch[1]=(char*)((*env)->GetStringUTFChars(env,old, 0)); ch[2]=(char*)((*env)->GetStringUTFChars(env,new, 0)); ch[3]=(char*)((*env)->GetStringUTFChars(env,patch, 0)); int ret=applypatch(4, ch); (*env)->ReleaseStringUTFChars(env,old,ch[1]); (*env)->ReleaseStringUTFChars(env,new,ch[2]); (*env)->ReleaseStringUTFChars(env,patch,ch[3]); //return (*env)->NewStringUTF(env,"success"); return ret; }

    注意两点:
    1. 引入”头文件”
    #include “com_example_selfincrease_PatchUpdate.h”
    2. 实现生命的本地方法patch
    Java_com_example_selfincrease_PatchUpdate_patch

    JNIEXPORT jint JNICALL Java_com_example_selfincrease_PatchUpdate_patch(JNIEnv *env,
            jobject obj, jstring old, jstring new , jstring patch)
    {
          char * ch[4];
          ch[0]="bspatch";
          ch[1]=(char*)((*env)->GetStringUTFChars(env,old, 0));
          ch[2]=(char*)((*env)->GetStringUTFChars(env,new, 0));
          ch[3]=(char*)((*env)->GetStringUTFChars(env,patch, 0));
    
          int ret=applypatch(4, ch);
          (*env)->ReleaseStringUTFChars(env,old,ch[1]);
          (*env)->ReleaseStringUTFChars(env,new,ch[2]);
          (*env)->ReleaseStringUTFChars(env,patch,ch[3]);
    
          //return (*env)->NewStringUTF(env,"success");
          return ret;
    }

    编写Android.mk文件:

    LOCAL_PATH := $(call my-dir)
    
    include $(CLEAR_VARS)
    LOCAL_MODULE    := increase
    LOCAL_CXXFLAGS :=
    LOCAL_C_INCLUDES := $(LOCAL_PATH)
    LOCAL_SRC_FILES := com_example_selfincrease_PatchUpdate.c
    LOCAL_LDLIBS := -lz -llog
    include $(BUILD_SHARED_LIBRARY)

    这里我声明编译出来的模块是increase。

    上层代码调用

    使用loadLibrary引入模块

    底层的c代码以及Android.mk文件都实现了以后。就是在上层载入了,这里我们在PatchUpdate类中载入:

    static{
            System.loadLibrary("increase");
        }

    能够看到这里载入的是increase模块。就是在Android.mk文件里声明的。

    MainActivity中调用

    在调用之前,当然须要将之前生成好的”increaseone1.0.apk”以及increase.patch文件拷贝至手机里,这里我复制到”storage/sdcard0/123”文件夹下:

    MainActivity.java

    package com.example.selfincrease;
    
    import android.app.Activity;
    import android.os.Bundle;
    import android.os.Environment;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
         String sd  =   Environment.getExternalStorageDirectory()   +   "/123/";
         String patch   =   "increase.patch";
         String oldapk  =   "increaseone1.0.apk";
    
         String oldapk_filepath =   sd  +   oldapk;
         String newapk_savepath =   sd  +   "new.apk";
         String patchpath = sd  +   patch;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            PatchUpdate patchInterence  =   new PatchUpdate();
            /**
             * oldapk_filepath  旧apk的路径
             * newapk_savepath  合成的apk路径
             * patchpath        查分包patch的路径
             */
            patchInterence.patch(oldapk_filepath, newapk_savepath, patchpath);
            Toast.makeText(MainActivity.this, "新的apk已经合成"   +   sd  +   "文件夹以下", Toast.LENGTH_LONG).show();
        }
    
    }
    

    能够看到这里主要是调用的patchInterence.patch(oldapk_filepath, newapk_savepath, patchpath);来实现patch的合成,也就是核心的工作是由底层的c代码来实现的。

    使用ndk-build编译

    接下来就是使用ndk-build来编译生成so文件。

    这里我在window下使用的是cygwine。不清楚的能够參考 一步一步学习androidNDK编程(搭建开发环境)
    这里写图片描写叙述

    编译好之后,会生成一个libincrease.so文件,此时执行selfincreaseproject,就会在指定文件夹下生成新的合成后的new.apk文件。


    这里写图片描写叙述
    注意:
    因为须要给sdcard上写入新的apk文件,所以须要在manifest中声明一下权限:

    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    此时安装执行new.apk,如图:
    这里写图片描写叙述
    和我们最新版本号的apk执行效果是相同的。说明我们已经合成新的apk成功了。

    总结

    1. 使用bsdiff4.3对新旧apk生成差分包
    2. 依据差分包合成新的apk文件。

    源代码下载

  • 相关阅读:
    10 Programming Languages You Should Learn Right Now
    【Vegas原创】asp.net页面作为邮件正文发送
    【Vegas原创】产生文件编号(形如:SC000610001)
    ASP操作Excel技术总结
    【Vegas原创】asp/html页面作为邮件正文发送
    【Vegas原创】jmail 发邮件
    ADO.NET 如何读取 Excel (下)
    【Vegas原创】Ajax实现无刷新三联动
    【Vegas原创】Excel权限问题
    成为编程高手的八大奥秘
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7223717.html
Copyright © 2011-2022 走看看