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 2 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, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 static NTSTATUS
ndr_pull_compression_zlib_chunk(struct ndr_pull
*ndrpull
,
29 struct ndr_push
*ndrpush
,
30 struct z_stream_s
*zs
, int i
)
33 uint32_t comp_chunk_offset
;
34 uint32_t comp_chunk_size
;
36 uint32_t plain_chunk_offset
;
37 uint32_t plain_chunk_size
;
38 uint16_t unknown_marker
;
41 /* I don't know why, this is needed... --metze */
42 if (i
== 5) ndrpull
->offset
-=4;
44 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &plain_chunk_size
));
45 if (plain_chunk_size
> 0x00008000) {
46 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
, "Bad ZLIB plain chunk size %08X > 0x00008000 (PULL)",
50 NDR_CHECK(ndr_pull_uint32(ndrpull
, NDR_SCALARS
, &comp_chunk_size
));
52 NDR_CHECK(ndr_pull_uint16(ndrpull
, NDR_SCALARS
, &unknown_marker
));
54 DEBUG(10,("plain_chunk_size: %08X (%u) comp_chunk_size: %08X (%u) unknown_marker: %04X (%u)\n",
55 plain_chunk_size
, plain_chunk_size
, comp_chunk_size
, comp_chunk_size
, unknown_marker
, unknown_marker
));
57 comp_chunk_offset
= ndrpull
->offset
;
58 NDR_CHECK(ndr_pull_advance(ndrpull
, comp_chunk_size
));
59 comp_chunk
= ndrpull
->data
+ comp_chunk_offset
;
61 plain_chunk_offset
= ndrpush
->offset
;
62 NDR_CHECK(ndr_push_zero(ndrpush
, plain_chunk_size
));
63 plain_chunk
= ndrpush
->data
+ plain_chunk_offset
;
65 zs
->avail_in
= comp_chunk_size
;
66 zs
->next_in
= comp_chunk
;
67 zs
->next_out
= plain_chunk
;
68 zs
->avail_out
= plain_chunk_size
;
71 ret
= inflate(zs
, Z_BLOCK
);
72 if (ret
== Z_STREAM_END
) {
73 DEBUG(0,("comp_chunk_size: %u avail_in: %d, plain_chunk_size: %u, avail_out: %d\n",
74 comp_chunk_size
, zs
->avail_in
, plain_chunk_size
, zs
->avail_out
));
78 return ndr_pull_error(ndrpull
, NDR_ERR_COMPRESSION
, "Bad ZLIB (PULL) inflate error %d",
83 if ((plain_chunk_size
< 0x00008000) || (ndrpull
->offset
+4 >= ndrpull
->data_size
)) {
84 /* this is the last chunk */
88 return NT_STATUS_MORE_PROCESSING_REQUIRED
;
91 static NTSTATUS
ndr_pull_compression_zlib(struct ndr_pull
*subndr
,
92 struct ndr_pull
*comndr
,
93 ssize_t decompressed_len
)
95 NTSTATUS status
= NT_STATUS_MORE_PROCESSING_REQUIRED
;
96 struct ndr_push
*ndrpush
;
97 DATA_BLOB uncompressed
;
104 ndrpush
= ndr_push_init_ctx(subndr
);
105 NT_STATUS_HAVE_NO_MEMORY(ndrpush
);
107 ret
= inflateInit2(&zs
, -15);
109 return ndr_pull_error(subndr
, NDR_ERR_COMPRESSION
, "Bad ZLIB (PULL) inflateInit2 error %d",
113 while (NT_STATUS_EQUAL(NT_STATUS_MORE_PROCESSING_REQUIRED
, status
)) {
114 status
= ndr_pull_compression_zlib_chunk(subndr
, ndrpush
, &zs
, i
++);
117 NT_STATUS_NOT_OK_RETURN(status
);
119 uncompressed
= ndr_push_blob(ndrpush
);
122 comndr
->data
= uncompressed
.data
;
123 comndr
->data_size
= uncompressed
.length
;
129 static NTSTATUS
ndr_push_compression_zlib(struct ndr_push
*subndr
,
130 struct ndr_push
*comndr
)
133 DATA_BLOB outbuf
= data_blob_talloc(comndr
, NULL
, comndr
->offset
+ 10);
134 struct z_stream_s zs
;
139 inbuf
= ndr_push_blob(comndr
);
141 zs
.avail_in
= inbuf
.length
;
142 zs
.next_in
= inbuf
.data
;
143 zs
.next_out
= outbuf
.data
+10;
144 zs
.avail_out
= outbuf
.length
-10;
146 ret
= deflateInit(&zs
, Z_DEFAULT_COMPRESSION
);
148 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
, "Bad ZLIB (PUSH) deflateInit2 error %d",
152 ret
= deflate(&zs
, Z_SYNC_FLUSH
);
154 if (ret
!= Z_OK
&& ret
!= Z_STREAM_END
) {
155 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
, "Bad ZLIB (PULL) deflate error %d",
161 /* TODO: push the header here */
164 NDR_CHECK(ndr_push_bytes(subndr
, outbuf
.data
, outbuf
.length
));
171 handle compressed subcontext buffers, which in midl land are user-marshalled, but
172 we use magic in pidl to make them easier to cope with
174 NTSTATUS
ndr_pull_compression(struct ndr_pull
*subndr
,
175 struct ndr_pull
*comndr
,
176 enum ndr_compression_alg compression_alg
,
177 ssize_t decompressed_len
)
179 comndr
->flags
= subndr
->flags
;
181 switch (compression_alg
) {
183 case NDR_COMPRESSION_ZLIB
:
184 return ndr_pull_compression_zlib(subndr
, comndr
, decompressed_len
);
187 return ndr_pull_error(subndr
, NDR_ERR_COMPRESSION
, "Bad compression algorithm %d (PULL)",
194 push a compressed subcontext
196 NTSTATUS
ndr_push_compression(struct ndr_push
*subndr
,
197 struct ndr_push
*comndr
,
198 enum ndr_compression_alg compression_alg
)
200 comndr
->flags
= subndr
->flags
;
202 switch (compression_alg
) {
204 case NDR_COMPRESSION_ZLIB
:
205 return ndr_push_compression_zlib(subndr
, comndr
);
208 return ndr_push_error(subndr
, NDR_ERR_COMPRESSION
, "Bad compression algorithm %d (PUSH)",