a83f4af08af27566d889f884fc8465fbe9681e63
[platform/kernel/u-boot.git] / lib / gzip.c
1 /*
2  * (C) Copyright 2012
3  * Lei Wen <leiwen@marvell.com>, Marvell Inc.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 #include <common.h>
25 #include <watchdog.h>
26 #include <command.h>
27 #include <image.h>
28 #include <malloc.h>
29 #include <u-boot/zlib.h>
30 #include "zlib/zutil.h"
31
32 #ifndef CONFIG_GZIP_COMPRESS_DEF_SZ
33 #define CONFIG_GZIP_COMPRESS_DEF_SZ     0x200
34 #endif
35 #define ZALLOC_ALIGNMENT                16
36
37 static void *zalloc(void *x, unsigned items, unsigned size)
38 {
39         void *p;
40
41         size *= items;
42         size = (size + ZALLOC_ALIGNMENT - 1) & ~(ZALLOC_ALIGNMENT - 1);
43
44         p = malloc (size);
45
46         return (p);
47 }
48
49 static void zfree(void *x, void *addr, unsigned nb)
50 {
51         free (addr);
52 }
53
54 int gzip(void *dst, unsigned long *lenp,
55                 unsigned char *src, unsigned long srclen)
56 {
57         return zzip(dst, lenp, src, srclen, 1, NULL);
58 }
59
60 /*
61  * Compress blocks with zlib
62  */
63 int zzip(void *dst, unsigned long *lenp, unsigned char *src,
64                 unsigned long srclen, int stoponerr,
65                 int (*func)(unsigned long, unsigned long))
66 {
67         z_stream s;
68         int r, flush, orig, window;
69         unsigned long comp_len, left_len;
70
71         if (!srclen)
72                 return 0;
73
74 #ifndef CONFIG_GZIP
75         window = MAX_WBITS;
76 #else
77         window = 2 * MAX_WBITS;
78 #endif
79         orig = *lenp;
80         s.zalloc = zalloc;
81         s.zfree = zfree;
82         s.opaque = Z_NULL;
83
84         r = deflateInit2_(&s, Z_BEST_SPEED, Z_DEFLATED, window,
85                         DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
86                         ZLIB_VERSION, sizeof(z_stream));
87         if (r != Z_OK) {
88                 printf ("Error: deflateInit2_() returned %d\n", r);
89                 return -1;
90         }
91
92         while (srclen > 0) {
93                 comp_len = (srclen > CONFIG_GZIP_COMPRESS_DEF_SZ) ?
94                                 CONFIG_GZIP_COMPRESS_DEF_SZ : srclen;
95
96                 s.next_in = src;
97                 s.avail_in = comp_len;
98                 flush = (srclen > CONFIG_GZIP_COMPRESS_DEF_SZ)?
99                         Z_NO_FLUSH : Z_FINISH;
100
101                 do {
102                         left_len = (*lenp > CONFIG_GZIP_COMPRESS_DEF_SZ) ?
103                                         CONFIG_GZIP_COMPRESS_DEF_SZ : *lenp;
104                         s.next_out = dst;
105                         s.avail_out = left_len;
106                         r = deflate(&s, flush);
107                         if (r == Z_STREAM_ERROR && stoponerr == 1) {
108                                 printf("Error: deflate() returned %d\n", r);
109                                 r = -1;
110                                 goto bail;
111                         }
112                         if (!func) {
113                                 dst += (left_len - s.avail_out);
114                                 *lenp -= (left_len - s.avail_out);
115                         } else if (left_len - s.avail_out > 0) {
116                                 r = func((unsigned long)dst,
117                                         left_len - s.avail_out);
118                                 if (r < 0)
119                                         goto bail;
120                         }
121                 } while (s.avail_out == 0 && (*lenp > 0));
122                 if (s.avail_in) {
123                         printf("Deflate failed to consume %u bytes", s.avail_in);
124                         r = -1;
125                         goto bail;
126                 }
127                 if (*lenp == 0) {
128                         printf("Deflate need more space to compress "
129                                 "left %lu bytes\n", srclen);
130                         r = -1;
131                         goto bail;
132                 }
133                 srclen -= comp_len;
134                 src += comp_len;
135         }
136
137         r = 0;
138 bail:
139         deflateEnd(&s);
140         *lenp = orig - *lenp;
141         return r;
142 }