ndr_compression: implement mszip compression based on deflate()
authorStefan Metzmacher <metze@samba.org>
Wed, 20 Aug 2008 13:48:00 +0000 (15:48 +0200)
committerStefan Metzmacher <metze@samba.org>
Thu, 21 Aug 2008 10:50:43 +0000 (12:50 +0200)
The output doesn't match the output from windows servers,
but it's a start...

metze
(This used to be commit 8a2f9688275aa150b739b5525e738df15c5e25cc)

source4/librpc/ndr/ndr_compression.c

index 3b38c6b913354565f553b639875e34cc7175ed4b..37f95bb1b6067a579d4d169b583bee9bdba69460 100644 (file)
@@ -150,7 +150,104 @@ static enum ndr_err_code ndr_push_compression_mszip_chunk(struct ndr_push *ndrpu
                                                          z_stream *z,
                                                          bool *last)
 {
-       return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION, "MSZIP compression is not supported yet (PUSH)");
+       DATA_BLOB comp_chunk;
+       uint32_t comp_chunk_size;
+       uint32_t comp_chunk_size_offset;
+       DATA_BLOB plain_chunk;
+       uint32_t plain_chunk_size;
+       uint32_t plain_chunk_offset;
+       uint32_t max_plain_size = 0x00008000;
+       uint32_t max_comp_size = 0x00008000 + 2 + 12 /*TODO: what value do we really need here?*/;
+       uint32_t tmp_offset;
+       int z_ret;
+
+       plain_chunk_size = MIN(max_plain_size, ndrpull->data_size - ndrpull->offset);
+       plain_chunk_offset = ndrpull->offset;
+       NDR_CHECK(ndr_pull_advance(ndrpull, plain_chunk_size));
+
+       plain_chunk.data = ndrpull->data + plain_chunk_offset;
+       plain_chunk.length = plain_chunk_size;
+
+       if (plain_chunk_size < max_plain_size) {
+               *last = true;
+       }
+
+       NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, plain_chunk_size));
+       comp_chunk_size_offset = ndrpush->offset;
+       NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, 0xFEFEFEFE));
+
+       NDR_CHECK(ndr_push_expand(ndrpush, max_comp_size));
+
+       comp_chunk.data = ndrpush->data + ndrpush->offset;
+       comp_chunk.length = max_comp_size;
+
+       /* CK = Chris Kirmse, official Microsoft purloiner */
+       comp_chunk.data[0] = 'C';
+       comp_chunk.data[1] = 'K';
+
+       z->next_in      = plain_chunk.data;
+       z->avail_in     = plain_chunk.length;
+       z->total_in     = 0;
+
+       z->next_out     = comp_chunk.data + 2;
+       z->avail_out    = comp_chunk.length - 2;
+       z->total_out    = 0;
+
+       if (!z->opaque) {
+               /* the first time we need to intialize completely */
+               z->zalloc       = ndr_zlib_alloc;
+               z->zfree        = ndr_zlib_free;
+               z->opaque       = ndrpull;
+
+               /* TODO: find how to trigger the same parameters windows uses */
+               z_ret = deflateInit2(z,
+                                    Z_DEFAULT_COMPRESSION,
+                                    Z_DEFLATED,
+                                    -15,
+                                    9,
+                                    Z_DEFAULT_STRATEGY);
+               if (z_ret != Z_OK) {
+                       return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+                                             "Bad deflateInit2 error %s(%d) (PUSH)",
+                                             zError(z_ret), z_ret);
+
+               }
+       } else {
+               /* TODO: keep the window */
+               z_ret = deflateReset(z);
+               if (z_ret != Z_OK) {
+                       return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+                                             "Bad delateReset2 error %s(%d) (PUSH)",
+                                             zError(z_ret), z_ret);
+               }
+       }
+
+       /* call deflate untill we get Z_STREAM_END or an error */
+       while (true) {
+               z_ret = deflate(z, Z_FINISH);
+               if (z_ret != Z_OK) break;
+       }
+       if (z_ret != Z_STREAM_END) {
+               return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+                                     "Bad delate(Z_BLOCK) error %s(%d) (PUSH)",
+                                     zError(z_ret), z_ret);
+       }
+
+       if (z->avail_in) {
+               return ndr_push_error(ndrpush, NDR_ERR_COMPRESSION,
+                                     "MSZIP not all avail_in[%u] bytes consumed (PUSH)",
+                                     z->avail_in);
+       }
+
+       comp_chunk_size = 2 + z->total_out;
+
+       tmp_offset = ndrpush->offset;
+       ndrpush->offset = comp_chunk_size_offset;
+       NDR_CHECK(ndr_push_uint32(ndrpush, NDR_SCALARS, comp_chunk_size));
+       ndrpush->offset = tmp_offset;
+
+       ndrpush->offset += comp_chunk_size;
+       return NDR_ERR_SUCCESS;
 }
 
 static enum ndr_err_code ndr_pull_compression_xpress_chunk(struct ndr_pull *ndrpull,