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 "../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);
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 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[0]));
116 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[1]));
117 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[2]));
118 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[3]));
120 if (payload_header[0] != 0x00081001) {
121 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[0] [0x%08X] != [0x00081001] (PULL)",
124 if (payload_header[1] != 0xCCCCCCCC) {
125 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[1] [0x%08X] != [0xCCCCCCCC] (PULL)",
129 payload_size = payload_header[2];
131 if (payload_header[3] != 0x00000000) {
132 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[3] [0x%08X] != [0x00000000] (PULL)",
136 payload_offset = comndr->offset;
137 NDR_CHECK(ndr_pull_advance(comndr, payload_size));
138 payload = comndr->data + payload_offset;
140 comndr->data = payload;
141 comndr->data_size = payload_size;
145 return NDR_ERR_SUCCESS;
148 static enum ndr_err_code ndr_push_compression_mszip(struct ndr_push *subndr,
149 struct ndr_push *comndr)
151 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)");
154 static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
155 struct ndr_push *ndrpush,
158 DATA_BLOB comp_chunk;
159 uint32_t comp_chunk_offset;
160 uint32_t comp_chunk_size;
161 uint32_t plain_chunk_size;
163 comp_chunk_offset = ndrpull->offset;
165 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
166 if (plain_chunk_size > 0x00010000) {
167 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)",
171 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
173 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
174 comp_chunk.length = comp_chunk_size + 8;
175 comp_chunk.data = ndrpull->data + comp_chunk_offset;
177 DEBUG(10,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
178 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
180 /* For now, we just copy over the compressed blob */
181 NDR_CHECK(ndr_push_bytes(ndrpush, comp_chunk.data, comp_chunk.length));
183 if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
184 /* this is the last chunk */
188 return NDR_ERR_SUCCESS;
191 static enum ndr_err_code ndr_pull_compression_xpress(struct ndr_pull *subndr,
192 struct ndr_pull **_comndr,
193 ssize_t decompressed_len)
195 struct ndr_push *ndrpush;
196 struct ndr_pull *comndr;
197 DATA_BLOB uncompressed;
200 ndrpush = ndr_push_init_ctx(subndr);
201 NDR_ERR_HAVE_NO_MEMORY(ndrpush);
204 NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr, ndrpush, &last));
207 uncompressed = ndr_push_blob(ndrpush);
209 comndr = talloc_zero(subndr, struct ndr_pull);
210 NDR_ERR_HAVE_NO_MEMORY(comndr);
211 comndr->flags = subndr->flags;
212 comndr->current_mem_ctx = subndr->current_mem_ctx;
214 comndr->data = uncompressed.data;
215 comndr->data_size = uncompressed.length;
219 return NDR_ERR_SUCCESS;
222 static enum ndr_err_code ndr_push_compression_xpress(struct ndr_push *subndr,
223 struct ndr_push *comndr)
225 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)");
229 handle compressed subcontext buffers, which in midl land are user-marshalled, but
230 we use magic in pidl to make them easier to cope with
232 enum ndr_err_code ndr_pull_compression_start(struct ndr_pull *subndr,
233 struct ndr_pull **_comndr,
234 enum ndr_compression_alg compression_alg,
235 ssize_t decompressed_len)
237 switch (compression_alg) {
238 case NDR_COMPRESSION_MSZIP:
239 return ndr_pull_compression_mszip(subndr, _comndr, decompressed_len);
240 case NDR_COMPRESSION_XPRESS:
241 return ndr_pull_compression_xpress(subndr, _comndr, decompressed_len);
243 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
246 return NDR_ERR_SUCCESS;
249 enum ndr_err_code ndr_pull_compression_end(struct ndr_pull *subndr,
250 struct ndr_pull *comndr,
251 enum ndr_compression_alg compression_alg,
252 ssize_t decompressed_len)
254 return NDR_ERR_SUCCESS;
258 push a compressed subcontext
260 enum ndr_err_code ndr_push_compression_start(struct ndr_push *subndr,
261 struct ndr_push **_comndr,
262 enum ndr_compression_alg compression_alg,
263 ssize_t decompressed_len)
265 struct ndr_push *comndr;
267 comndr = ndr_push_init_ctx(subndr);
268 NDR_ERR_HAVE_NO_MEMORY(comndr);
269 comndr->flags = subndr->flags;
272 return NDR_ERR_SUCCESS;
276 push a compressed subcontext
278 enum ndr_err_code ndr_push_compression_end(struct ndr_push *subndr,
279 struct ndr_push *comndr,
280 enum ndr_compression_alg compression_alg,
281 ssize_t decompressed_len)
283 switch (compression_alg) {
284 case NDR_COMPRESSION_MSZIP:
285 return ndr_push_compression_mszip(subndr, comndr);
286 case NDR_COMPRESSION_XPRESS:
287 return ndr_push_compression_xpress(subndr, comndr);
289 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",
292 return NDR_ERR_SUCCESS;