uboot/lib/gunzip.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2000-2006
   3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <watchdog.h>
  10#include <command.h>
  11#include <image.h>
  12#include <malloc.h>
  13#include <u-boot/zlib.h>
  14#include <div64.h>
  15
  16#define HEADER0                 '\x1f'
  17#define HEADER1                 '\x8b'
  18#define ZALLOC_ALIGNMENT        16
  19#define HEAD_CRC                2
  20#define EXTRA_FIELD             4
  21#define ORIG_NAME               8
  22#define COMMENT                 0x10
  23#define RESERVED                0xe0
  24#define DEFLATED                8
  25
  26void *gzalloc(void *x, unsigned items, unsigned size)
  27{
  28        void *p;
  29
  30        size *= items;
  31        size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
  32
  33        p = malloc (size);
  34
  35        return (p);
  36}
  37
  38void gzfree(void *x, void *addr, unsigned nb)
  39{
  40        free (addr);
  41}
  42
  43int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
  44{
  45        int i, flags;
  46
  47        /* skip header */
  48        i = 10;
  49        flags = src[3];
  50        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
  51                puts ("Error: Bad gzipped data\n");
  52                return (-1);
  53        }
  54        if ((flags & EXTRA_FIELD) != 0)
  55                i = 12 + src[10] + (src[11] << 8);
  56        if ((flags & ORIG_NAME) != 0)
  57                while (src[i++] != 0)
  58                        ;
  59        if ((flags & COMMENT) != 0)
  60                while (src[i++] != 0)
  61                        ;
  62        if ((flags & HEAD_CRC) != 0)
  63                i += 2;
  64        if (i >= *lenp) {
  65                puts ("Error: gunzip out of data in header\n");
  66                return (-1);
  67        }
  68
  69        return zunzip(dst, dstlen, src, lenp, 1, i);
  70}
  71
  72__weak
  73void gzwrite_progress_init(u64 expectedsize)
  74{
  75        putc('\n');
  76}
  77
  78__weak
  79void gzwrite_progress(int iteration,
  80                     u64 bytes_written,
  81                     u64 total_bytes)
  82{
  83        if (0 == (iteration & 3))
  84                printf("%llu/%llu\r", bytes_written, total_bytes);
  85}
  86
  87__weak
  88void gzwrite_progress_finish(int returnval,
  89                             u64 bytes_written,
  90                             u64 total_bytes,
  91                             u32 expected_crc,
  92                             u32 calculated_crc)
  93{
  94        if (0 == returnval) {
  95                printf("\n\t%llu bytes, crc 0x%08x\n",
  96                       total_bytes, calculated_crc);
  97        } else {
  98                printf("\n\tuncompressed %llu of %llu\n"
  99                       "\tcrcs == 0x%08x/0x%08x\n",
 100                       bytes_written, total_bytes,
 101                       expected_crc, calculated_crc);
 102        }
 103}
 104
 105int gzwrite(unsigned char *src, int len,
 106            struct block_dev_desc *dev,
 107            unsigned long szwritebuf,
 108            u64 startoffs,
 109            u64 szexpected)
 110{
 111        int i, flags;
 112        z_stream s;
 113        int r = 0;
 114        unsigned char *writebuf;
 115        unsigned crc = 0;
 116        u64 totalfilled = 0;
 117        lbaint_t blksperbuf, outblock;
 118        u32 expected_crc;
 119        u32 payload_size;
 120        int iteration = 0;
 121
 122        if (!szwritebuf ||
 123            (szwritebuf % dev->blksz) ||
 124            (szwritebuf < dev->blksz)) {
 125                printf("%s: size %lu not a multiple of %lu\n",
 126                       __func__, szwritebuf, dev->blksz);
 127                return -1;
 128        }
 129
 130        if (startoffs & (dev->blksz-1)) {
 131                printf("%s: start offset %llu not a multiple of %lu\n",
 132                       __func__, startoffs, dev->blksz);
 133                return -1;
 134        }
 135
 136        blksperbuf = szwritebuf / dev->blksz;
 137        outblock = lldiv(startoffs, dev->blksz);
 138
 139        /* skip header */
 140        i = 10;
 141        flags = src[3];
 142        if (src[2] != DEFLATED || (flags & RESERVED) != 0) {
 143                puts("Error: Bad gzipped data\n");
 144                return -1;
 145        }
 146        if ((flags & EXTRA_FIELD) != 0)
 147                i = 12 + src[10] + (src[11] << 8);
 148        if ((flags & ORIG_NAME) != 0)
 149                while (src[i++] != 0)
 150                        ;
 151        if ((flags & COMMENT) != 0)
 152                while (src[i++] != 0)
 153                        ;
 154        if ((flags & HEAD_CRC) != 0)
 155                i += 2;
 156
 157        if (i >= len-8) {
 158                puts("Error: gunzip out of data in header");
 159                return -1;
 160        }
 161
 162        payload_size = len - i - 8;
 163
 164        memcpy(&expected_crc, src + len - 8, sizeof(expected_crc));
 165        expected_crc = le32_to_cpu(expected_crc);
 166        u32 szuncompressed;
 167        memcpy(&szuncompressed, src + len - 4, sizeof(szuncompressed));
 168        if (szexpected == 0) {
 169                szexpected = le32_to_cpu(szuncompressed);
 170        } else if (szuncompressed != (u32)szexpected) {
 171                printf("size of %llx doesn't match trailer low bits %x\n",
 172                       szexpected, szuncompressed);
 173                return -1;
 174        }
 175        if (lldiv(szexpected, dev->blksz) > (dev->lba - outblock)) {
 176                printf("%s: uncompressed size %llu exceeds device size\n",
 177                       __func__, szexpected);
 178                return -1;
 179        }
 180
 181        gzwrite_progress_init(szexpected);
 182
 183        s.zalloc = gzalloc;
 184        s.zfree = gzfree;
 185
 186        r = inflateInit2(&s, -MAX_WBITS);
 187        if (r != Z_OK) {
 188                printf("Error: inflateInit2() returned %d\n", r);
 189                return -1;
 190        }
 191
 192        s.next_in = src + i;
 193        s.avail_in = payload_size+8;
 194        writebuf = (unsigned char *)malloc(szwritebuf);
 195
 196        /* decompress until deflate stream ends or end of file */
 197        do {
 198                if (s.avail_in == 0) {
 199                        printf("%s: weird termination with result %d\n",
 200                               __func__, r);
 201                        break;
 202                }
 203
 204                /* run inflate() on input until output buffer not full */
 205                do {
 206                        unsigned long blocks_written;
 207                        int numfilled;
 208                        lbaint_t writeblocks;
 209
 210                        s.avail_out = szwritebuf;
 211                        s.next_out = writebuf;
 212                        r = inflate(&s, Z_SYNC_FLUSH);
 213                        if ((r != Z_OK) &&
 214                            (r != Z_STREAM_END)) {
 215                                printf("Error: inflate() returned %d\n", r);
 216                                goto out;
 217                        }
 218                        numfilled = szwritebuf - s.avail_out;
 219                        crc = crc32(crc, writebuf, numfilled);
 220                        totalfilled += numfilled;
 221                        if (numfilled < szwritebuf) {
 222                                writeblocks = (numfilled+dev->blksz-1)
 223                                                / dev->blksz;
 224                                memset(writebuf+numfilled, 0,
 225                                       dev->blksz-(numfilled%dev->blksz));
 226                        } else {
 227                                writeblocks = blksperbuf;
 228                        }
 229
 230                        gzwrite_progress(iteration++,
 231                                         totalfilled,
 232                                         szexpected);
 233                        blocks_written = dev->block_write(dev->dev,
 234                                                          outblock,
 235                                                          writeblocks,
 236                                                          writebuf);
 237                        outblock += blocks_written;
 238                        if (ctrlc()) {
 239                                puts("abort\n");
 240                                goto out;
 241                        }
 242                        WATCHDOG_RESET();
 243                } while (s.avail_out == 0);
 244                /* done when inflate() says it's done */
 245        } while (r != Z_STREAM_END);
 246
 247        if ((szexpected != totalfilled) ||
 248            (crc != expected_crc))
 249                r = -1;
 250        else
 251                r = 0;
 252
 253out:
 254        gzwrite_progress_finish(r, totalfilled, szexpected,
 255                                expected_crc, crc);
 256        free(writebuf);
 257        inflateEnd(&s);
 258
 259        return r;
 260}
 261
 262/*
 263 * Uncompress blocks compressed with zlib without headers
 264 */
 265int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp,
 266                                                int stoponerr, int offset)
 267{
 268        z_stream s;
 269        int err = 0;
 270        int r;
 271
 272        s.zalloc = gzalloc;
 273        s.zfree = gzfree;
 274
 275        r = inflateInit2(&s, -MAX_WBITS);
 276        if (r != Z_OK) {
 277                printf("Error: inflateInit2() returned %d\n", r);
 278                return -1;
 279        }
 280        s.next_in = src + offset;
 281        s.avail_in = *lenp - offset;
 282        s.next_out = dst;
 283        s.avail_out = dstlen;
 284        do {
 285                r = inflate(&s, Z_FINISH);
 286                if (stoponerr == 1 && r != Z_STREAM_END &&
 287                    (s.avail_out == 0 || r != Z_BUF_ERROR)) {
 288                        printf("Error: inflate() returned %d\n", r);
 289                        err = -1;
 290                        break;
 291                }
 292                s.avail_in = *lenp - offset - (int)(s.next_out - (unsigned char*)dst);
 293        } while (r == Z_BUF_ERROR);
 294        *lenp = s.next_out - (unsigned char *) dst;
 295        inflateEnd(&s);
 296
 297        return err;
 298}
 299