tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

zip.c (19819B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "signtool.h"
      6 #include "zip.h"
      7 #include "zlib.h"
      8 #include "prmem.h"
      9 
     10 static void inttox(int in, char *out);
     11 static void longtox(long in, char *out);
     12 
     13 /****************************************************************
     14 *
     15 * J z i p O p e n
     16 *
     17 * Opens a new ZIP file and creates a new ZIPfile structure to
     18 * control the process of installing files into a zip.
     19 */
     20 ZIPfile *
     21 JzipOpen(char *filename, char *comment)
     22 {
     23    ZIPfile *zipfile;
     24    PRExplodedTime prtime;
     25 
     26    zipfile = PORT_ZAlloc(sizeof(ZIPfile));
     27    if (!zipfile)
     28        out_of_memory();
     29 
     30    /* Construct time and date */
     31    PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime);
     32    zipfile->date = ((prtime.tm_year - 1980) << 9) |
     33                    ((prtime.tm_month + 1) << 5) |
     34                    prtime.tm_mday;
     35    zipfile->time = (prtime.tm_hour << 11) |
     36                    (prtime.tm_min << 5) |
     37                    (prtime.tm_sec & 0x3f);
     38 
     39    zipfile->fp = NULL;
     40    if (filename &&
     41        (zipfile->fp = PR_Open(filename,
     42                               PR_WRONLY |
     43                                   PR_CREATE_FILE |
     44                                   PR_TRUNCATE,
     45                               0777)) == NULL) {
     46        char *nsprErr;
     47        if (PR_GetErrorTextLength()) {
     48            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
     49            PR_GetErrorText(nsprErr);
     50        } else {
     51            nsprErr = NULL;
     52        }
     53        PR_fprintf(errorFD, "%s: can't open output jar, %s.%s\n",
     54                   PROGRAM_NAME,
     55                   filename, nsprErr ? nsprErr : "");
     56        if (nsprErr)
     57            PR_Free(nsprErr);
     58        errorCount++;
     59        exit(ERRX);
     60    }
     61 
     62    zipfile->list = NULL;
     63    if (filename) {
     64        zipfile->filename = PORT_ZAlloc(strlen(filename) + 1);
     65        if (!zipfile->filename)
     66            out_of_memory();
     67        PORT_Strcpy(zipfile->filename, filename);
     68    }
     69    if (comment) {
     70        zipfile->comment = PORT_ZAlloc(strlen(comment) + 1);
     71        if (!zipfile->comment)
     72            out_of_memory();
     73        PORT_Strcpy(zipfile->comment, comment);
     74    }
     75 
     76    return zipfile;
     77 }
     78 
     79 static void *
     80 my_alloc_func(void *opaque, uInt items, uInt size)
     81 {
     82    return PORT_Alloc(items * size);
     83 }
     84 
     85 static void
     86 my_free_func(void *opaque, void *address)
     87 {
     88    PORT_Free(address);
     89 }
     90 
     91 static void
     92 handle_zerror(int err, char *msg)
     93 {
     94    if (!msg) {
     95        msg = "";
     96    }
     97 
     98    errorCount++; /* unless Z_OK...see below */
     99 
    100    switch (err) {
    101        case Z_OK:
    102            PR_fprintf(errorFD, "No error: %s\n", msg);
    103            errorCount--; /* this was incremented above */
    104            break;
    105        case Z_MEM_ERROR:
    106            PR_fprintf(errorFD, "Deflation ran out of memory: %s\n", msg);
    107            break;
    108        case Z_STREAM_ERROR:
    109            PR_fprintf(errorFD, "Invalid compression level: %s\n", msg);
    110            break;
    111        case Z_VERSION_ERROR:
    112            PR_fprintf(errorFD, "Incompatible compression library version: %s\n",
    113                       msg);
    114            break;
    115        case Z_DATA_ERROR:
    116            PR_fprintf(errorFD, "Compression data error: %s\n", msg);
    117            break;
    118        default:
    119            PR_fprintf(errorFD, "Unknown error in compression library: %s\n", msg);
    120            break;
    121    }
    122 }
    123 
    124 /****************************************************************
    125 *
    126 * J z i p A d d
    127 *
    128 * Adds a new file into a ZIP file.  The ZIP file must have already
    129 * been opened with JzipOpen.
    130 */
    131 int
    132 JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, int lvl)
    133 {
    134    ZIPentry *entry;
    135    PRFileDesc *readfp;
    136    PRFileDesc *zipfp;
    137    unsigned long crc;
    138    unsigned long local_size_pos;
    139    int num;
    140    int err;
    141    int deflate_percent;
    142    z_stream zstream;
    143    Bytef inbuf[BUFSIZ];
    144    Bytef outbuf[BUFSIZ];
    145 
    146    if (!fullname || !filename || !zipfile) {
    147        return -1;
    148    }
    149 
    150    zipfp = zipfile->fp;
    151    if (!zipfp)
    152        return -1;
    153 
    154    if ((readfp = PR_Open(fullname, PR_RDONLY, 0777)) == NULL) {
    155        char *nsprErr;
    156        if (PR_GetErrorTextLength()) {
    157            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    158            PR_GetErrorText(nsprErr);
    159        } else {
    160            nsprErr = NULL;
    161        }
    162        PR_fprintf(errorFD, "%s: %s\n", fullname, nsprErr ? nsprErr : "");
    163        errorCount++;
    164        if (nsprErr)
    165            PR_Free(nsprErr);
    166        exit(ERRX);
    167    }
    168 
    169    /*
    170     * Make sure the input file is not the output file.
    171     * Add a few bytes to the end of the JAR file and see if the input file
    172     * twitches
    173     */
    174    {
    175        PRInt32 endOfJar;
    176        PRInt32 inputSize;
    177        PRBool isSame;
    178 
    179        inputSize = PR_Available(readfp);
    180 
    181        endOfJar = PR_Seek(zipfp, 0L, PR_SEEK_CUR);
    182 
    183        if (PR_Write(zipfp, "abcde", 5) < 5) {
    184            char *nsprErr;
    185 
    186            if (PR_GetErrorTextLength()) {
    187                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    188                PR_GetErrorText(nsprErr);
    189            } else {
    190                nsprErr = NULL;
    191            }
    192            PR_fprintf(errorFD, "Writing to zip file: %s\n",
    193                       nsprErr ? nsprErr : "");
    194            if (nsprErr)
    195                PR_Free(nsprErr);
    196            errorCount++;
    197            exit(ERRX);
    198        }
    199 
    200        isSame = (PR_Available(readfp) != inputSize);
    201 
    202        PR_Seek(zipfp, endOfJar, PR_SEEK_SET);
    203 
    204        if (isSame) {
    205            /* It's the same file! Forget it! */
    206            PR_Close(readfp);
    207            return 0;
    208        }
    209    }
    210 
    211    if (verbosity >= 0) {
    212        PR_fprintf(outputFD, "adding %s to %s...", fullname, zipfile->filename);
    213    }
    214 
    215    entry = PORT_ZAlloc(sizeof(ZIPentry));
    216    if (!entry)
    217        out_of_memory();
    218 
    219    entry->filename = PORT_Strdup(filename);
    220    entry->comment = NULL;
    221 
    222    /* Set up local file header */
    223    longtox(LSIG, entry->local.signature);
    224    inttox(strlen(filename), entry->local.filename_len);
    225    inttox(zipfile->time, entry->local.time);
    226    inttox(zipfile->date, entry->local.date);
    227    inttox(Z_DEFLATED, entry->local.method);
    228 
    229    /* Set up central directory entry */
    230    longtox(CSIG, entry->central.signature);
    231    inttox(strlen(filename), entry->central.filename_len);
    232    if (entry->comment) {
    233        inttox(strlen(entry->comment), entry->central.commentfield_len);
    234    }
    235    longtox(PR_Seek(zipfile->fp, 0, PR_SEEK_CUR),
    236            entry->central.localhdr_offset);
    237    inttox(zipfile->time, entry->central.time);
    238    inttox(zipfile->date, entry->central.date);
    239    inttox(Z_DEFLATED, entry->central.method);
    240 
    241    /* Compute crc.  Too bad we have to process the whole file to do this*/
    242    crc = crc32(0L, NULL, 0);
    243    while ((num = PR_Read(readfp, inbuf, BUFSIZ)) > 0) {
    244        crc = crc32(crc, inbuf, num);
    245    }
    246    PR_Seek(readfp, 0L, PR_SEEK_SET);
    247 
    248    /* Store CRC */
    249    longtox(crc, entry->local.crc32);
    250    longtox(crc, entry->central.crc32);
    251 
    252    /* Stick this entry onto the end of the list */
    253    entry->next = NULL;
    254    if (zipfile->list == NULL) {
    255        /* First entry */
    256        zipfile->list = entry;
    257    } else {
    258        ZIPentry *pe;
    259 
    260        pe = zipfile->list;
    261        while (pe->next != NULL) {
    262            pe = pe->next;
    263        }
    264        pe->next = entry;
    265    }
    266 
    267    /*
    268     * Start writing stuff out
    269     */
    270 
    271    local_size_pos = PR_Seek(zipfp, 0, PR_SEEK_CUR) + 18;
    272    /* File header */
    273    if (PR_Write(zipfp, &entry->local, sizeof(struct ZipLocal)) <
    274        sizeof(struct ZipLocal)) {
    275        char *nsprErr;
    276        if (PR_GetErrorTextLength()) {
    277            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    278            PR_GetErrorText(nsprErr);
    279        } else {
    280            nsprErr = NULL;
    281        }
    282        PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
    283        if (nsprErr)
    284            PR_Free(nsprErr);
    285        errorCount++;
    286        exit(ERRX);
    287    }
    288 
    289    /* File Name */
    290    if (PR_Write(zipfp, filename, strlen(filename)) < strlen(filename)) {
    291        char *nsprErr;
    292        if (PR_GetErrorTextLength()) {
    293            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    294            PR_GetErrorText(nsprErr);
    295        } else {
    296            nsprErr = NULL;
    297        }
    298        PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
    299        if (nsprErr)
    300            PR_Free(nsprErr);
    301        errorCount++;
    302        exit(ERRX);
    303    }
    304 
    305    /*
    306     * File data
    307     */
    308    /* Initialize zstream */
    309    zstream.zalloc = my_alloc_func;
    310    zstream.zfree = my_free_func;
    311    zstream.opaque = NULL;
    312    zstream.next_in = inbuf;
    313    zstream.avail_in = BUFSIZ;
    314    zstream.next_out = outbuf;
    315    zstream.avail_out = BUFSIZ;
    316    /* Setting the windowBits to -MAX_WBITS is an undocumented feature of
    317     * zlib (see deflate.c in zlib).  It is the same thing that Java does
    318     * when you specify the nowrap option for deflation in java.util.zip.
    319     * It causes zlib to leave out its headers and footers, which don't
    320     * work in PKZIP files.
    321     */
    322    err = deflateInit2(&zstream, lvl, Z_DEFLATED,
    323                       -MAX_WBITS, 8 /*default*/, Z_DEFAULT_STRATEGY);
    324    if (err != Z_OK) {
    325        handle_zerror(err, zstream.msg);
    326        exit(ERRX);
    327    }
    328 
    329    while ((zstream.avail_in = PR_Read(readfp, inbuf, BUFSIZ)) > 0) {
    330        zstream.next_in = inbuf;
    331        /* Process this chunk of data */
    332        while (zstream.avail_in > 0) {
    333            err = deflate(&zstream, Z_NO_FLUSH);
    334            if (err != Z_OK) {
    335                handle_zerror(err, zstream.msg);
    336                exit(ERRX);
    337            }
    338            if (zstream.avail_out <= 0) {
    339                if (PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) {
    340                    char *nsprErr;
    341                    if (PR_GetErrorTextLength()) {
    342                        nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    343                        PR_GetErrorText(nsprErr);
    344                    } else {
    345                        nsprErr = NULL;
    346                    }
    347                    PR_fprintf(errorFD, "Writing zip data: %s\n",
    348                               nsprErr ? nsprErr : "");
    349                    if (nsprErr)
    350                        PR_Free(nsprErr);
    351                    errorCount++;
    352                    exit(ERRX);
    353                }
    354                zstream.next_out = outbuf;
    355                zstream.avail_out = BUFSIZ;
    356            }
    357        }
    358    }
    359 
    360    /* Now flush everything */
    361    while (1) {
    362        err = deflate(&zstream, Z_FINISH);
    363        if (err == Z_STREAM_END) {
    364            break;
    365        } else if (err == Z_OK) {
    366            /* output buffer full, repeat */
    367        } else {
    368            handle_zerror(err, zstream.msg);
    369            exit(ERRX);
    370        }
    371        if (PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) {
    372            char *nsprErr;
    373            if (PR_GetErrorTextLength()) {
    374                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    375                PR_GetErrorText(nsprErr);
    376            } else {
    377                nsprErr = NULL;
    378            }
    379            PR_fprintf(errorFD, "Writing zip data: %s\n",
    380                       nsprErr ? nsprErr : "");
    381            if (nsprErr)
    382                PR_Free(nsprErr);
    383            errorCount++;
    384            exit(ERRX);
    385        }
    386        zstream.avail_out = BUFSIZ;
    387        zstream.next_out = outbuf;
    388    }
    389 
    390    /* If there's any output left, write it out. */
    391    if (zstream.next_out != outbuf) {
    392        if (PR_Write(zipfp, outbuf, zstream.next_out - outbuf) <
    393            zstream.next_out - outbuf) {
    394            char *nsprErr;
    395            if (PR_GetErrorTextLength()) {
    396                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    397                PR_GetErrorText(nsprErr);
    398            } else {
    399                nsprErr = NULL;
    400            }
    401            PR_fprintf(errorFD, "Writing zip data: %s\n",
    402                       nsprErr ? nsprErr : "");
    403            if (nsprErr)
    404                PR_Free(nsprErr);
    405            errorCount++;
    406            exit(ERRX);
    407        }
    408        zstream.avail_out = BUFSIZ;
    409        zstream.next_out = outbuf;
    410    }
    411 
    412    /* Now that we know the compressed size, write this to the headers */
    413    longtox(zstream.total_in, entry->local.orglen);
    414    longtox(zstream.total_out, entry->local.size);
    415    if (PR_Seek(zipfp, local_size_pos, PR_SEEK_SET) == -1) {
    416        char *nsprErr;
    417        if (PR_GetErrorTextLength()) {
    418            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    419            PR_GetErrorText(nsprErr);
    420        } else {
    421            nsprErr = NULL;
    422        }
    423        PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : "");
    424        if (nsprErr)
    425            PR_Free(nsprErr);
    426        errorCount++;
    427        exit(ERRX);
    428    }
    429    if (PR_Write(zipfp, entry->local.size, 8) != 8) {
    430        char *nsprErr;
    431        if (PR_GetErrorTextLength()) {
    432            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    433            PR_GetErrorText(nsprErr);
    434        } else {
    435            nsprErr = NULL;
    436        }
    437        PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : "");
    438        if (nsprErr)
    439            PR_Free(nsprErr);
    440        errorCount++;
    441        exit(ERRX);
    442    }
    443    if (PR_Seek(zipfp, 0L, PR_SEEK_END) == -1) {
    444        char *nsprErr;
    445        if (PR_GetErrorTextLength()) {
    446            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    447            PR_GetErrorText(nsprErr);
    448        } else {
    449            nsprErr = NULL;
    450        }
    451        PR_fprintf(errorFD, "Accessing zip file: %s\n",
    452                   nsprErr ? nsprErr : "");
    453        if (nsprErr)
    454            PR_Free(nsprErr);
    455        errorCount++;
    456        exit(ERRX);
    457    }
    458    longtox(zstream.total_in, entry->central.orglen);
    459    longtox(zstream.total_out, entry->central.size);
    460 
    461    /* Close out the deflation operation */
    462    err = deflateEnd(&zstream);
    463    if (err != Z_OK) {
    464        handle_zerror(err, zstream.msg);
    465        exit(ERRX);
    466    }
    467 
    468    PR_Close(readfp);
    469 
    470    if ((zstream.total_in > zstream.total_out) && (zstream.total_in > 0)) {
    471        deflate_percent = (int)((zstream.total_in -
    472                                 zstream.total_out) *
    473                                100 / zstream.total_in);
    474    } else {
    475        deflate_percent = 0;
    476    }
    477    if (verbosity >= 0) {
    478        PR_fprintf(outputFD, "(deflated %d%%)\n", deflate_percent);
    479    }
    480 
    481    return 0;
    482 }
    483 
    484 /********************************************************************
    485 * J z i p C l o s e
    486 *
    487 * Finishes the ZipFile. ALSO DELETES THE ZIPFILE STRUCTURE PASSED IN!!
    488 */
    489 int
    490 JzipClose(ZIPfile *zipfile)
    491 {
    492    ZIPentry *pe, *dead;
    493    PRFileDesc *zipfp;
    494    struct ZipEnd zipend;
    495    unsigned int entrycount = 0;
    496 
    497    if (!zipfile) {
    498        return -1;
    499    }
    500 
    501    if (!zipfile->filename) {
    502        /* bogus */
    503        return 0;
    504    }
    505 
    506    zipfp = zipfile->fp;
    507    zipfile->central_start = PR_Seek(zipfp, 0L, PR_SEEK_CUR);
    508 
    509    /* Write out all the central directories */
    510    pe = zipfile->list;
    511    while (pe) {
    512        entrycount++;
    513 
    514        /* Write central directory info */
    515        if (PR_Write(zipfp, &pe->central, sizeof(struct ZipCentral)) <
    516            sizeof(struct ZipCentral)) {
    517            char *nsprErr;
    518            if (PR_GetErrorTextLength()) {
    519                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    520                PR_GetErrorText(nsprErr);
    521            } else {
    522                nsprErr = NULL;
    523            }
    524            PR_fprintf(errorFD, "Writing zip data: %s\n",
    525                       nsprErr ? nsprErr : "");
    526            if (nsprErr)
    527                PR_Free(nsprErr);
    528            errorCount++;
    529            exit(ERRX);
    530        }
    531 
    532        /* Write filename */
    533        if (PR_Write(zipfp, pe->filename, strlen(pe->filename)) <
    534            strlen(pe->filename)) {
    535            char *nsprErr;
    536            if (PR_GetErrorTextLength()) {
    537                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    538                PR_GetErrorText(nsprErr);
    539            } else {
    540                nsprErr = NULL;
    541            }
    542            PR_fprintf(errorFD, "Writing zip data: %s\n",
    543                       nsprErr ? nsprErr : "");
    544            if (nsprErr)
    545                PR_Free(nsprErr);
    546            errorCount++;
    547            exit(ERRX);
    548        }
    549 
    550        /* Write file comment */
    551        if (pe->comment) {
    552            if (PR_Write(zipfp, pe->comment, strlen(pe->comment)) <
    553                strlen(pe->comment)) {
    554                char *nsprErr;
    555                if (PR_GetErrorTextLength()) {
    556                    nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    557                    PR_GetErrorText(nsprErr);
    558                } else {
    559                    nsprErr = NULL;
    560                }
    561                PR_fprintf(errorFD, "Writing zip data: %s\n",
    562                           nsprErr ? nsprErr : "");
    563                if (nsprErr)
    564                    PR_Free(nsprErr);
    565                errorCount++;
    566                exit(ERRX);
    567            }
    568        }
    569 
    570        /* Delete the structure */
    571        dead = pe;
    572        pe = pe->next;
    573        if (dead->filename) {
    574            PORT_Free(dead->filename);
    575        }
    576        if (dead->comment) {
    577            PORT_Free(dead->comment);
    578        }
    579        PORT_Free(dead);
    580    }
    581    zipfile->central_end = PR_Seek(zipfile->fp, 0L, PR_SEEK_CUR);
    582 
    583    /* Create the ZipEnd structure */
    584    PORT_Memset(&zipend, 0, sizeof(zipend));
    585    longtox(ESIG, zipend.signature);
    586    inttox(entrycount, zipend.total_entries_disk);
    587    inttox(entrycount, zipend.total_entries_archive);
    588    longtox(zipfile->central_end - zipfile->central_start,
    589            zipend.central_dir_size);
    590    longtox(zipfile->central_start, zipend.offset_central_dir);
    591    if (zipfile->comment) {
    592        inttox(strlen(zipfile->comment), zipend.commentfield_len);
    593    }
    594 
    595    /* Write out ZipEnd xtructure */
    596    if (PR_Write(zipfp, &zipend, sizeof(zipend)) < sizeof(zipend)) {
    597        char *nsprErr;
    598        if (PR_GetErrorTextLength()) {
    599            nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    600            PR_GetErrorText(nsprErr);
    601        } else {
    602            nsprErr = NULL;
    603        }
    604        PR_fprintf(errorFD, "Writing zip data: %s\n",
    605                   nsprErr ? nsprErr : "");
    606        if (nsprErr)
    607            PR_Free(nsprErr);
    608        errorCount++;
    609        exit(ERRX);
    610    }
    611 
    612    /* Write out Zipfile comment */
    613    if (zipfile->comment) {
    614        if (PR_Write(zipfp, zipfile->comment, strlen(zipfile->comment)) <
    615            strlen(zipfile->comment)) {
    616            char *nsprErr;
    617            if (PR_GetErrorTextLength()) {
    618                nsprErr = PR_Malloc(PR_GetErrorTextLength() + 1);
    619                PR_GetErrorText(nsprErr);
    620            } else {
    621                nsprErr = NULL;
    622            }
    623            PR_fprintf(errorFD, "Writing zip data: %s\n",
    624                       nsprErr ? nsprErr : "");
    625            if (nsprErr)
    626                PR_Free(nsprErr);
    627            errorCount++;
    628            exit(ERRX);
    629        }
    630    }
    631 
    632    PR_Close(zipfp);
    633 
    634    /* Free the memory of the zipfile structure */
    635    if (zipfile->filename) {
    636        PORT_Free(zipfile->filename);
    637    }
    638    if (zipfile->comment) {
    639        PORT_Free(zipfile->comment);
    640    }
    641    PORT_Free(zipfile);
    642 
    643    return 0;
    644 }
    645 
    646 /**********************************************
    647 *  i n t t o x
    648 *
    649 *  Converts a two byte ugly endianed integer
    650 *  to our platform's integer.
    651 *
    652 */
    653 
    654 static void
    655 inttox(int in, char *out)
    656 {
    657    out[0] = (in & 0xFF);
    658    out[1] = (in & 0xFF00) >> 8;
    659 }
    660 
    661 /*********************************************
    662 *  l o n g t o x
    663 *
    664 *  Converts a four byte ugly endianed integer
    665 *  to our platform's integer.
    666 *
    667 */
    668 
    669 static void
    670 longtox(long in, char *out)
    671 {
    672    out[0] = (in & 0xFF);
    673    out[1] = (in & 0xFF00) >> 8;
    674    out[2] = (in & 0xFF0000) >> 16;
    675    out[3] = (in & 0xFF000000) >> 24;
    676 }