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"
26 static NTSTATUS ndr_pull_compression_mszip_chunk(struct ndr_pull *ndrpull,
27 struct ndr_push *ndrpush,
28 struct decomp_state *decomp_state)
31 uint32_t comp_chunk_offset;
32 uint32_t comp_chunk_size;
33 DATA_BLOB plain_chunk;
34 uint32_t plain_chunk_offset;
35 uint32_t plain_chunk_size;
38 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
39 if (plain_chunk_size > 0x00008000) {
40 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)",
44 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
46 DEBUG(10,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
47 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
49 comp_chunk_offset = ndrpull->offset;
50 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
51 comp_chunk.length = comp_chunk_size;
52 comp_chunk.data = ndrpull->data + comp_chunk_offset;
54 plain_chunk_offset = ndrpush->offset;
55 NDR_CHECK(ndr_push_zero(ndrpush, plain_chunk_size));
56 plain_chunk.length = plain_chunk_size;
57 plain_chunk.data = ndrpush->data + plain_chunk_offset;
59 ret = ZIPdecompress(decomp_state, &comp_chunk, &plain_chunk);
61 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad ZIPdecompress() error %d (PULL)",
65 if ((plain_chunk_size < 0x00008000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
66 /* this is the last chunk */
70 return NT_STATUS_MORE_PROCESSING_REQUIRED;
73 static NTSTATUS ndr_pull_compression_mszip(struct ndr_pull *subndr,
74 struct ndr_pull **_comndr,
75 ssize_t decompressed_len)
77 NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED;
78 struct ndr_push *ndrpush;
79 struct ndr_pull *comndr;
80 DATA_BLOB uncompressed;
81 uint32_t payload_header[4];
82 uint32_t payload_size;
83 uint32_t payload_offset;
85 struct decomp_state *decomp_state;
87 ndrpush = ndr_push_init_ctx(subndr);
88 NT_STATUS_HAVE_NO_MEMORY(ndrpush);
90 decomp_state = ZIPdecomp_state(subndr);
91 NT_STATUS_HAVE_NO_MEMORY(decomp_state);
93 while (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
94 status = ndr_pull_compression_mszip_chunk(subndr, ndrpush, decomp_state);
96 NT_STATUS_NOT_OK_RETURN(status);
98 uncompressed = ndr_push_blob(ndrpush);
100 if (uncompressed.length != decompressed_len) {
101 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP uncompressed_len [%u] != [%d] (PULL)",
102 (int)uncompressed.length, (int)decompressed_len);
105 comndr = talloc_zero(subndr, struct ndr_pull);
106 NT_STATUS_HAVE_NO_MEMORY(comndr);
107 comndr->flags = subndr->flags;
108 comndr->current_mem_ctx = subndr->current_mem_ctx;
110 comndr->data = uncompressed.data;
111 comndr->data_size = uncompressed.length;
114 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[0]));
115 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[1]));
116 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[2]));
117 NDR_CHECK(ndr_pull_uint32(comndr, NDR_SCALARS, &payload_header[3]));
119 if (payload_header[0] != 0x00081001) {
120 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[0] [0x%08X] != [0x00081001] (PULL)",
123 if (payload_header[1] != 0xCCCCCCCC) {
124 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[1] [0x%08X] != [0xCCCCCCCC] (PULL)",
128 payload_size = payload_header[2];
130 if (payload_header[3] != 0x00000000) {
131 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad MSZIP payload_header[3] [0x%08X] != [0x00000000] (PULL)",
135 payload_offset = comndr->offset;
136 NDR_CHECK(ndr_pull_advance(comndr, payload_size));
137 payload = comndr->data + payload_offset;
139 comndr->data = payload;
140 comndr->data_size = payload_size;
147 static NTSTATUS ndr_push_compression_mszip(struct ndr_push *subndr,
148 struct ndr_push *comndr)
150 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Sorry MSZIP compression is not supported yet (PUSH)");
153 static NTSTATUS ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,
154 struct ndr_push *ndrpush)
156 DATA_BLOB comp_chunk;
157 uint32_t comp_chunk_offset;
158 uint32_t comp_chunk_size;
159 uint32_t plain_chunk_size;
161 comp_chunk_offset = ndrpull->offset;
163 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &plain_chunk_size));
164 if (plain_chunk_size > 0x00010000) {
165 return ndr_pull_error(ndrpull, NDR_ERR_COMPRESSION, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)",
169 NDR_CHECK(ndr_pull_uint32(ndrpull, NDR_SCALARS, &comp_chunk_size));
171 NDR_CHECK(ndr_pull_advance(ndrpull, comp_chunk_size));
172 comp_chunk.length = comp_chunk_size + 8;
173 comp_chunk.data = ndrpull->data + comp_chunk_offset;
175 DEBUG(10,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
176 plain_chunk_size, plain_chunk_size, comp_chunk_size, comp_chunk_size));
178 /* For now, we just copy over the compressed blob */
179 NDR_CHECK(ndr_push_bytes(ndrpush, comp_chunk.data, comp_chunk.length));
181 if ((plain_chunk_size < 0x00010000) || (ndrpull->offset+4 >= ndrpull->data_size)) {
182 /* this is the last chunk */
186 return NT_STATUS_MORE_PROCESSING_REQUIRED;
189 static NTSTATUS ndr_pull_compression_xpress(struct ndr_pull *subndr,
190 struct ndr_pull **_comndr,
191 ssize_t decompressed_len)
193 NTSTATUS status = NT_STATUS_MORE_PROCESSING_REQUIRED;
194 struct ndr_push *ndrpush;
195 struct ndr_pull *comndr;
196 DATA_BLOB uncompressed;
198 ndrpush = ndr_push_init_ctx(subndr);
199 NT_STATUS_HAVE_NO_MEMORY(ndrpush);
201 while (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED, status)) {
202 status = ndr_pull_compression_xpress_chunk(subndr, ndrpush);
204 NT_STATUS_NOT_OK_RETURN(status);
206 uncompressed = ndr_push_blob(ndrpush);
208 comndr = talloc_zero(subndr, struct ndr_pull);
209 NT_STATUS_HAVE_NO_MEMORY(comndr);
210 comndr->flags = subndr->flags;
211 comndr->current_mem_ctx = subndr->current_mem_ctx;
213 comndr->data = uncompressed.data;
214 comndr->data_size = uncompressed.length;
221 static NTSTATUS ndr_push_compression_xpress(struct ndr_push *subndr,
222 struct ndr_push *comndr)
224 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "XPRESS compression is not supported yet (PUSH)");
228 handle compressed subcontext buffers, which in midl land are user-marshalled, but
229 we use magic in pidl to make them easier to cope with
231 NTSTATUS ndr_pull_compression_start(struct ndr_pull *subndr,
232 struct ndr_pull **_comndr,
233 enum ndr_compression_alg compression_alg,
234 ssize_t decompressed_len)
236 switch (compression_alg) {
237 case NDR_COMPRESSION_MSZIP:
238 return ndr_pull_compression_mszip(subndr, _comndr, decompressed_len);
239 case NDR_COMPRESSION_XPRESS:
240 return ndr_pull_compression_xpress(subndr, _comndr, decompressed_len);
242 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)",
248 NTSTATUS ndr_pull_compression_end(struct ndr_pull *subndr,
249 struct ndr_pull *comndr,
250 enum ndr_compression_alg compression_alg,
251 ssize_t decompressed_len)
257 push a compressed subcontext
259 NTSTATUS ndr_push_compression_start(struct ndr_push *subndr,
260 struct ndr_push **_comndr,
261 enum ndr_compression_alg compression_alg,
262 ssize_t decompressed_len)
264 struct ndr_push *comndr;
266 comndr = ndr_push_init_ctx(subndr);
267 NT_STATUS_HAVE_NO_MEMORY(comndr);
268 comndr->flags = subndr->flags;
275 push a compressed subcontext
277 NTSTATUS ndr_push_compression_end(struct ndr_push *subndr,
278 struct ndr_push *comndr,
279 enum ndr_compression_alg compression_alg,
280 ssize_t decompressed_len)
282 switch (compression_alg) {
283 case NDR_COMPRESSION_MSZIP:
284 return ndr_push_compression_mszip(subndr, comndr);
285 case NDR_COMPRESSION_XPRESS:
286 return ndr_push_compression_xpress(subndr, comndr);
288 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)",