2 Unix SMB/CIFS implementation.
4 libndr compression support
6 Copyright (C) Stefan Metzmacher 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "lib/compression/mszip.h"
24 #include "librpc/ndr/libndr.h"
25 #include "librpc/ndr/ndr_compression.h"
27 static enum ndr_err_code ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
28 struct ndr_push *ndrpush,
29 struct decomp_state *decomp_state,
33 uint32_t comp_chunk_offset;
34 uint32_t comp_chunk_size;
35 DATA_BLOB plain_chunk;
36 uint32_t plain_chunk_offset;
37 uint32_t plain_chunk_size;
40 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
41 if (plain_chunk_size > 0x00008000) {
42 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)",
46 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
48 DEBUG(10,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
49 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
51 comp_chunk_offset = ndrpull->offset;
52 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
53 comp_chunk.length = comp_chunk_size;
54 comp_chunk.data = ndrpull->data + comp_chunk_offset;
56 plain_chunk_offset = ndrpush->offset;
57 NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
58 plain_chunk.length = plain_chunk_size;
59 plain_chunk.data = ndrpush->data + plain_chunk_offset;
61 ret = ZIPdecompress(decomp_state, &comp_chunk, &plain_chunk);
63 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZIPdecompress() error %d (PULL)",
67 if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
68 /* this is the last chunk */
72 return NDR_ERR_SUCCESS;
75 static enum ndr_err_code ndr_pull_compression_mszip(struct ndr_pull *subndr,
76 struct ndr_pull **_comndr,
77 ssize_t decompressed_len)
79 struct ndr_push *ndrpush;
80 struct ndr_pull *comndr;
81 DATA_BLOB uncompressed;
82 uint32_t payload_header[4];
83 uint32_t payload_size;
84 uint32_t payload_offset;
86 struct decomp_state *decomp_state;
89 ndrpush = ndr_push_init_ctx(subndr, subndr->iconv_convenience);
90 NDR_ERR_HAVE_NO_MEMORY(ndrpush);
92 decomp_state = ZIPdecomp_state(subndr);
93 NDR_ERR_HAVE_NO_MEMORY(decomp_state);
96 NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr, ndrpush, decomp_state, &last));
99 uncompressed = ndr_push_blob(ndrpush);
101 if (uncompressed.length != decompressed_len) {
102 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP uncompressed_len [%u] != [%d] (PULL)",
103 (int)uncompressed.length, (int)decompressed_len);
106 comndr = talloc_zero(subndr, struct ndr_pull);
107 NDR_ERR_HAVE_NO_MEMORY(comndr);
108 comndr->flags = subndr->flags;
109 comndr->current_mem_ctx = subndr->current_mem_ctx;
111 comndr->data = uncompressed.data;
112 comndr->data_size = uncompressed.length;
115 comndr->iconv_convenience = talloc_reference(comndr, subndr->iconv_convenience);
117 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[0]));
118 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[1]));
119 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[2]));
120 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[3]));
122 if (payload_header[0] != 0x00081001) {
123 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[0] [0x%08X] != [0x00081001] (PULL)",
126 if (payload_header[1] != 0xCCCCCCCC) {
127 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[1] [0x%08X] != [0xCCCCCCCC] (PULL)",
131 payload_size = payload_header[2];
133 if (payload_header[3] != 0x00000000) {
134 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[3] [0x%08X] != [0x00000000] (PULL)",
138 payload_offset = comndr->offset;
139 NDR_CHECK(ndr_pull_advance(comndr, payload_size));
140 payload = comndr->data + payload_offset;
142 comndr->data = payload;
143 comndr->data_size = payload_size;
147 return NDR_ERR_SUCCESS;
150 static enum ndr_err_code ndr_push_compression_mszip(struct ndr_push *subndr,
151 struct ndr_push *comndr)
153 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)");
156 static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
157 struct ndr_push *ndrpush,
160 DATA_BLOB comp_chunk;
161 uint32_t comp_chunk_offset;
162 uint32_t comp_chunk_size;
163 uint32_t plain_chunk_size;
165 comp_chunk_offset = ndrpull->offset;
167 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
168 if (plain_chunk_size > 0x00010000) {
169 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)",
173 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
175 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
176 comp_chunk.length = comp_chunk_size + 8;
177 comp_chunk.data = ndrpull->data + comp_chunk_offset;
179 DEBUG(10,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
180 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
182 /* For now, we just copy over the compressed blob */
183 NDR_CHECK(ndr_push_bytes(ndrpush, comp_chunk.data, comp_chunk.length));
185 if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
186 /* this is the last chunk */
190 return NDR_ERR_SUCCESS;
193 static enum ndr_err_code ndr_pull_compression_xpress(struct ndr_pull *subndr,
194 struct ndr_pull **_comndr,
195 ssize_t decompressed_len)
197 struct ndr_push *ndrpush;
198 struct ndr_pull *comndr;
199 DATA_BLOB uncompressed;
202 ndrpush = ndr_push_init_ctx(subndr, subndr->iconv_convenience);
203 NDR_ERR_HAVE_NO_MEMORY(ndrpush);
206 NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last));
209 uncompressed = ndr_push_blob(ndrpush);
211 comndr = talloc_zero(subndr, struct ndr_pull);
212 NDR_ERR_HAVE_NO_MEMORY(comndr);
213 comndr->flags = subndr->flags;
214 comndr->current_mem_ctx = subndr->current_mem_ctx;
216 comndr->data = uncompressed.data;
217 comndr->data_size = uncompressed.length;
220 comndr->iconv_convenience = talloc_reference(comndr, subndr->iconv_convenience);
223 return NDR_ERR_SUCCESS;
226 static enum ndr_err_code ndr_push_compression_xpress(struct ndr_push *subndr,
227 struct ndr_push *comndr)
229 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)");
233 handle compressed subcontext buffers, which in midl land are user-marshalled, but
234 we use magic in pidl to make them easier to cope with
236 enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
237 struct ndr_pull **_comndr,
238 enum ndr_compression_alg compression_alg,
239 ssize_t decompressed_len)
241 switch (compression_alg) {
242 case NDR_COMPRESSION_MSZIP:
243 return ndr_pull_compression_mszip(subndr, _comndr, decompressed_len);
244 case NDR_COMPRESSION_XPRESS:
245 return ndr_pull_compression_xpress(subndr, _comndr, decompressed_len);
247 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
250 return NDR_ERR_SUCCESS;
253 enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
254 struct ndr_pull *comndr,
255 enum ndr_compression_alg compression_alg,
256 ssize_t decompressed_len)
258 return NDR_ERR_SUCCESS;
262 push a compressed subcontext
264 enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
265 struct ndr_push **_comndr,
266 enum ndr_compression_alg compression_alg,
267 ssize_t decompressed_len)
269 struct ndr_push *comndr;
271 comndr = ndr_push_init_ctx(subndr, subndr->iconv_convenience);
272 NDR_ERR_HAVE_NO_MEMORY(comndr);
273 comndr->flags = subndr->flags;
276 return NDR_ERR_SUCCESS;
280 push a compressed subcontext
282 enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
283 struct ndr_push *comndr,
284 enum ndr_compression_alg compression_alg,
285 ssize_t decompressed_len)
287 switch (compression_alg) {
288 case NDR_COMPRESSION_MSZIP:
289 return ndr_push_compression_mszip(subndr, comndr);
290 case NDR_COMPRESSION_XPRESS:
291 return ndr_push_compression_xpress(subndr, comndr);
293 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",
296 return NDR_ERR_SUCCESS;