r6061: add start of compression support in our rpc code
[tprouty/samba.git] / source4 / librpc / ndr / ndr_compression.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    libndr compression support
5
6    Copyright (C) Stefan Metzmacher 2005
7    
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.
12    
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.
17    
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.
21 */
22
23 #include "includes.h"
24
25 #ifdef HAVE_ZLIB
26 #include <zlib.h>
27
28 static NTSTATUS ndr_pull_compression_zlib(struct ndr_pull *subndr,
29                                           struct ndr_pull *comndr,
30                                           ssize_t decompressed_len)
31 {
32         DATA_BLOB inbuf;
33         DATA_BLOB outbuf = data_blob_talloc(comndr, NULL, decompressed_len);
34         uint32_t outbuf_len = outbuf.length;
35         struct z_stream_s zs;
36         int ret;
37
38         ZERO_STRUCT(zs);
39
40         if (subndr->data_size < 10) {
41                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB compressed header (PULL) subcontext size %d", 
42                                       subndr->data_size);
43         }
44
45         inbuf.data = subndr->data+10;
46         inbuf.length = subndr->data_size-10;
47
48         zs.avail_in = inbuf.length;
49         zs.next_in = inbuf.data;
50         zs.next_out = outbuf.data;
51         zs.avail_out = outbuf.length;
52
53         ret = inflateInit2(&zs, 15);
54         if (ret != Z_OK) {
55                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) inflateInit2 error %d", 
56                                       ret);
57         }
58
59         while(1) {
60                 ret = inflate(&zs, Z_SYNC_FLUSH);
61                 if (ret == Z_STREAM_END) {
62                         
63                         DEBUG(0,("inbuf.length: %d avail_in: %d, avail_out: %d\n", inbuf.length, zs.avail_in, zs.avail_out));
64                         break;
65                 }
66                 if (ret != Z_OK) {
67                         return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) inflate error %d", 
68                                       ret);
69                 }
70         }
71
72         inflateEnd(&zs);
73
74         /* TODO: check if the decompressed_len == outbuf_len */
75         outbuf.length = outbuf_len - zs.avail_out;
76
77         if (outbuf.length < 16) {
78                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB uncompressed header (PULL) uncompressed size %d", 
79                                       outbuf.length);
80         }
81
82         outbuf.data     += 16;
83         outbuf.length   -= 16;
84
85         /* TODO: really decompress the data here */
86         *comndr = *subndr;
87         comndr->data            = outbuf.data;
88         comndr->data_size       = outbuf.length;
89         comndr->offset          = 0;
90
91         return NT_STATUS_OK;
92 }
93
94 static NTSTATUS ndr_push_compression_zlib(struct ndr_push *subndr,
95                                           struct ndr_push *comndr)
96 {
97         DATA_BLOB inbuf;
98         DATA_BLOB outbuf = data_blob_talloc(comndr, NULL, comndr->offset + 10);
99         struct z_stream_s zs;
100         int ret;
101
102         ZERO_STRUCT(zs);
103
104         inbuf = ndr_push_blob(comndr);
105
106         zs.avail_in = inbuf.length;
107         zs.next_in = inbuf.data;
108         zs.next_out = outbuf.data+10;
109         zs.avail_out = outbuf.length-10;
110
111         ret = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
112         if (ret != Z_OK) {
113                 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PUSH) deflateInit2 error %d", 
114                                       ret);
115         }
116
117         ret = deflate(&zs, Z_SYNC_FLUSH);
118
119         if (ret != Z_OK && ret != Z_STREAM_END) {
120                 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad ZLIB (PULL) deflate error %d", 
121                                       ret);
122         }
123
124         deflateEnd(&zs);
125
126         /* TODO: push the header here */
127
128
129         NDR_CHECK(ndr_push_bytes(subndr, outbuf.data, outbuf.length));
130
131         return NT_STATUS_OK;
132 }
133 #endif
134
135 /*
136   handle compressed subcontext buffers, which in midl land are user-marshalled, but
137   we use magic in pidl to make them easier to cope with
138 */
139 NTSTATUS ndr_pull_compression(struct ndr_pull *subndr,
140                               struct ndr_pull *comndr,
141                               enum ndr_compression_alg compression_alg,
142                               ssize_t decompressed_len)
143 {
144         comndr->flags = subndr->flags;
145
146         switch (compression_alg) {
147 #ifdef HAVE_ZLIB
148         case NDR_COMPRESSION_ZLIB:
149                 return ndr_pull_compression_zlib(subndr, comndr, decompressed_len);
150 #endif
151         default:
152                 return ndr_pull_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PULL)", 
153                                       compression_alg);
154         }
155         return NT_STATUS_OK;
156 }
157
158 /*
159   push a compressed subcontext
160 */
161 NTSTATUS ndr_push_compression(struct ndr_push *subndr,
162                               struct ndr_push *comndr,
163                               enum ndr_compression_alg compression_alg)
164 {
165         comndr->flags = subndr->flags;
166
167         switch (compression_alg) {
168 #ifdef HAVE_ZLIB
169         case NDR_COMPRESSION_ZLIB:
170                 return ndr_push_compression_zlib(subndr, comndr);
171 #endif
172         default:
173                 return ndr_push_error(subndr, NDR_ERR_COMPRESSION, "Bad compression algorithm %d (PUSH)", 
174                                       compression_alg);
175         }
176         return NT_STATUS_OK;
177 }