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 "../lib/compression/lzxpress_huffman.h"
26 #include "librpc/ndr/libndr.h"
27 #include "../librpc/ndr/ndr_compression.h"
30 struct ndr_compression_state
{
31 enum ndr_compression_alg type
;
39 struct lzxhuff_compressor_mem
*mem
;
44 static voidpf
ndr_zlib_alloc(voidpf opaque
, uInt items
, uInt size
)
46 return talloc_zero_size(opaque
, items
* size
);
49 static void ndr_zlib_free(voidpf opaque
, voidpf address
)
54 static enum ndr_err_code
ndr_pull_compression_mszip_cab_chunk(struct ndr_pull
*ndrpull
,
55 struct ndr_push
*ndrpush
,
56 struct ndr_compression_state
*state
,
57 ssize_t decompressed_len
,
58 ssize_t compressed_len
)
61 uint32_t comp_chunk_offset
;
62 uint32_t comp_chunk_size
;
63 DATA_BLOB plain_chunk
;
64 uint32_t plain_chunk_offset
;
65 uint32_t plain_chunk_size
;
66 z_stream
*z
= state
->alg
.mszip
.z
;
69 plain_chunk_size
= decompressed_len
;
71 if (plain_chunk_size
> 0x00008000) {
72 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
73 "Bad MSZIP CAB plain chunk size %08"PRIX32
" > 0x00008000 (PULL)",
78 comp_chunk_size
= compressed_len
;
80 DEBUG(9,("MSZIP CAB plain_chunk_size: %08"PRIX32
" (%"PRIu32
") comp_chunk_size: %08"PRIX32
" (%"PRIu32
")\n",
81 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
83 comp_chunk_offset
= ndrpull
->offset
;
84 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
85 comp_chunk
.length
= comp_chunk_size
;
86 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
88 plain_chunk_offset
= ndrpush
->offset
;
89 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
90 plain_chunk
.length
= plain_chunk_size
;
91 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
93 if (comp_chunk
.length
< 2) {
94 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
95 "Bad MSZIP CAB comp chunk size %zu < 2 (PULL)",
98 /* CK = Chris Kirmse, official Microsoft purloiner */
99 if (comp_chunk
.data
[0] != 'C' ||
100 comp_chunk
.data
[1] != 'K') {
101 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
102 "Bad MSZIP CAB invalid prefix [%c%c] != [CK]",
103 comp_chunk
.data
[0], comp_chunk
.data
[1]);
107 * This is a MSZIP block. It is actually using the deflate
108 * algorithm which can be decompressed by zlib. zlib will try
109 * to decompress as much as it can in each run. If we provide
110 * all the input and enough room for the uncompressed output,
111 * one call is enough. It will loop over all the sub-blocks
112 * that make up a deflate block.
114 * See corresponding push function for more info.
117 z
->next_in
= comp_chunk
.data
+ 2;
118 z
->avail_in
= comp_chunk
.length
- 2;
119 z
->next_out
= plain_chunk
.data
;
120 z
->avail_out
= plain_chunk
.length
;
123 * Each MSZIP CDATA contains a complete deflate stream
124 * i.e. the stream starts and ends in the CFDATA but the
125 * _dictionary_ is shared between all CFDATA of a CFFOLDER.
127 * When decompressing, the initial dictionary of the first
128 * CDATA is empty. All other CFDATA use the previous CFDATA
129 * uncompressed output as dictionary.
132 if (state
->alg
.mszip
.dict_size
) {
133 z_ret
= inflateSetDictionary(z
, state
->alg
.mszip
.dict
, state
->alg
.mszip
.dict_size
);
135 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
136 "zlib inflateSetDictionary error %s (%d) %s (PULL)",
137 zError(z_ret
), z_ret
, z
->msg
);
141 z_ret
= inflate(z
, Z_FINISH
);
144 * Z_OK here means there was no error but the stream
145 * hasn't been fully decompressed because there was
146 * not enough room for the output, which should not
149 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
150 "zlib inflate error not enough space for output (PULL)");
152 if (z_ret
!= Z_STREAM_END
) {
153 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
154 "zlib inflate error %s (%d) %s (PULL)", zError(z_ret
), z_ret
, z
->msg
);
157 if (z
->total_out
< plain_chunk
.length
) {
158 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
159 "zlib uncompressed output is smaller than expected (%lu < %zu) (PULL)",
160 z
->total_out
, plain_chunk
.length
);
164 * Keep a copy of the output to set as dictionary for the
165 * next decompression call.
167 * The input pointer seems to be still valid between calls, so
168 * we can just store that instead of copying the memory over
169 * the dict temp buffer.
171 state
->alg
.mszip
.dict
= plain_chunk
.data
;
172 state
->alg
.mszip
.dict_size
= plain_chunk
.length
;
174 z_ret
= inflateReset(z
);
176 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
177 "zlib inflateReset error %s (%d) %s (PULL)",
178 zError(z_ret
), z_ret
, z
->msg
);
181 return NDR_ERR_SUCCESS
;
184 static enum ndr_err_code
ndr_push_compression_mszip_cab_chunk(struct ndr_push
*ndrpush
,
185 struct ndr_pull
*ndrpull
,
186 struct ndr_compression_state
*state
)
188 DATA_BLOB comp_chunk
;
189 uint32_t comp_chunk_size
;
190 DATA_BLOB plain_chunk
;
191 uint32_t plain_chunk_size
;
192 uint32_t plain_chunk_offset
;
193 uint32_t max_plain_size
= 0x00008000;
195 * The maximum compressed size of each MSZIP block is 32k + 12 bytes
198 uint32_t max_comp_size
= 0x00008000 + 12;
202 if (ndrpull
->data_size
<= ndrpull
->offset
) {
203 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
204 "strange NDR pull size and offset (integer overflow?)");
208 plain_chunk_size
= MIN(max_plain_size
, ndrpull
->data_size
- ndrpull
->offset
);
209 plain_chunk_offset
= ndrpull
->offset
;
210 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
212 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
213 plain_chunk
.length
= plain_chunk_size
;
215 NDR_CHECK(ndr_push_expand(ndrpush
, max_comp_size
));
217 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
218 comp_chunk
.length
= max_comp_size
;
220 /* CK = Chris Kirmse, official Microsoft purloiner */
221 comp_chunk
.data
[0] = 'C';
222 comp_chunk
.data
[1] = 'K';
224 z
= state
->alg
.mszip
.z
;
225 z
->next_in
= plain_chunk
.data
;
226 z
->avail_in
= plain_chunk
.length
;
229 z
->next_out
= comp_chunk
.data
+ 2;
230 z
->avail_out
= comp_chunk
.length
;
234 * See pull function for explanations of the MSZIP format.
236 * The CFDATA block contains a full deflate stream. Each stream
237 * uses the uncompressed input of the previous CFDATA in the
238 * same CFFOLDER as a dictionary for the compression.
241 if (state
->alg
.mszip
.dict_size
) {
242 z_ret
= deflateSetDictionary(z
, state
->alg
.mszip
.dict
, state
->alg
.mszip
.dict_size
);
244 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
245 "zlib deflateSetDictionary error %s (%d) %s (PUSH)",
246 zError(z_ret
), z_ret
, z
->msg
);
251 * Z_FINISH should make deflate process all of the input in
252 * one call. If the stream is not finished there was an error
253 * e.g. not enough room to store the compressed output.
255 z_ret
= deflate(z
, Z_FINISH
);
256 if (z_ret
!= Z_STREAM_END
) {
257 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
258 "zlib deflate error %s (%d) %s (PUSH)",
259 zError(z_ret
), z_ret
, z
->msg
);
263 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
264 "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
268 comp_chunk_size
= 2 + z
->total_out
;
269 if (comp_chunk_size
< z
->total_out
) {
270 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
271 "strange NDR push compressed size (integer overflow?)");
274 z_ret
= deflateReset(z
);
276 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
277 "zlib deflateReset error %s (%d) %s (PUSH)",
278 zError(z_ret
), z_ret
, z
->msg
);
281 if (plain_chunk
.length
> talloc_array_length(state
->alg
.mszip
.dict
)) {
282 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
283 "zlib dict buffer is too big (PUSH)");
287 * Keep a copy of the input to set as dictionary for the next
290 * Ideally we would just store the input pointer and length
291 * without copying but the memory gets invalidated between the
292 * calls, so we just copy to a dedicated buffer we know is
293 * still going to be valid for the lifetime of the
294 * compressions state object.
296 memcpy(state
->alg
.mszip
.dict
, plain_chunk
.data
, plain_chunk
.length
);
297 state
->alg
.mszip
.dict_size
= plain_chunk
.length
;
299 DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32
" (%"PRIu32
")\n",
302 comp_chunk_size
, comp_chunk_size
));
304 ndrpush
->offset
+= comp_chunk_size
;
305 return NDR_ERR_SUCCESS
;
309 static enum ndr_err_code
ndr_pull_compression_mszip_chunk(struct ndr_pull
*ndrpull
,
310 struct ndr_push
*ndrpush
,
314 DATA_BLOB comp_chunk
;
315 uint32_t comp_chunk_offset
;
316 uint32_t comp_chunk_size
;
317 DATA_BLOB plain_chunk
;
318 uint32_t plain_chunk_offset
;
319 uint32_t plain_chunk_size
;
322 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &plain_chunk_size
));
323 if (plain_chunk_size
> 0x00008000) {
324 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
, "Bad MSZIP plain chunk size %08"PRIX32
" > 0x00008000 (PULL)",
328 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &comp_chunk_size
));
330 DEBUG(9,("MSZIP plain_chunk_size: %08"PRIX32
" (%"PRIu32
") comp_chunk_size: %08"PRIX32
" (%"PRIu32
")\n",
331 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
333 comp_chunk_offset
= ndrpull
->offset
;
334 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
335 comp_chunk
.length
= comp_chunk_size
;
336 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
338 plain_chunk_offset
= ndrpush
->offset
;
339 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
340 plain_chunk
.length
= plain_chunk_size
;
341 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
343 if (comp_chunk
.length
< 2) {
344 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
345 "Bad MSZIP comp chunk size %zu < 2 (PULL)",
348 /* CK = Chris Kirmse, official Microsoft purloiner */
349 if (comp_chunk
.data
[0] != 'C' ||
350 comp_chunk
.data
[1] != 'K') {
351 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
352 "Bad MSZIP invalid prefix [%c%c] != [CK]",
353 comp_chunk
.data
[0], comp_chunk
.data
[1]);
356 z
->next_in
= comp_chunk
.data
+ 2;
357 z
->avail_in
= comp_chunk
.length
-2;
360 z
->next_out
= plain_chunk
.data
;
361 z
->avail_out
= plain_chunk
.length
;
365 /* the first time we need to initialize completely */
366 z
->zalloc
= ndr_zlib_alloc
;
367 z
->zfree
= ndr_zlib_free
;
370 z_ret
= inflateInit2(z
, -MAX_WBITS
);
372 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
373 "Bad inflateInit2 error %s(%d) (PULL)",
374 zError(z_ret
), z_ret
);
379 /* call inflate until we get Z_STREAM_END or an error */
381 z_ret
= inflate(z
, Z_BLOCK
);
382 if (z_ret
!= Z_OK
) break;
385 if (z_ret
!= Z_STREAM_END
) {
386 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
387 "Bad inflate(Z_BLOCK) error %s(%d) (PULL)",
388 zError(z_ret
), z_ret
);
392 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
393 "MSZIP not all avail_in[%u] bytes consumed (PULL)",
398 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
399 "MSZIP not all avail_out[%u] bytes consumed (PULL)",
403 if ((plain_chunk_size
< 0x00008000) || (ndrpull
->offset
+4 >= ndrpull
->data_size
)) {
404 /* this is the last chunk */
408 z_ret
= inflateReset(z
);
410 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
411 "Bad inflateReset error %s(%d) (PULL)",
412 zError(z_ret
), z_ret
);
415 z_ret
= inflateSetDictionary(z
, plain_chunk
.data
, plain_chunk
.length
);
417 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
418 "Bad inflateSetDictionary error %s(%d) (PULL)",
419 zError(z_ret
), z_ret
);
422 return NDR_ERR_SUCCESS
;
425 static enum ndr_err_code
ndr_push_compression_mszip_chunk(struct ndr_push
*ndrpush
,
426 struct ndr_pull
*ndrpull
,
430 DATA_BLOB comp_chunk
;
431 uint32_t comp_chunk_size
;
432 uint32_t comp_chunk_size_offset
;
433 DATA_BLOB plain_chunk
;
434 uint32_t plain_chunk_size
;
435 uint32_t plain_chunk_offset
;
436 uint32_t max_plain_size
= 0x00008000;
438 * The maximum compressed size of each MSZIP block is 32k + 12 bytes
441 uint32_t max_comp_size
= 0x00008000 + 12;
445 plain_chunk_size
= MIN(max_plain_size
, ndrpull
->data_size
- ndrpull
->offset
);
446 plain_chunk_offset
= ndrpull
->offset
;
447 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
449 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
450 plain_chunk
.length
= plain_chunk_size
;
452 if (plain_chunk_size
< max_plain_size
) {
456 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, plain_chunk_size
));
457 comp_chunk_size_offset
= ndrpush
->offset
;
458 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, 0xFEFEFEFE));
460 NDR_CHECK(ndr_push_expand(ndrpush
, max_comp_size
));
462 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
463 comp_chunk
.length
= max_comp_size
;
465 /* CK = Chris Kirmse, official Microsoft purloiner */
466 comp_chunk
.data
[0] = 'C';
467 comp_chunk
.data
[1] = 'K';
469 z
->next_in
= plain_chunk
.data
;
470 z
->avail_in
= plain_chunk
.length
;
473 z
->next_out
= comp_chunk
.data
+ 2;
474 z
->avail_out
= comp_chunk
.length
;
478 /* the first time we need to initialize completely */
479 z
->zalloc
= ndr_zlib_alloc
;
480 z
->zfree
= ndr_zlib_free
;
483 /* TODO: find how to trigger the same parameters windows uses */
484 z_ret
= deflateInit2(z
,
485 Z_DEFAULT_COMPRESSION
,
491 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
492 "Bad deflateInit2 error %s(%d) (PUSH)",
493 zError(z_ret
), z_ret
);
498 /* call deflate until we get Z_STREAM_END or an error */
500 z_ret
= deflate(z
, Z_FINISH
);
501 if (z_ret
!= Z_OK
) break;
503 if (z_ret
!= Z_STREAM_END
) {
504 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
505 "Bad deflate(Z_BLOCK) error %s(%d) (PUSH)",
506 zError(z_ret
), z_ret
);
510 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
511 "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
515 comp_chunk_size
= 2 + z
->total_out
;
517 z_ret
= deflateReset(z
);
519 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
520 "Bad deflateReset error %s(%d) (PULL)",
521 zError(z_ret
), z_ret
);
524 z_ret
= deflateSetDictionary(z
, plain_chunk
.data
, plain_chunk
.length
);
526 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
527 "Bad deflateSetDictionary error %s(%d) (PULL)",
528 zError(z_ret
), z_ret
);
531 tmp_offset
= ndrpush
->offset
;
532 ndrpush
->offset
= comp_chunk_size_offset
;
533 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, comp_chunk_size
));
534 ndrpush
->offset
= tmp_offset
;
536 DEBUG(9,("MSZIP comp plain_chunk_size: %08zX (%zu) comp_chunk_size: %08"PRIX32
" (%"PRIu32
")\n",
539 comp_chunk_size
, comp_chunk_size
));
541 ndrpush
->offset
+= comp_chunk_size
;
542 return NDR_ERR_SUCCESS
;
545 static enum ndr_err_code
ndr_pull_compression_xpress_chunk(struct ndr_pull
*ndrpull
,
546 struct ndr_push
*ndrpush
,
549 DATA_BLOB comp_chunk
;
550 DATA_BLOB plain_chunk
;
551 uint32_t comp_chunk_offset
;
552 uint32_t plain_chunk_offset
;
553 uint32_t comp_chunk_size
;
554 uint32_t plain_chunk_size
;
557 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &plain_chunk_size
));
558 if (plain_chunk_size
> 0x00010000) {
559 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
, "Bad XPRESS plain chunk size %08"PRIX32
" > 0x00010000 (PULL)",
563 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &comp_chunk_size
));
565 comp_chunk_offset
= ndrpull
->offset
;
566 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
567 comp_chunk
.length
= comp_chunk_size
;
568 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
570 plain_chunk_offset
= ndrpush
->offset
;
571 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
572 plain_chunk
.length
= plain_chunk_size
;
573 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
575 DEBUG(9,("XPRESS plain_chunk_size: %08"PRIX32
" (%"PRIu32
") comp_chunk_size: %08"PRIX32
" (%"PRIu32
")\n",
576 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
578 /* Uncompressing the buffer using LZ Xpress algorithm */
579 ret
= lzxpress_decompress(comp_chunk
.data
,
584 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
585 "XPRESS lzxpress_decompress() returned %zd\n",
588 plain_chunk
.length
= ret
;
590 if ((plain_chunk_size
< 0x00010000) || (ndrpull
->offset
+4 >= ndrpull
->data_size
)) {
591 /* this is the last chunk */
595 return NDR_ERR_SUCCESS
;
598 static enum ndr_err_code
ndr_push_compression_xpress_chunk(struct ndr_push
*ndrpush
,
599 struct ndr_pull
*ndrpull
,
602 DATA_BLOB comp_chunk
;
603 uint32_t comp_chunk_size_offset
;
604 DATA_BLOB plain_chunk
;
605 uint32_t plain_chunk_size
;
606 uint32_t plain_chunk_offset
;
607 uint32_t max_plain_size
= 0x00010000;
608 uint32_t max_comp_size
= 0x00020000 + 2; /* TODO: use the correct value here */
612 plain_chunk_size
= MIN(max_plain_size
, ndrpull
->data_size
- ndrpull
->offset
);
613 plain_chunk_offset
= ndrpull
->offset
;
614 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
616 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
617 plain_chunk
.length
= plain_chunk_size
;
619 if (plain_chunk_size
< max_plain_size
) {
623 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, plain_chunk_size
));
624 comp_chunk_size_offset
= ndrpush
->offset
;
625 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, 0xFEFEFEFE));
627 NDR_CHECK(ndr_push_expand(ndrpush
, max_comp_size
));
629 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
630 comp_chunk
.length
= max_comp_size
;
632 /* Compressing the buffer using LZ Xpress algorithm */
633 ret
= lzxpress_compress(plain_chunk
.data
,
638 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
639 "XPRESS lzxpress_compress() returned %zd\n",
642 comp_chunk
.length
= ret
;
644 tmp_offset
= ndrpush
->offset
;
645 ndrpush
->offset
= comp_chunk_size_offset
;
646 NDR_CHECK(ndr_push_uint32(ndrpush
, NDR_SCALARS
, comp_chunk
.length
));
647 ndrpush
->offset
= tmp_offset
;
649 ndrpush
->offset
+= comp_chunk
.length
;
650 return NDR_ERR_SUCCESS
;
653 static enum ndr_err_code
ndr_pull_compression_none(struct ndr_pull
*ndrpull
,
654 struct ndr_push
*ndrpush
,
655 ssize_t decompressed_len
,
656 ssize_t compressed_len
)
658 DATA_BLOB comp_chunk
;
659 uint32_t comp_chunk_size
= compressed_len
;
660 uint32_t comp_chunk_offset
;
662 if (decompressed_len
!= compressed_len
) {
663 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
664 "decompressed len %zd != compressed_len %zd in 'NONE' compression!",
669 if (comp_chunk_size
!= compressed_len
) {
670 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
671 "compressed_len %zd overflows uint32_t in 'NONE' compression!",
675 comp_chunk_offset
= ndrpull
->offset
;
676 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
677 comp_chunk
.length
= comp_chunk_size
;
678 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
680 NDR_CHECK(ndr_push_array_uint8(ndrpush
,
685 return NDR_ERR_SUCCESS
;
688 static enum ndr_err_code
ndr_push_compression_none(struct ndr_push
*ndrpush
,
689 struct ndr_pull
*ndrpull
)
691 DATA_BLOB plain_chunk
;
692 uint32_t plain_chunk_size
;
693 uint32_t plain_chunk_offset
;
695 plain_chunk_size
= ndrpull
->data_size
- ndrpull
->offset
;
696 plain_chunk_offset
= ndrpull
->offset
;
697 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
699 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
700 plain_chunk
.length
= plain_chunk_size
;
702 NDR_CHECK(ndr_push_array_uint8(ndrpush
,
705 plain_chunk
.length
));
706 return NDR_ERR_SUCCESS
;
709 static enum ndr_err_code
ndr_pull_compression_xpress_huff_raw_chunk(struct ndr_pull
*ndrpull
,
710 struct ndr_push
*ndrpush
,
711 ssize_t decompressed_len
,
712 ssize_t compressed_len
)
714 DATA_BLOB comp_chunk
;
715 uint32_t comp_chunk_offset
;
716 uint32_t comp_chunk_size
;
717 DATA_BLOB plain_chunk
;
718 uint32_t plain_chunk_offset
;
719 uint32_t plain_chunk_size
;
722 plain_chunk_size
= decompressed_len
;
723 comp_chunk_size
= compressed_len
;
725 DEBUG(9,("XPRESS_HUFF plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u)\n",
726 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
));
728 comp_chunk_offset
= ndrpull
->offset
;
729 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
730 comp_chunk
.length
= comp_chunk_size
;
731 comp_chunk
.data
= ndrpull
->data
+ comp_chunk_offset
;
733 plain_chunk_offset
= ndrpush
->offset
;
734 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
735 plain_chunk
.length
= plain_chunk_size
;
736 plain_chunk
.data
= ndrpush
->data
+ plain_chunk_offset
;
738 /* Decompressing the buffer using LZ Xpress w/ Huffman algorithm */
739 ret
= lzxpress_huffman_decompress(comp_chunk
.data
,
744 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
745 "XPRESS HUFF lzxpress_huffman_decompress() returned %zd\n",
749 if (plain_chunk
.length
!= ret
) {
750 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
751 "XPRESS HUFF lzxpress_huffman_decompress() output is not as expected (%zd != %zu) (PULL)",
752 ret
, plain_chunk
.length
);
755 return NDR_ERR_SUCCESS
;
758 static enum ndr_err_code
ndr_push_compression_xpress_huff_raw_chunk(struct ndr_push
*ndrpush
,
759 struct ndr_pull
*ndrpull
,
760 struct ndr_compression_state
*state
)
762 DATA_BLOB comp_chunk
;
763 DATA_BLOB plain_chunk
;
764 uint32_t plain_chunk_size
;
765 uint32_t plain_chunk_offset
;
768 struct lzxhuff_compressor_mem
*mem
= state
->alg
.lzxpress_huffman
.mem
;
770 if (ndrpull
->data_size
<= ndrpull
->offset
) {
771 return ndr_push_error(ndrpush
, NDR_ERR_COMPRESSION
,
772 "strange NDR pull size and offset (integer overflow?)");
776 plain_chunk_size
= ndrpull
->data_size
- ndrpull
->offset
;
777 plain_chunk_offset
= ndrpull
->offset
;
778 NDR_CHECK(ndr_pull_advance(ndrpull
, plain_chunk_size
));
780 plain_chunk
.data
= ndrpull
->data
+ plain_chunk_offset
;
781 plain_chunk
.length
= plain_chunk_size
;
783 comp_chunk
.length
= lzxpress_huffman_max_compressed_size(plain_chunk_size
);
784 NDR_CHECK(ndr_push_expand(ndrpush
, comp_chunk
.length
));
786 comp_chunk
.data
= ndrpush
->data
+ ndrpush
->offset
;
789 /* Compressing the buffer using LZ Xpress w/ Huffman algorithm */
790 ret
= lzxpress_huffman_compress(mem
,
796 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
797 "XPRESS HUFF lzxpress_huffman_compress() returned %zd\n",
801 if (ret
> comp_chunk
.length
) {
802 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
,
803 "XPRESS HUFF lzxpress_huffman_compress() output is not as expected (%zd > %zu) (PULL)",
804 ret
, comp_chunk
.length
);
807 ndrpush
->offset
+= ret
;
808 return NDR_ERR_SUCCESS
;
813 handle compressed subcontext buffers, which in midl land are user-marshalled, but
814 we use magic in pidl to make them easier to cope with
816 enum ndr_err_code
ndr_pull_compression_start(struct ndr_pull
*subndr
,
817 struct ndr_pull
**_comndr
,
818 enum ndr_compression_alg compression_alg
,
819 ssize_t decompressed_len
,
820 ssize_t compressed_len
)
822 struct ndr_push
*ndrpush
;
823 struct ndr_pull
*comndr
;
824 DATA_BLOB uncompressed
;
828 ndrpush
= ndr_push_init_ctx(subndr
);
829 NDR_ERR_HAVE_NO_MEMORY(ndrpush
);
831 switch (compression_alg
) {
832 case NDR_COMPRESSION_NONE
:
833 NDR_CHECK(ndr_pull_compression_none(subndr
, ndrpush
,
837 case NDR_COMPRESSION_MSZIP_CAB
:
838 NDR_CHECK(ndr_pull_compression_mszip_cab_chunk(subndr
, ndrpush
,
843 case NDR_COMPRESSION_MSZIP
:
846 NDR_CHECK(ndr_pull_compression_mszip_chunk(subndr
, ndrpush
, &z
, &last
));
850 case NDR_COMPRESSION_XPRESS
:
852 NDR_CHECK(ndr_pull_compression_xpress_chunk(subndr
, ndrpush
, &last
));
856 case NDR_COMPRESSION_XPRESS_HUFF_RAW
:
857 NDR_CHECK(ndr_pull_compression_xpress_huff_raw_chunk(subndr
, ndrpush
,
863 return ndr_pull_error(subndr
, NDR_ERR_COMPRESSION
, "Bad compression algorithm %d (PULL)",
867 uncompressed
= ndr_push_blob(ndrpush
);
868 if (uncompressed
.length
!= decompressed_len
) {
869 return ndr_pull_error(subndr
, NDR_ERR_COMPRESSION
,
870 "Bad uncompressed_len [%zu] != [%zd](0x%08zX) (PULL)",
876 comndr
= talloc_zero(subndr
, struct ndr_pull
);
877 NDR_ERR_HAVE_NO_MEMORY(comndr
);
878 comndr
->flags
= subndr
->flags
;
879 comndr
->current_mem_ctx
= subndr
->current_mem_ctx
;
881 comndr
->data
= uncompressed
.data
;
882 comndr
->data_size
= uncompressed
.length
;
886 return NDR_ERR_SUCCESS
;
889 enum ndr_err_code
ndr_pull_compression_end(struct ndr_pull
*subndr
,
890 struct ndr_pull
*comndr
,
891 enum ndr_compression_alg compression_alg
,
892 ssize_t decompressed_len
)
894 return NDR_ERR_SUCCESS
;
898 push a compressed subcontext
900 enum ndr_err_code
ndr_push_compression_start(struct ndr_push
*subndr
,
901 struct ndr_push
**_uncomndr
)
903 struct ndr_push
*uncomndr
;
904 enum ndr_compression_alg compression_alg
= subndr
->cstate
->type
;
906 switch (compression_alg
) {
907 case NDR_COMPRESSION_NONE
:
908 case NDR_COMPRESSION_MSZIP_CAB
:
909 case NDR_COMPRESSION_MSZIP
:
910 case NDR_COMPRESSION_XPRESS
:
911 case NDR_COMPRESSION_XPRESS_HUFF_RAW
:
914 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
,
915 "Bad compression algorithm %d (PUSH)",
919 uncomndr
= ndr_push_init_ctx(subndr
);
920 NDR_ERR_HAVE_NO_MEMORY(uncomndr
);
921 uncomndr
->flags
= subndr
->flags
;
923 *_uncomndr
= uncomndr
;
924 return NDR_ERR_SUCCESS
;
928 push a compressed subcontext
930 enum ndr_err_code
ndr_push_compression_end(struct ndr_push
*subndr
,
931 struct ndr_push
*uncomndr
)
933 struct ndr_pull
*ndrpull
;
937 enum ndr_compression_alg compression_alg
= subndr
->cstate
->type
;
939 ndrpull
= talloc_zero(uncomndr
, struct ndr_pull
);
940 NDR_ERR_HAVE_NO_MEMORY(ndrpull
);
941 ndrpull
->flags
= uncomndr
->flags
;
942 ndrpull
->data
= uncomndr
->data
;
943 ndrpull
->data_size
= uncomndr
->offset
;
946 switch (compression_alg
) {
947 case NDR_COMPRESSION_NONE
:
948 NDR_CHECK(ndr_push_compression_none(subndr
, ndrpull
));
951 case NDR_COMPRESSION_MSZIP_CAB
:
952 NDR_CHECK(ndr_push_compression_mszip_cab_chunk(subndr
, ndrpull
, subndr
->cstate
));
955 case NDR_COMPRESSION_MSZIP
:
958 NDR_CHECK(ndr_push_compression_mszip_chunk(subndr
, ndrpull
, &z
, &last
));
962 case NDR_COMPRESSION_XPRESS
:
964 NDR_CHECK(ndr_push_compression_xpress_chunk(subndr
, ndrpull
, &last
));
968 case NDR_COMPRESSION_XPRESS_HUFF_RAW
:
969 NDR_CHECK(ndr_push_compression_xpress_huff_raw_chunk(subndr
, ndrpull
, subndr
->cstate
));
973 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
, "Bad compression algorithm %d (PUSH)",
977 talloc_free(uncomndr
);
978 return NDR_ERR_SUCCESS
;
981 static enum ndr_err_code
generic_mszip_init(struct ndr_compression_state
*state
)
983 z_stream
*z
= talloc_zero(state
, z_stream
);
984 NDR_ERR_HAVE_NO_MEMORY(z
);
986 z
->zalloc
= ndr_zlib_alloc
;
987 z
->zfree
= ndr_zlib_free
;
990 state
->alg
.mszip
.z
= z
;
991 state
->alg
.mszip
.dict_size
= 0;
992 /* pre-alloc dictionary */
993 state
->alg
.mszip
.dict
= talloc_array(state
, uint8_t, 0x8000);
994 NDR_ERR_HAVE_NO_MEMORY(state
->alg
.mszip
.dict
);
996 return NDR_ERR_SUCCESS
;
999 enum ndr_err_code
ndr_pull_compression_state_init(struct ndr_pull
*ndr
,
1000 enum ndr_compression_alg compression_alg
,
1001 struct ndr_compression_state
**state
)
1003 struct ndr_compression_state
*s
;
1006 s
= talloc_zero(ndr
, struct ndr_compression_state
);
1007 NDR_ERR_HAVE_NO_MEMORY(s
);
1008 s
->type
= compression_alg
;
1010 switch (compression_alg
) {
1011 case NDR_COMPRESSION_NONE
:
1012 case NDR_COMPRESSION_MSZIP
:
1013 case NDR_COMPRESSION_XPRESS
:
1014 case NDR_COMPRESSION_XPRESS_HUFF_RAW
:
1016 case NDR_COMPRESSION_MSZIP_CAB
:
1017 NDR_CHECK(generic_mszip_init(s
));
1018 z_ret
= inflateInit2(s
->alg
.mszip
.z
, -MAX_WBITS
);
1019 if (z_ret
!= Z_OK
) {
1020 return ndr_pull_error(ndr
, NDR_ERR_COMPRESSION
,
1021 "zlib inflateinit2 error %s (%d) %s (PULL)",
1022 zError(z_ret
), z_ret
, s
->alg
.mszip
.z
->msg
);
1026 return ndr_pull_error(ndr
, NDR_ERR_COMPRESSION
,
1027 "Bad compression algorithm %d (PULL)",
1034 return NDR_ERR_SUCCESS
;
1037 enum ndr_err_code
ndr_push_compression_state_init(struct ndr_push
*ndr
,
1038 enum ndr_compression_alg compression_alg
)
1040 struct ndr_compression_state
*s
;
1044 * Avoid confusion, NULL out ndr->cstate at the start of the
1049 s
= talloc_zero(ndr
, struct ndr_compression_state
);
1050 NDR_ERR_HAVE_NO_MEMORY(s
);
1051 s
->type
= compression_alg
;
1053 switch (compression_alg
) {
1054 case NDR_COMPRESSION_NONE
:
1055 case NDR_COMPRESSION_XPRESS
:
1058 case NDR_COMPRESSION_XPRESS_HUFF_RAW
:
1059 s
->alg
.lzxpress_huffman
.mem
= talloc(s
, struct lzxhuff_compressor_mem
);
1060 if (s
->alg
.lzxpress_huffman
.mem
== NULL
) {
1061 return NDR_ERR_ALLOC
;
1065 case NDR_COMPRESSION_MSZIP
:
1067 case NDR_COMPRESSION_MSZIP_CAB
:
1068 NDR_CHECK(generic_mszip_init(s
));
1069 z_ret
= deflateInit2(s
->alg
.mszip
.z
,
1070 Z_DEFAULT_COMPRESSION
,
1074 Z_DEFAULT_STRATEGY
);
1075 if (z_ret
!= Z_OK
) {
1076 return ndr_push_error(ndr
, NDR_ERR_COMPRESSION
,
1077 "zlib inflateinit2 error %s (%d) %s (PUSH)",
1078 zError(z_ret
), z_ret
, s
->alg
.mszip
.z
->msg
);
1082 return ndr_push_error(ndr
, NDR_ERR_COMPRESSION
,
1083 "Bad compression algorithm %d (PUSH)",
1090 return NDR_ERR_SUCCESS
;