2 Unix SMB/CIFS implementation.
4 libndr compression support
6 Copyright (C) Stefan Metzmacher 2005
7 Copyright (C) Matthieu Suiche 2008
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 #include "../lib/compression/lzxpress.h"
25 #include "librpc/ndr/libndr.h"
26 #include "../librpc/ndr/ndr_compression.h"
29 struct ndr_compression_state
{
30 enum ndr_compression_alg type
;
40 static voidpf
ndr_zlib_alloc(voidpf opaque
, uInt items
, uInt size
)
42 return talloc_zero_size(opaque
, items
* size
);
45 static void ndr_zlib_free(voidpf opaque
, voidpf address
)
50 static enum ndr_err_code
ndr_pull_compression_mszip_cab_chunk(struct ndr_pull
*ndrpull
,
51 struct ndr_push
*ndrpush
,
52 struct ndr_compression_state
*state
,
53 ssize_t decompressed_len
,
54 ssize_t compressed_len
)
57 uint32_t comp_chunk_offset
;
58 uint32_t comp_chunk_size
;
59 DATA_BLOB plain_chunk
;
60 uint32_t plain_chunk_offset
;
61 uint32_t plain_chunk_size
;
62 z_stream
*z
= state
->alg
.mszip
.z
;
65 plain_chunk_size
= decompressed_len
;
67 if (plain_chunk_size
> 0x00008000) {
68 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
69 "Bad MSZIP CAB plain chunk size %08X > 0x00008000 (PULL)",
74 comp_chunk_size
= compressed_len
;
76 DEBUG(9,("MSZIP CAB plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
77 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
79 comp_chunk_offset
= ndrpull
->offset
;
80 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
81 comp_chunk
.length
= comp_chunk_size
;
82 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
84 plain_chunk_offset
= ndrpush
->offset
;
85 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
86 plain_chunk
.length
= plain_chunk_size
;
87 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
89 if (comp_chunk
.length
< 2) {
90 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
91 "Bad MSZIP CAB comp chunk size %u < 2 (PULL)",
92 (unsigned int)comp_chunk
.length
);
94 /* CK = Chris Kirmse, official Microsoft purloiner */
95 if (comp_chunk
.data
[0] != 'C' ||
96 comp_chunk
.data
[1] != 'K') {
97 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
98 "Bad MSZIP CAB invalid prefix [%c%c] != [CK]",
99 comp_chunk
.data
[0], comp_chunk
.data
[1]);
103 * This is a MSZIP block. It is actually using the deflate
104 * algorithm which can be decompressed by zlib. zlib will try
105 * to decompress as much as it can in each run. If we provide
106 * all the input and enough room for the uncompressed output,
107 * one call is enough. It will loop over all the sub-blocks
108 * that make up a deflate block.
110 * See corresponding push function for more info.
113 z
->next_in
= comp_chunk
.data
+ 2;
114 z
->avail_in
= comp_chunk
.length
- 2;
115 z
->next_out
= plain_chunk
.data
;
116 z
->avail_out
= plain_chunk
.length
;
119 * Each MSZIP CDATA contains a complete deflate stream
120 * i.e. the stream starts and ends in the CFDATA but the
121 * _dictionary_ is shared between all CFDATA of a CFFOLDER.
123 * When decompressing, the initial dictionary of the first
124 * CDATA is empty. All other CFDATA use the previous CFDATA
125 * uncompressed output as dictionary.
128 if (state
->alg
.mszip
.dict_size
) {
129 z_ret
= inflateSetDictionary(z
, state
->alg
.mszip
.dict
, state
->alg
.mszip
.dict_size
);
131 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
132 "zlib inflateSetDictionary error %s (%d) %s (PULL)",
133 zError(z_ret
), z_ret
, z
->msg
);
137 z_ret
= inflate(z
, Z_FINISH
);
140 * Z_OK here means there was no error but the stream
141 * hasn't been fully decompressed because there was
142 * not enough room for the output, which should not
145 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
146 "zlib inflate error not enough space for output (PULL)");
148 if (z_ret
!= Z_STREAM_END
) {
149 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
150 "zlib inflate error %s (%d) %s (PULL)", zError(z_ret
), z_ret
, z
->msg
);
153 if (z
->total_out
< plain_chunk
.length
) {
154 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
155 "zlib uncompressed output is smaller than expected (%lu < %zu) (PULL)",
156 z
->total_out
, plain_chunk
.length
);
160 * Keep a copy of the output to set as dictionary for the
161 * next decompression call.
163 * The input pointer seems to be still valid between calls, so
164 * we can just store that instead of copying the memory over
165 * the dict temp buffer.
167 state
->alg
.mszip
.dict
= plain_chunk
.data
;
168 state
->alg
.mszip
.dict_size
= plain_chunk
.length
;
170 z_ret
= inflateReset(z
);
172 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
173 "zlib inflateReset error %s (%d) %s (PULL)",
174 zError(z_ret
), z_ret
, z
->msg
);
177 return NDR_ERR_SUCCESS
;
180 static enum ndr_err_code
ndr_push_compression_mszip_cab_chunk(struct ndr_push
*ndrpush
,
181 struct ndr_pull
*ndrpull
,
182 struct ndr_compression_state
*state
)
184 DATA_BLOB comp_chunk
;
185 uint32_t comp_chunk_size
;
186 DATA_BLOB plain_chunk
;
187 uint32_t plain_chunk_size
;
188 uint32_t plain_chunk_offset
;
189 uint32_t max_plain_size
= 0x00008000;
191 * The maximum compressed size of each MSZIP block is 32k + 12 bytes
194 uint32_t max_comp_size
= 0x00008000 + 12;
198 if (ndrpull
->data_size
<= ndrpull
->offset
) {
199 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
200 "strange NDR pull size and offset (integer overflow?)");
204 plain_chunk_size
= MIN(max_plain_size
, ndrpull
->data_size
- ndrpull
->offset
);
205 plain_chunk_offset
= ndrpull
->offset
;
206 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
208 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
209 plain_chunk
.length
= plain_chunk_size
;
211 NDR_CHECK(ndr_push_expand(ndrpush
, max_comp_size
));
213 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
214 comp_chunk
.length
= max_comp_size
;
216 /* CK = Chris Kirmse, official Microsoft purloiner */
217 comp_chunk
.data
[0] = 'C';
218 comp_chunk
.data
[1] = 'K';
220 z
= state
->alg
.mszip
.z
;
221 z
->next_in
= plain_chunk
.data
;
222 z
->avail_in
= plain_chunk
.length
;
225 z
->next_out
= comp_chunk
.data
+ 2;
226 z
->avail_out
= comp_chunk
.length
;
230 * See pull function for explanations of the MSZIP format.
232 * The CFDATA block contains a full deflate stream. Each stream
233 * uses the uncompressed input of the previous CFDATA in the
234 * same CFFOLDER as a dictionary for the compression.
237 if (state
->alg
.mszip
.dict_size
) {
238 z_ret
= deflateSetDictionary(z
, state
->alg
.mszip
.dict
, state
->alg
.mszip
.dict_size
);
240 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
241 "zlib deflateSetDictionary error %s (%d) %s (PUSH)",
242 zError(z_ret
), z_ret
, z
->msg
);
247 * Z_FINISH should make deflate process all of the input in
248 * one call. If the stream is not finished there was an error
249 * e.g. not enough room to store the compressed output.
251 z_ret
= deflate(z
, Z_FINISH
);
252 if (z_ret
!= Z_STREAM_END
) {
253 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
254 "zlib deflate error %s (%d) %s (PUSH)",
255 zError(z_ret
), z_ret
, z
->msg
);
259 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
260 "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
264 comp_chunk_size
= 2 + z
->total_out
;
265 if (comp_chunk_size
< z
->total_out
) {
266 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
267 "strange NDR push compressed size (integer overflow?)");
270 z_ret
= deflateReset(z
);
272 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
273 "zlib deflateReset error %s (%d) %s (PUSH)",
274 zError(z_ret
), z_ret
, z
->msg
);
277 if (plain_chunk
.length
> talloc_array_length(state
->alg
.mszip
.dict
)) {
278 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
279 "zlib dict buffer is too big (PUSH)");
283 * Keep a copy of the input to set as dictionary for the next
286 * Ideally we would just store the input pointer and length
287 * without copying but the memory gets invalidated between the
288 * calls, so we just copy to a dedicated buffer we now is
289 * still going to been valid for the lifetime of the
290 * compressions state object.
292 memcpy(state
->alg
.mszip
.dict
, plain_chunk
.data
, plain_chunk
.length
);
293 state
->alg
.mszip
.dict_size
= plain_chunk
.length
;
295 DEBUG(9,("MSZIP comp plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
296 (unsigned int)plain_chunk
.length
,
297 (unsigned int)plain_chunk
.length
,
298 comp_chunk_size
, comp_chunk_size
));
300 ndrpush
->offset
+= comp_chunk_size
;
301 return NDR_ERR_SUCCESS
;
305 static enum ndr_err_code
ndr_pull_compression_mszip_chunk(struct ndr_pull
*ndrpull
,
306 struct ndr_push
*ndrpush
,
310 DATA_BLOB comp_chunk
;
311 uint32_t comp_chunk_offset
;
312 uint32_t comp_chunk_size
;
313 DATA_BLOB plain_chunk
;
314 uint32_t plain_chunk_offset
;
315 uint32_t plain_chunk_size
;
318 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &plain_chunk_size
));
319 if (plain_chunk_size
> 0x00008000) {
320 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
, "Bad MSZIP plain chunk size %08X > 0x00008000 (PULL)",
324 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &comp_chunk_size
));
326 DEBUG(9,("MSZIP plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
327 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
329 comp_chunk_offset
= ndrpull
->offset
;
330 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
331 comp_chunk
.length
= comp_chunk_size
;
332 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
334 plain_chunk_offset
= ndrpush
->offset
;
335 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
336 plain_chunk
.length
= plain_chunk_size
;
337 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
339 if (comp_chunk
.length
< 2) {
340 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
341 "Bad MSZIP comp chunk size %u < 2 (PULL)",
342 (unsigned int)comp_chunk
.length
);
344 /* CK = Chris Kirmse, official Microsoft purloiner */
345 if (comp_chunk
.data
[0] != 'C' ||
346 comp_chunk
.data
[1] != 'K') {
347 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
348 "Bad MSZIP invalid prefix [%c%c] != [CK]",
349 comp_chunk
.data
[0], comp_chunk
.data
[1]);
352 z
->next_in
= comp_chunk
.data
+ 2;
353 z
->avail_in
= comp_chunk
.length
-2;
356 z
->next_out
= plain_chunk
.data
;
357 z
->avail_out
= plain_chunk
.length
;
361 /* the first time we need to intialize completely */
362 z
->zalloc
= ndr_zlib_alloc
;
363 z
->zfree
= ndr_zlib_free
;
366 z_ret
= inflateInit2(z
, -MAX_WBITS
);
368 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
369 "Bad inflateInit2 error %s(%d) (PULL)",
370 zError(z_ret
), z_ret
);
375 /* call inflate untill we get Z_STREAM_END or an error */
377 z_ret
= inflate(z
, Z_BLOCK
);
378 if (z_ret
!= Z_OK
) break;
381 if (z_ret
!= Z_STREAM_END
) {
382 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
383 "Bad inflate(Z_BLOCK) error %s(%d) (PULL)",
384 zError(z_ret
), z_ret
);
388 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
389 "MSZIP not all avail_in[%u] bytes consumed (PULL)",
394 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
395 "MSZIP not all avail_out[%u] bytes consumed (PULL)",
399 if ((plain_chunk_size
< 0x00008000) || (ndrpull
->offset
+4 >= ndrpull
->data_size
)) {
400 /* this is the last chunk */
404 z_ret
= inflateReset(z
);
406 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
407 "Bad inflateReset error %s(%d) (PULL)",
408 zError(z_ret
), z_ret
);
411 z_ret
= inflateSetDictionary(z
, plain_chunk
.data
, plain_chunk
.length
);
413 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
414 "Bad inflateSetDictionary error %s(%d) (PULL)",
415 zError(z_ret
), z_ret
);
418 return NDR_ERR_SUCCESS
;
421 static enum ndr_err_code
ndr_push_compression_mszip_chunk(struct ndr_push
*ndrpush
,
422 struct ndr_pull
*ndrpull
,
426 DATA_BLOB comp_chunk
;
427 uint32_t comp_chunk_size
;
428 uint32_t comp_chunk_size_offset
;
429 DATA_BLOB plain_chunk
;
430 uint32_t plain_chunk_size
;
431 uint32_t plain_chunk_offset
;
432 uint32_t max_plain_size
= 0x00008000;
434 * The maximum compressed size of each MSZIP block is 32k + 12 bytes
437 uint32_t max_comp_size
= 0x00008000 + 12;
441 plain_chunk_size
= MIN(max_plain_size
, ndrpull
->data_size
- ndrpull
->offset
);
442 plain_chunk_offset
= ndrpull
->offset
;
443 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
445 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
446 plain_chunk
.length
= plain_chunk_size
;
448 if (plain_chunk_size
< max_plain_size
) {
452 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, plain_chunk_size
));
453 comp_chunk_size_offset
= ndrpush
->offset
;
454 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, 0xFEFEFEFE));
456 NDR_CHECK(ndr_push_expand(ndrpush
, max_comp_size
));
458 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
459 comp_chunk
.length
= max_comp_size
;
461 /* CK = Chris Kirmse, official Microsoft purloiner */
462 comp_chunk
.data
[0] = 'C';
463 comp_chunk
.data
[1] = 'K';
465 z
->next_in
= plain_chunk
.data
;
466 z
->avail_in
= plain_chunk
.length
;
469 z
->next_out
= comp_chunk
.data
+ 2;
470 z
->avail_out
= comp_chunk
.length
;
474 /* the first time we need to intialize completely */
475 z
->zalloc
= ndr_zlib_alloc
;
476 z
->zfree
= ndr_zlib_free
;
479 /* TODO: find how to trigger the same parameters windows uses */
480 z_ret
= deflateInit2(z
,
481 Z_DEFAULT_COMPRESSION
,
487 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
488 "Bad deflateInit2 error %s(%d) (PUSH)",
489 zError(z_ret
), z_ret
);
494 /* call deflate untill we get Z_STREAM_END or an error */
496 z_ret
= deflate(z
, Z_FINISH
);
497 if (z_ret
!= Z_OK
) break;
499 if (z_ret
!= Z_STREAM_END
) {
500 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
501 "Bad delate(Z_BLOCK) error %s(%d) (PUSH)",
502 zError(z_ret
), z_ret
);
506 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
507 "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
511 comp_chunk_size
= 2 + z
->total_out
;
513 z_ret
= deflateReset(z
);
515 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
516 "Bad deflateReset error %s(%d) (PULL)",
517 zError(z_ret
), z_ret
);
520 z_ret
= deflateSetDictionary(z
, plain_chunk
.data
, plain_chunk
.length
);
522 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
523 "Bad deflateSetDictionary error %s(%d) (PULL)",
524 zError(z_ret
), z_ret
);
527 tmp_offset
= ndrpush
->offset
;
528 ndrpush
->offset
= comp_chunk_size_offset
;
529 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, comp_chunk_size
));
530 ndrpush
->offset
= tmp_offset
;
532 DEBUG(9,("MSZIP comp plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
533 (unsigned int)plain_chunk
.length
,
534 (unsigned int)plain_chunk
.length
,
535 comp_chunk_size
, comp_chunk_size
));
537 ndrpush
->offset
+= comp_chunk_size
;
538 return NDR_ERR_SUCCESS
;
541 static enum ndr_err_code
ndr_pull_compression_xpress_chunk(struct ndr_pull
*ndrpull
,
542 struct ndr_push
*ndrpush
,
545 DATA_BLOB comp_chunk
;
546 DATA_BLOB plain_chunk
;
547 uint32_t comp_chunk_offset
;
548 uint32_t plain_chunk_offset
;
549 uint32_t comp_chunk_size
;
550 uint32_t plain_chunk_size
;
553 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &plain_chunk_size
));
554 if (plain_chunk_size
> 0x00010000) {
555 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
, "Bad XPRESS plain chunk size %08X > 0x00010000 (PULL)",
559 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &comp_chunk_size
));
561 comp_chunk_offset
= ndrpull
->offset
;
562 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
563 comp_chunk
.length
= comp_chunk_size
;
564 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
566 plain_chunk_offset
= ndrpush
->offset
;
567 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
568 plain_chunk
.length
= plain_chunk_size
;
569 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
571 DEBUG(9,("XPRESS plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
572 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
574 /* Uncompressing the buffer using LZ Xpress algorithm */
575 ret
= lzxpress_decompress(comp_chunk
.data
,
580 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
581 "XPRESS lzxpress_decompress() returned %d\n",
584 plain_chunk
.length
= ret
;
586 if ((plain_chunk_size
< 0x00010000) || (ndrpull
->offset
+4 >= ndrpull
->data_size
)) {
587 /* this is the last chunk */
591 return NDR_ERR_SUCCESS
;
594 static enum ndr_err_code
ndr_push_compression_xpress_chunk(struct ndr_push
*ndrpush
,
595 struct ndr_pull
*ndrpull
,
598 DATA_BLOB comp_chunk
;
599 uint32_t comp_chunk_size_offset
;
600 DATA_BLOB plain_chunk
;
601 uint32_t plain_chunk_size
;
602 uint32_t plain_chunk_offset
;
603 uint32_t max_plain_size
= 0x00010000;
604 uint32_t max_comp_size
= 0x00020000 + 2; /* TODO: use the correct value here */
608 plain_chunk_size
= MIN(max_plain_size
, ndrpull
->data_size
- ndrpull
->offset
);
609 plain_chunk_offset
= ndrpull
->offset
;
610 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
612 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
613 plain_chunk
.length
= plain_chunk_size
;
615 if (plain_chunk_size
< max_plain_size
) {
619 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, plain_chunk_size
));
620 comp_chunk_size_offset
= ndrpush
->offset
;
621 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, 0xFEFEFEFE));
623 NDR_CHECK(ndr_push_expand(ndrpush
, max_comp_size
));
625 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
626 comp_chunk
.length
= max_comp_size
;
628 /* Compressing the buffer using LZ Xpress algorithm */
629 ret
= lzxpress_compress(plain_chunk
.data
,
634 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
635 "XPRESS lzxpress_compress() returned %d\n",
638 comp_chunk
.length
= ret
;
640 tmp_offset
= ndrpush
->offset
;
641 ndrpush
->offset
= comp_chunk_size_offset
;
642 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, comp_chunk
.length
));
643 ndrpush
->offset
= tmp_offset
;
645 ndrpush
->offset
+= comp_chunk
.length
;
646 return NDR_ERR_SUCCESS
;
650 handle compressed subcontext buffers, which in midl land are user-marshalled, but
651 we use magic in pidl to make them easier to cope with
653 enum ndr_err_code
ndr_pull_compression_start(struct ndr_pull
*subndr
,
654 struct ndr_pull
**_comndr
,
655 enum ndr_compression_alg compression_alg
,
656 ssize_t decompressed_len
,
657 ssize_t compressed_len
)
659 struct ndr_push
*ndrpush
;
660 struct ndr_pull
*comndr
;
661 DATA_BLOB uncompressed
;
665 ndrpush
= ndr_push_init_ctx(subndr
);
666 NDR_ERR_HAVE_NO_MEMORY(ndrpush
);
668 switch (compression_alg
) {
669 case NDR_COMPRESSION_MSZIP_CAB
:
670 NDR_CHECK(ndr_pull_compression_mszip_cab_chunk(subndr
, ndrpush
,
675 case NDR_COMPRESSION_MSZIP
:
678 NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr
, ndrpush
, &z
, &last
));
682 case NDR_COMPRESSION_XPRESS
:
684 NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr
, ndrpush
, &last
));
689 return ndr_pull_error(subndr
, NDR_ERR_COMPRESSION
, "Bad compression algorithm %d (PULL)",
693 uncompressed
= ndr_push_blob(ndrpush
);
694 if (uncompressed
.length
!= decompressed_len
) {
695 return ndr_pull_error(subndr
, NDR_ERR_COMPRESSION
,
696 "Bad uncompressed_len [%u] != [%u](0x%08X) (PULL)",
697 (int)uncompressed
.length
,
698 (int)decompressed_len
,
699 (int)decompressed_len
);
702 comndr
= talloc_zero(subndr
, struct ndr_pull
);
703 NDR_ERR_HAVE_NO_MEMORY(comndr
);
704 comndr
->flags
= subndr
->flags
;
705 comndr
->current_mem_ctx
= subndr
->current_mem_ctx
;
707 comndr
->data
= uncompressed
.data
;
708 comndr
->data_size
= uncompressed
.length
;
712 return NDR_ERR_SUCCESS
;
715 enum ndr_err_code
ndr_pull_compression_end(struct ndr_pull
*subndr
,
716 struct ndr_pull
*comndr
,
717 enum ndr_compression_alg compression_alg
,
718 ssize_t decompressed_len
)
720 return NDR_ERR_SUCCESS
;
724 push a compressed subcontext
726 enum ndr_err_code
ndr_push_compression_start(struct ndr_push
*subndr
,
727 struct ndr_push
**_uncomndr
,
728 enum ndr_compression_alg compression_alg
,
729 ssize_t decompressed_len
)
731 struct ndr_push
*uncomndr
;
733 switch (compression_alg
) {
734 case NDR_COMPRESSION_MSZIP_CAB
:
735 case NDR_COMPRESSION_MSZIP
:
736 case NDR_COMPRESSION_XPRESS
:
739 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
,
740 "Bad compression algorithm %d (PUSH)",
744 uncomndr
= ndr_push_init_ctx(subndr
);
745 NDR_ERR_HAVE_NO_MEMORY(uncomndr
);
746 uncomndr
->flags
= subndr
->flags
;
748 *_uncomndr
= uncomndr
;
749 return NDR_ERR_SUCCESS
;
753 push a compressed subcontext
755 enum ndr_err_code
ndr_push_compression_end(struct ndr_push
*subndr
,
756 struct ndr_push
*uncomndr
,
757 enum ndr_compression_alg compression_alg
,
758 ssize_t decompressed_len
)
760 struct ndr_pull
*ndrpull
;
764 ndrpull
= talloc_zero(uncomndr
, struct ndr_pull
);
765 NDR_ERR_HAVE_NO_MEMORY(ndrpull
);
766 ndrpull
->flags
= uncomndr
->flags
;
767 ndrpull
->data
= uncomndr
->data
;
768 ndrpull
->data_size
= uncomndr
->offset
;
771 switch (compression_alg
) {
772 case NDR_COMPRESSION_MSZIP_CAB
:
773 NDR_CHECK(ndr_push_compression_mszip_cab_chunk(subndr
, ndrpull
, subndr
->cstate
));
776 case NDR_COMPRESSION_MSZIP
:
779 NDR_CHECK(ndr_push_compression_mszip_chunk(subndr
, ndrpull
, &z
, &last
));
783 case NDR_COMPRESSION_XPRESS
:
785 NDR_CHECK(ndr_push_compression_xpress_chunk(subndr
, ndrpull
, &last
));
790 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
, "Bad compression algorithm %d (PUSH)",
794 talloc_free(uncomndr
);
795 return NDR_ERR_SUCCESS
;
798 static enum ndr_err_code
generic_mszip_init(TALLOC_CTX
*mem_ctx
,
799 struct ndr_compression_state
*state
)
801 z_stream
*z
= talloc_zero(mem_ctx
, z_stream
);
802 NDR_ERR_HAVE_NO_MEMORY(z
);
804 z
->zalloc
= ndr_zlib_alloc
;
805 z
->zfree
= ndr_zlib_free
;
808 state
->alg
.mszip
.z
= z
;
809 state
->alg
.mszip
.dict_size
= 0;
810 /* pre-alloc dictionary */
811 state
->alg
.mszip
.dict
= talloc_array(mem_ctx
, uint8_t, 0x8000);
812 NDR_ERR_HAVE_NO_MEMORY(state
->alg
.mszip
.dict
);
814 return NDR_ERR_SUCCESS
;
817 static void generic_mszip_free(struct ndr_compression_state
*state
)
823 TALLOC_FREE(state
->alg
.mszip
.z
);
824 TALLOC_FREE(state
->alg
.mszip
.dict
);
828 enum ndr_err_code
ndr_pull_compression_state_init(struct ndr_pull
*ndr
,
829 enum ndr_compression_alg compression_alg
,
830 struct ndr_compression_state
**state
)
832 struct ndr_compression_state
*s
;
835 s
= talloc_zero(ndr
, struct ndr_compression_state
);
836 NDR_ERR_HAVE_NO_MEMORY(s
);
837 s
->type
= compression_alg
;
839 switch (compression_alg
) {
840 case NDR_COMPRESSION_MSZIP
:
841 case NDR_COMPRESSION_XPRESS
:
843 case NDR_COMPRESSION_MSZIP_CAB
:
844 NDR_CHECK(generic_mszip_init(ndr
, s
));
845 z_ret
= inflateInit2(s
->alg
.mszip
.z
, -MAX_WBITS
);
847 return ndr_pull_error(ndr
, NDR_ERR_COMPRESSION
,
848 "zlib inflateinit2 error %s (%d) %s (PULL)",
849 zError(z_ret
), z_ret
, s
->alg
.mszip
.z
->msg
);
853 return ndr_pull_error(ndr
, NDR_ERR_COMPRESSION
,
854 "Bad compression algorithm %d (PULL)",
861 return NDR_ERR_SUCCESS
;
864 void ndr_pull_compression_state_free(struct ndr_compression_state
*state
)
870 switch (state
->type
) {
871 case NDR_COMPRESSION_MSZIP
:
872 case NDR_COMPRESSION_XPRESS
:
874 case NDR_COMPRESSION_MSZIP_CAB
:
875 generic_mszip_free(state
);
883 enum ndr_err_code
ndr_push_compression_state_init(struct ndr_push
*ndr
,
884 enum ndr_compression_alg compression_alg
,
885 struct ndr_compression_state
**state
)
887 struct ndr_compression_state
*s
;
890 s
= talloc_zero(ndr
, struct ndr_compression_state
);
891 NDR_ERR_HAVE_NO_MEMORY(s
);
892 s
->type
= compression_alg
;
894 switch (compression_alg
) {
895 case NDR_COMPRESSION_XPRESS
:
896 case NDR_COMPRESSION_MSZIP
:
898 case NDR_COMPRESSION_MSZIP_CAB
:
899 NDR_CHECK(generic_mszip_init(ndr
, s
));
900 z_ret
= deflateInit2(s
->alg
.mszip
.z
,
901 Z_DEFAULT_COMPRESSION
,
907 return ndr_push_error(ndr
, NDR_ERR_COMPRESSION
,
908 "zlib inflateinit2 error %s (%d) %s (PUSH)",
909 zError(z_ret
), z_ret
, s
->alg
.mszip
.z
->msg
);
913 return ndr_push_error(ndr
, NDR_ERR_COMPRESSION
,
914 "Bad compression algorithm %d (PUSH)",
921 return NDR_ERR_SUCCESS
;
924 void ndr_push_compression_state_free(struct ndr_compression_state
*state
)
930 switch (state
->type
) {
931 case NDR_COMPRESSION_MSZIP
:
932 case NDR_COMPRESSION_XPRESS
:
934 case NDR_COMPRESSION_MSZIP_CAB
:
935 generic_mszip_free(state
);