tizen 2.4 release
[external/xdelta3.git] / xdelta3-lzma.h
1 /* xdelta 3 - delta compression tools and library
2  * Copyright (C) 2012, 2013.  Joshua P. MacDonald
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19 /* Note: The use of the _easy_ decoder means we're not calling the
20  * xd3_stream malloc hooks.  TODO(jmacd) Fix if anyone cares. */
21
22 #ifndef _XDELTA3_LZMA_H_
23 #define _XDELTA3_LZMA_H_
24
25 #include <lzma.h>
26
27 typedef struct _xd3_lzma_stream xd3_lzma_stream;
28
29 struct _xd3_lzma_stream {
30   lzma_stream lzma;
31   lzma_options_lzma options;
32   lzma_filter filters[2];
33 };
34
35 xd3_sec_stream* 
36 xd3_lzma_alloc (xd3_stream *stream)
37 {
38   return (xd3_sec_stream*) xd3_alloc (stream, sizeof (xd3_lzma_stream), 1);
39 }
40
41 void
42 xd3_lzma_destroy (xd3_stream *stream, xd3_sec_stream *sec_stream)
43 {
44   xd3_lzma_stream *ls = (xd3_lzma_stream*) sec_stream;
45   lzma_end (&ls->lzma);
46   xd3_free (stream, ls);
47 }
48
49 int
50 xd3_lzma_init (xd3_stream *stream, xd3_lzma_stream *sec, int is_encode)
51 {
52   int ret;
53
54   memset (&sec->lzma, 0, sizeof(sec->lzma));
55
56   if (is_encode)
57     {
58       int preset = (stream->flags & XD3_COMPLEVEL_MASK) >> XD3_COMPLEVEL_SHIFT;
59
60       if (lzma_lzma_preset(&sec->options, preset)) 
61         {
62           stream->msg = "invalid lzma preset";
63           return XD3_INVALID;
64         }
65
66       sec->filters[0].id = LZMA_FILTER_LZMA2;
67       sec->filters[0].options = &sec->options;
68       sec->filters[1].id = LZMA_VLI_UNKNOWN;
69
70       ret = lzma_stream_encoder (&sec->lzma, &sec->filters[0], LZMA_CHECK_NONE);
71     }
72   else 
73     {
74       ret = lzma_stream_decoder (&sec->lzma, UINT64_MAX, LZMA_TELL_NO_CHECK);
75     }
76   
77   if (ret != LZMA_OK)
78     {
79       stream->msg = "lzma stream init failed";
80       return XD3_INTERNAL;
81     }
82
83   return 0;
84 }
85
86 int xd3_decode_lzma (xd3_stream *stream, xd3_lzma_stream *sec,
87                      const uint8_t **input_pos,
88                      const uint8_t  *const input_end,
89                      uint8_t       **output_pos,
90                      const uint8_t  *const output_end)
91 {
92   uint8_t *output = *output_pos;
93   const uint8_t *input = *input_pos;
94   size_t avail_in = input_end - input;
95   size_t avail_out = output_end - output;
96
97   sec->lzma.avail_in = avail_in;
98   sec->lzma.next_in = input;
99   sec->lzma.avail_out = avail_out;
100   sec->lzma.next_out = output;
101   
102   while (1) 
103     {
104       int lret = lzma_code (&sec->lzma, LZMA_RUN);
105
106       switch (lret)
107         {
108         case LZMA_NO_CHECK: 
109         case LZMA_OK:
110           if (sec->lzma.avail_out == 0) 
111             {
112               (*output_pos) = sec->lzma.next_out;
113               (*input_pos) = sec->lzma.next_in;
114               return 0;
115             }
116           break;
117
118         default:
119           stream->msg = "lzma decoding error";
120           return XD3_INTERNAL;
121         }
122     }
123 }
124
125 #if XD3_ENCODER
126
127 int xd3_encode_lzma (xd3_stream *stream, 
128                      xd3_lzma_stream *sec, 
129                      xd3_output   *input,
130                      xd3_output   *output,
131                      xd3_sec_cfg  *cfg)
132
133 {
134   lzma_action action = LZMA_RUN;
135
136   cfg->inefficient = 1;  /* Can't skip windows */
137   sec->lzma.next_in = NULL;
138   sec->lzma.avail_in = 0;
139   sec->lzma.next_out = (output->base + output->next);
140   sec->lzma.avail_out = (output->avail - output->next);
141
142   while (1)
143     {
144       int lret;
145           size_t nwrite;
146       if (sec->lzma.avail_in == 0 && input != NULL)
147         {
148           sec->lzma.avail_in = input->next;
149           sec->lzma.next_in = input->base;
150           
151           if ((input = input->next_page) == NULL)
152             {
153               action = LZMA_SYNC_FLUSH;
154             }
155         }
156
157       lret = lzma_code (&sec->lzma, action);
158
159       nwrite = (output->avail - output->next) - sec->lzma.avail_out;
160
161       if (nwrite != 0) 
162         {
163           output->next += nwrite;
164
165           if (output->next == output->avail)
166             {
167               if ((output = xd3_alloc_output (stream, output)) == NULL)
168                 {
169                   return ENOMEM;
170                 }
171               
172               sec->lzma.next_out = output->base;
173               sec->lzma.avail_out = output->avail;
174             }
175         }
176
177       switch (lret)
178         {
179         case LZMA_OK:
180           break;
181
182         case LZMA_STREAM_END:
183           return 0;
184
185         default:
186           stream->msg = "lzma encoding error";
187           return XD3_INTERNAL;
188         }
189     }
190
191   return 0;
192 }
193
194 #endif /* XD3_ENCODER */
195
196 #endif /* _XDELTA3_LZMA_H_ */