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