chiark / gitweb /
cafe8f4f54e4758993a9531d746d04613d25e44c
[elogind.git] / src / journal / compress.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <assert.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <lzma.h>
26
27 #include "macro.h"
28 #include "compress.h"
29
30 bool compress_blob(const void *src, uint64_t src_size, void *dst, uint64_t *dst_size) {
31         lzma_ret ret;
32         size_t out_pos = 0;
33
34         assert(src);
35         assert(src_size > 0);
36         assert(dst);
37         assert(dst_size);
38
39         /* Returns false if we couldn't compress the data or the
40          * compressed result is longer than the original */
41
42         ret = lzma_easy_buffer_encode(LZMA_PRESET_DEFAULT, LZMA_CHECK_NONE, NULL,
43                                       src, src_size, dst, &out_pos, *dst_size);
44         if (ret != LZMA_OK)
45                 return false;
46
47         /* Is it actually shorter? */
48         if (out_pos == *dst_size)
49                 return false;
50
51         *dst_size = out_pos;
52         return true;
53 }
54
55 bool uncompress_blob(const void *src, uint64_t src_size,
56                      void **dst, uint64_t *dst_alloc_size, uint64_t* dst_size, uint64_t dst_max) {
57
58         lzma_stream s = LZMA_STREAM_INIT;
59         lzma_ret ret;
60         uint64_t space;
61         bool b = false;
62
63         assert(src);
64         assert(src_size > 0);
65         assert(dst);
66         assert(dst_alloc_size);
67         assert(dst_size);
68         assert(*dst_alloc_size == 0 || *dst);
69
70         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
71         if (ret != LZMA_OK)
72                 return false;
73
74         if (*dst_alloc_size <= src_size) {
75                 void *p;
76
77                 p = realloc(*dst, src_size*2);
78                 if (!p)
79                         return false;
80
81                 *dst = p;
82                 *dst_alloc_size = src_size*2;
83         }
84
85         s.next_in = src;
86         s.avail_in = src_size;
87
88         s.next_out = *dst;
89         space = dst_max > 0 ? MIN(*dst_alloc_size, dst_max) : *dst_alloc_size;
90         s.avail_out = space;
91
92         for (;;) {
93                 void *p;
94
95                 ret = lzma_code(&s, LZMA_FINISH);
96
97                 if (ret == LZMA_STREAM_END)
98                         break;
99
100                 if (ret != LZMA_OK)
101                         goto fail;
102
103                 if (dst_max > 0 && (space - s.avail_out) >= dst_max)
104                         break;
105
106                 p = realloc(*dst, space*2);
107                 if (!p)
108                         goto fail;
109
110                 s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *dst);
111                 s.avail_out += space;
112
113                 space *= 2;
114
115                 *dst = p;
116                 *dst_alloc_size = space;
117         }
118
119         *dst_size = space - s.avail_out;
120         b = true;
121
122 fail:
123         lzma_end(&s);
124
125         return b;
126 }
127
128 bool uncompress_startswith(const void *src, uint64_t src_size,
129                            void **buffer, uint64_t *buffer_size,
130                            const void *prefix, uint64_t prefix_len,
131                            uint8_t extra) {
132
133         lzma_stream s = LZMA_STREAM_INIT;
134         lzma_ret ret;
135         bool b = false;
136
137         /* Checks whether the uncompressed blob starts with the
138          * mentioned prefix. The byte extra needs to follow the
139          * prefix */
140
141         assert(src);
142         assert(src_size > 0);
143         assert(buffer);
144         assert(buffer_size);
145         assert(prefix);
146         assert(*buffer_size == 0 || *buffer);
147
148         ret = lzma_stream_decoder(&s, UINT64_MAX, 0);
149         if (ret != LZMA_OK)
150                 return false;
151
152         if (*buffer_size <= prefix_len) {
153                 void *p;
154
155                 p = realloc(*buffer, prefix_len*2);
156                 if (!p)
157                         return false;
158
159                 *buffer = p;
160                 *buffer_size = prefix_len*2;
161         }
162
163         s.next_in = src;
164         s.avail_in = src_size;
165
166         s.next_out = *buffer;
167         s.avail_out = *buffer_size;
168
169         for (;;) {
170                 void *p;
171
172                 ret = lzma_code(&s, LZMA_FINISH);
173
174                 if (ret != LZMA_STREAM_END && ret != LZMA_OK)
175                         goto fail;
176
177                 if ((*buffer_size - s.avail_out > prefix_len) &&
178                     memcmp(*buffer, prefix, prefix_len) == 0 &&
179                     ((const uint8_t*) *buffer)[prefix_len] == extra)
180                         break;
181
182                 if (ret == LZMA_STREAM_END)
183                         goto fail;
184
185                 p = realloc(*buffer, *buffer_size*2);
186                 if (!p)
187                         goto fail;
188
189                 s.next_out = (uint8_t*) p + ((uint8_t*) s.next_out - (uint8_t*) *buffer);
190                 s.avail_out += *buffer_size;
191
192                 *buffer = p;
193                 *buffer_size *= 2;
194         }
195
196         b = true;
197
198 fail:
199         lzma_end(&s);
200
201         return b;
202 }