ca04b70eb229c583d7b78bdb1670b5f0118fd7d0
[metze/samba/wip.git] / source4 / 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 2 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, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /**
25  * @file
26  * @brief Manipulation of arbitrary data blobs
27  **/
28
29 /**
30  construct a data blob, must be freed with data_blob_free()
31  you can pass NULL for p and get a blank data blob
32 **/
33 _PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name)
34 {
35         DATA_BLOB ret;
36
37         if (p == NULL && length == 0) {
38                 ZERO_STRUCT(ret);
39                 return ret;
40         }
41
42         if (p) {
43                 ret.data = talloc_memdup(NULL, p, length);
44         } else {
45                 ret.data = talloc_size(NULL, length);
46         }
47         if (ret.data == NULL) {
48                 ret.length = 0;
49                 return ret;
50         }
51         talloc_set_name_const(ret.data, name);
52         ret.length = length;
53         return ret;
54 }
55
56 /**
57  construct a data blob, using supplied TALLOC_CTX
58 **/
59 _PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
60 {
61         DATA_BLOB ret = data_blob_named(p, length, name);
62
63         if (ret.data) {
64                 talloc_steal(mem_ctx, ret.data);
65         }
66         return ret;
67 }
68
69
70 /**
71  reference a data blob, to the supplied TALLOC_CTX.  
72  Returns a NULL DATA_BLOB on failure
73 **/
74 _PUBLIC_ DATA_BLOB data_blob_talloc_reference(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
75 {
76         DATA_BLOB ret = *blob;
77
78         ret.data = talloc_reference(mem_ctx, blob->data);
79
80         if (!ret.data) {
81                 return data_blob(NULL, 0);
82         }
83         return ret;
84 }
85
86 /**
87  construct a zero data blob, using supplied TALLOC_CTX. 
88  use this sparingly as it initialises data - better to initialise
89  yourself if you want specific data in the blob
90 **/
91 _PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
92 {
93         DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
94         data_blob_clear(&blob);
95         return blob;
96 }
97
98 /**
99 free a data blob
100 **/
101 _PUBLIC_ void data_blob_free(DATA_BLOB *d)
102 {
103         if (d) {
104                 talloc_free(d->data);
105                 d->data = NULL;
106                 d->length = 0;
107         }
108 }
109
110 /**
111 clear a DATA_BLOB's contents
112 **/
113 _PUBLIC_ void data_blob_clear(DATA_BLOB *d)
114 {
115         if (d->data) {
116                 memset(d->data, 0, d->length);
117         }
118 }
119
120 /**
121 free a data blob and clear its contents
122 **/
123 _PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
124 {
125         data_blob_clear(d);
126         data_blob_free(d);
127 }
128
129
130 /**
131 check if two data blobs are equal
132 **/
133 _PUBLIC_ int data_blob_cmp(const DATA_BLOB *d1, const DATA_BLOB *d2)
134 {
135         int ret;
136         if (d1->data == NULL && d2->data != NULL) {
137                 return -1;
138         }
139         if (d1->data != NULL && d2->data == NULL) {
140                 return 1;
141         }
142         if (d1->data == d2->data) {
143                 return d1->length - d2->length;
144         }
145         ret = memcmp(d1->data, d2->data, MIN(d1->length, d2->length));
146         if (ret == 0) {
147                 return d1->length - d2->length;
148         }
149         return ret;
150 }
151
152 /**
153 print the data_blob as hex string
154 **/
155 _PUBLIC_ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob)
156 {
157         int i;
158         char *hex_string;
159
160         hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
161         if (!hex_string) {
162                 return NULL;
163         }
164
165         for (i = 0; i < blob->length; i++)
166                 slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
167
168         hex_string[(blob->length*2)] = '\0';
169         return hex_string;
170 }
171
172 /**
173   useful for constructing data blobs in test suites, while
174   avoiding const warnings
175 **/
176 _PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
177 {
178         DATA_BLOB blob;
179         blob.data = discard_const(str);
180         blob.length = strlen(str);
181         return blob;
182 }
183
184 /**
185  * Create a new data blob from const data 
186  */
187
188 _PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length)
189 {
190         DATA_BLOB blob;
191         blob.data = discard_const(p);
192         blob.length = length;
193         return blob;
194 }
195
196
197 /**
198   realloc a data_blob
199 **/
200 _PUBLIC_ NTSTATUS data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
201 {
202         blob->data = talloc_realloc_size(mem_ctx, blob->data, length);
203         NT_STATUS_HAVE_NO_MEMORY(blob->data);   
204         blob->length = length;
205         return NT_STATUS_OK;
206 }
207
208
209 /**
210   append some data to a data blob
211 **/
212 _PUBLIC_ NTSTATUS data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
213                                    const void *p, size_t length)
214 {
215         NTSTATUS status;
216         size_t old_len = blob->length;
217         size_t new_len = old_len + length;
218         if (new_len < length || new_len < old_len) {
219                 return NT_STATUS_NO_MEMORY;
220         }
221
222         if ((const uint8_t *)p + length < (const uint8_t *)p) {
223                 return NT_STATUS_NO_MEMORY;
224         }
225         
226         status = data_blob_realloc(mem_ctx, blob, new_len);
227         if (!NT_STATUS_IS_OK(status)) {
228                 return status;
229         }
230
231         memcpy(blob->data + old_len, p, length);
232         return NT_STATUS_OK;
233 }
234