Initial revision
[blender.git] / source / blender / deflate / intern / BLO_deflate.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * zlib deflate compression wrapper library
32  */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #include "zlib.h"
38
39 #include "GEN_messaging.h"
40
41 #include "BLO_writeStreamGlue.h"
42 #include "BLO_deflate.h"
43 #include "BLO_in_de_flateHeader.h"
44
45 // TODO use other error function
46 static int CHECK_ERR(int err, char *msg);
47
48 static int CHECK_ERR(int err, char *msg) { 
49         if (err != Z_OK) {
50 #ifndef NDEBUG
51                 fprintf(GEN_errorstream,
52                                 "%s error: %d\n",
53                                 msg,
54                                 err); 
55 #endif
56                 return 1;
57         }
58         return 0;
59 }
60
61         int
62 BLO_deflate(
63         unsigned char *data,
64         unsigned int dataIn,
65         struct streamGlueHeaderStruct *streamGlueHeader)
66 {
67         int zlib_err;           /* zlib error */
68         int err = 0;        /* our own error */
69         z_stream c_stream;      /* compression stream */
70         char dictionary[50];
71         Bytef *compressBuf;     /* minimally sized output buffer for deflate */
72         uInt compressSize;      /* minimally sized compressBuf size in bytes */
73         struct writeStreamGlueStruct *streamGlue = NULL;
74         struct BLO_in_de_flateHeaderStruct BLO_in_de_flateHeader;
75         char* errmsg1 = "deflateInit";
76         char* errmsg2 = "deflateSetDictionary";
77         char* errmsg3 = "deflateEnd";
78
79         // TODO use dictionary index, this is id = 1 :
80         strcpy(dictionary, "sure this is not a number");
81
82         compressSize = (dataIn * 1.1) + 12;
83         compressBuf = (Bytef *)malloc(compressSize);
84         if (!compressBuf) {
85                 err = BWS_SETFUNCTION(BWS_DEFLATE) |
86                           BWS_SETGENERR(BWS_MALLOC);
87                 return err;
88         }
89
90         c_stream.next_out = compressBuf;
91         c_stream.avail_out = compressSize;
92         c_stream.next_in = data;
93         c_stream.avail_in = dataIn;
94
95         c_stream.zalloc = (alloc_func)0;
96         c_stream.zfree = (free_func)0;
97         c_stream.opaque = (voidpf)0;
98
99         zlib_err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
100         if (CHECK_ERR(zlib_err, errmsg1)) {
101                 err = BWS_SETFUNCTION(BWS_DEFLATE) |
102                           BWS_SETSPECERR(BWS_DEFLATEERROR);
103                 free(compressBuf);
104                 return err;
105         }
106
107         zlib_err = deflateSetDictionary(&c_stream,
108                                                                         (const Bytef*)dictionary,
109                                                                         strlen(dictionary));
110         if (CHECK_ERR(zlib_err, errmsg2)) {
111                 err = BWS_SETFUNCTION(BWS_DEFLATE) |
112                           BWS_SETSPECERR(BWS_DEFLATEERROR);
113                 free(compressBuf);
114                 return err;
115         }
116         
117         // Compress it
118         zlib_err = deflate(&c_stream, Z_FINISH);
119         if (zlib_err != Z_STREAM_END) {
120 #ifndef NDEBUG          
121                 fprintf(GEN_errorstream,
122                                 "deflate should report Z_STREAM_END\n");
123 #endif
124                 // (avail_out == 0) possibility ? Should not, because we
125                 // malloc by the minimal needed amount rule
126                 err = BWS_SETFUNCTION(BWS_DEFLATE) |
127                           BWS_SETSPECERR(BWS_DEFLATEERROR);
128                 free(compressBuf);
129                 return err;
130         }
131
132         zlib_err = deflateEnd(&c_stream);
133         if (CHECK_ERR(zlib_err, errmsg3)) {
134                 err = BWS_SETFUNCTION(BWS_DEFLATE) |
135                           BWS_SETSPECERR(BWS_DEFLATEERROR);
136                 free(compressBuf);
137                 return err;
138         }
139
140 #ifndef NDEBUG
141         fprintf(GEN_errorstream,
142                         "BLO_deflate compressed %ld bytes to %ld (%.0f%%)\n",                   
143                         c_stream.total_in, c_stream.total_out,
144                         100. * (float)c_stream.total_out / (float)c_stream.total_in);
145         
146         fprintf(GEN_errorstream,
147                         "BLO_deflate writes streamGlueHeader of %u bytes\n",
148                         STREAMGLUEHEADERSIZE);
149 #endif
150         // Update streamGlueHeader that initiated us and write it away
151         streamGlueHeader->totalStreamLength =
152                 htonl(IN_DE_FLATEHEADERSTRUCTSIZE + c_stream.total_out);
153         streamGlueHeader->crc = htonl(crc32(0L, (const Bytef *) streamGlueHeader,
154                                         STREAMGLUEHEADERSIZE - 4));
155         err = writeStreamGlue(
156                 Global_streamGlueControl,
157                 &streamGlue,
158                 (unsigned char *) streamGlueHeader,
159                 STREAMGLUEHEADERSIZE,
160                 0);
161         if (err) {
162                 free(compressBuf);
163                 return err;
164         }
165
166 #ifndef NDEBUG
167         fprintf(GEN_errorstream,
168                         "BLO_deflate writes BLO_in_de_flateHeader of %u bytes\n",
169                         IN_DE_FLATEHEADERSTRUCTSIZE);
170 #endif
171
172         // write out our header
173         BLO_in_de_flateHeader.magic = 'B';
174         BLO_in_de_flateHeader.compressedLength = htonl(c_stream.total_out);
175         BLO_in_de_flateHeader.uncompressedLength = htonl(c_stream.total_in);
176         BLO_in_de_flateHeader.dictionary_id = htonl(1);
177         BLO_in_de_flateHeader.dictId = htonl(c_stream.adler); // adler checksum
178         BLO_in_de_flateHeader.crc = htonl(crc32(0L,
179                 (const Bytef *) &BLO_in_de_flateHeader, IN_DE_FLATEHEADERSTRUCTSIZE-4));
180         err = writeStreamGlue(
181                 Global_streamGlueControl,
182                 &streamGlue,
183                 (unsigned char *) &BLO_in_de_flateHeader,
184                 IN_DE_FLATEHEADERSTRUCTSIZE,
185                 0);
186         if (err) {
187                 free(compressBuf);
188                 return err;
189         }
190
191 #ifndef NDEBUG
192         fprintf(GEN_errorstream,
193                         "BLO_deflate writes %lu bytes raw data (total %lu)\n",
194                         c_stream.total_out, STREAMGLUEHEADERSIZE +
195                         IN_DE_FLATEHEADERSTRUCTSIZE + c_stream.total_out);
196 #endif
197
198         // finally write all compressed data
199         err = writeStreamGlue(
200                 Global_streamGlueControl,
201                 &streamGlue,
202                 (unsigned char *) compressBuf,
203                 c_stream.total_out,
204                 1);
205
206         free(compressBuf);
207
208         return err;
209 }
210