1b0e6ab35af8139c0b9b65a08df1a58104c9c02d
[obnox/samba/samba-obnox.git] / lib / util / data_blob.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Easy management of byte-length data
4    Copyright (C) Andrew Tridgell 2001
5    Copyright (C) Andrew Bartlett 2001
6    
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "replace.h"
22 #include "attr.h"
23 #include "data_blob.h"
24
25 const DATA_BLOB data_blob_null = { NULL, 0 };
26
27 /**
28  * @file
29  * @brief Manipulation of arbitrary data blobs
30  **/
31
32 /**
33  construct a data blob, must be freed with data_blob_free()
34  you can pass NULL for p and get a blank data blob
35 **/
36 _PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name)
37 {
38         return data_blob_talloc_named(NULL, p, length, name);
39 }
40
41 /**
42  construct a data blob, using supplied TALLOC_CTX
43 **/
44 _PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
45 {
46         DATA_BLOB ret;
47
48         if (p == NULL && length == 0) {
49                 ZERO_STRUCT(ret);
50                 return ret;
51         }
52
53         if (p) {
54                 ret.data = (uint8_t *)talloc_memdup(mem_ctx, p, length);
55         } else {
56                 ret.data = talloc_array(mem_ctx, uint8_t, length);
57         }
58         if (ret.data == NULL) {
59                 ret.length = 0;
60                 return ret;
61         }
62         talloc_set_name_const(ret.data, name);
63         ret.length = length;
64         return ret;
65 }
66
67 /**
68  construct a zero data blob, using supplied TALLOC_CTX. 
69  use this sparingly as it initialises data - better to initialise
70  yourself if you want specific data in the blob
71 **/
72 _PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
73 {
74         DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
75         data_blob_clear(&blob);
76         return blob;
77 }
78
79 /**
80 free a data blob
81 **/
82 _PUBLIC_ void data_blob_free(DATA_BLOB *d)
83 {
84         if (d) {
85                 talloc_free(d->data);
86                 d->data = NULL;
87                 d->length = 0;
88         }
89 }
90
91 /**
92 clear a DATA_BLOB's contents
93 **/
94 _PUBLIC_ void data_blob_clear(DATA_BLOB *d)
95 {
96         if (d->data) {
97                 memset(d->data, 0, d->length);
98         }
99 }
100
101 /**
102 free a data blob and clear its contents
103 **/
104 _PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
105 {
106         data_blob_clear(d);
107         data_blob_free(d);
108 }
109
110
111 /**
112 check if two data blobs are equal
113 **/
114 _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
115 {
116         int ret;
117         if (d1->data == NULL && d2->data != NULL) {
118                 return -1;
119         }
120         if (d1->data != NULL && d2->data == NULL) {
121                 return 1;
122         }
123         if (d1->data == d2->data) {
124                 return d1->length - d2->length;
125         }
126         ret = memcmp(d1->data, d2->data, MIN(d1->length, d2->length));
127         if (ret == 0) {
128                 return d1->length - d2->length;
129         }
130         return ret;
131 }
132
133 /**
134 print the data_blob as hex string
135 **/
136 _PUBLIC_ char *data_blob_hex_string_lower(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
137 {
138         int i;
139         char *hex_string;
140
141         hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
142         if (!hex_string) {
143                 return NULL;
144         }
145
146         /* this must be lowercase or w2k8 cannot join a samba domain,
147            as this routine is used to encode extended DNs and windows
148            only accepts lowercase hexadecimal numbers */
149         for (i = 0; i < blob->length; i++)
150                 slprintf(&hex_string[i*2], 3, "%02x", blob->data[i]);
151
152         hex_string[(blob->length*2)] = '\0';
153         return hex_string;
154 }
155
156 _PUBLIC_ char *data_blob_hex_string_upper(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
157 {
158         int i;
159         char *hex_string;
160
161         hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
162         if (!hex_string) {
163                 return NULL;
164         }
165
166         for (i = 0; i < blob->length; i++)
167                 slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
168
169         hex_string[(blob->length*2)] = '\0';
170         return hex_string;
171 }
172
173 /**
174   useful for constructing data blobs in test suites, while
175   avoiding const warnings
176 **/
177 _PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
178 {
179         DATA_BLOB blob;
180         blob.data = discard_const_p(uint8_t, str);
181         blob.length = str ? strlen(str) : 0;
182         return blob;
183 }
184
185 /**
186   useful for constructing data blobs in test suites, while
187   avoiding const warnings
188 **/
189 _PUBLIC_ DATA_BLOB data_blob_string_const_null(const char *str)
190 {
191         DATA_BLOB blob;
192         blob.data = discard_const_p(uint8_t, str);
193         blob.length = str ? strlen(str)+1 : 0;
194         return blob;
195 }
196
197 /**
198  * Create a new data blob from const data 
199  */
200
201 _PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length)
202 {
203         DATA_BLOB blob;
204         blob.data = discard_const_p(uint8_t, p);
205         blob.length = length;
206         return blob;
207 }
208
209
210 /**
211   realloc a data_blob
212 **/
213 _PUBLIC_ bool data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
214 {
215         blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, length);
216         if (blob->data == NULL)
217                 return false;
218         blob->length = length;
219         return true;
220 }
221
222
223 /**
224   append some data to a data blob
225 **/
226 _PUBLIC_ bool data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
227                                    const void *p, size_t length)
228 {
229         size_t old_len = blob->length;
230         size_t new_len = old_len + length;
231         if (new_len < length || new_len < old_len) {
232                 return false;
233         }
234
235         if ((const uint8_t *)p + length < (const uint8_t *)p) {
236                 return false;
237         }
238         
239         if (!data_blob_realloc(mem_ctx, blob, new_len)) {
240                 return false;
241         }
242
243         memcpy(blob->data + old_len, p, length);
244         return true;
245 }
246