Branch data Line data Source code
1 : : // $Id: BroString.cc 6219 2008-10-01 05:39:07Z vern $
2 : : //
3 : : // See the file "COPYING" in the main distribution directory for copyright.
4 : :
5 : : #include "config.h"
6 : :
7 : : #include <algorithm>
8 : : #include <ctype.h>
9 : :
10 : : #include "BroString.h"
11 : : #include "Var.h"
12 : :
13 : : #ifdef DEBUG
14 : : #define DEBUG_STR(msg) DBG_LOG(DBG_STRING, msg)
15 : : #else
16 : : #define DEBUG_STR(msg)
17 : : #endif
18 : :
19 : : const int BroString::EXPANDED_STRING;
20 : : const int BroString::BRO_STRING_LITERAL;
21 : :
22 : : // This constructor forces the user to specify arg_final_NUL. When str
23 : : // is a *normal* NUL-terminated string, make arg_n == strlen(str) and
24 : : // arg_final_NUL == 1; when str is a sequence of n bytes, make
25 : : // arg_final_NUL == 0.
26 : :
27 : 128477 : BroString::BroString(int arg_final_NUL, byte_vec str, int arg_n)
28 : : {
29 : 128477 : b = str;
30 : 128477 : n = arg_n;
31 : 128477 : final_NUL = arg_final_NUL;
32 : 128477 : use_free_to_delete = 0;
33 : 128477 : }
34 : :
35 : 50024 : BroString::BroString(const u_char* str, int arg_n, int add_NUL)
36 : : {
37 : 50024 : b = 0;
38 : 50024 : n = 0;
39 : 50024 : use_free_to_delete = 0;
40 : 50024 : Set(str, arg_n, add_NUL);
41 : 50024 : }
42 : :
43 : 27298 : BroString::BroString(const char* str)
44 : : {
45 : 27298 : b = 0;
46 : 27298 : n = 0;
47 : 27298 : use_free_to_delete = 0;
48 : 27298 : Set(str);
49 : 27298 : }
50 : :
51 : 0 : BroString::BroString(const string &str)
52 : : {
53 : 0 : b = 0;
54 : 0 : n = 0;
55 : 0 : use_free_to_delete = 0;
56 : 0 : Set(str);
57 : 0 : }
58 : :
59 : 0 : BroString::BroString(const BroString& bs)
60 : : {
61 : 0 : b = 0;
62 : 0 : n = 0;
63 : 0 : use_free_to_delete = 0;
64 : 0 : *this = bs;
65 : 0 : }
66 : :
67 : 0 : BroString::BroString()
68 : : {
69 : 0 : b = 0;
70 : 0 : n = 0;
71 : 0 : final_NUL = 0;
72 : 0 : use_free_to_delete = 0;
73 : 0 : }
74 : :
75 : 278947 : void BroString::Reset()
76 : : {
77 [ + + ]: 278947 : if ( use_free_to_delete )
78 : 71219 : free(b);
79 : : else
80 [ + + ]: 207728 : delete [] b;
81 : :
82 : 278947 : b = 0;
83 : 278947 : n = 0;
84 : 278947 : final_NUL = 0;
85 : 278947 : use_free_to_delete = 0;
86 : 278947 : }
87 : :
88 : 0 : const BroString& BroString::operator=(const BroString &bs)
89 : : {
90 : 0 : Reset();
91 : 0 : n = bs.n;
92 : 0 : b = new u_char[n+1];
93 : :
94 : 0 : memcpy(b, bs.b, n);
95 : 0 : b[n] = '\0';
96 : :
97 : 0 : final_NUL = 1;
98 : 0 : use_free_to_delete = 0;
99 : 0 : return *this;
100 : : }
101 : :
102 : 0 : bool BroString::operator==(const BroString &bs) const
103 : : {
104 : 0 : return Bstr_eq(this, &bs);
105 : : }
106 : :
107 : 0 : bool BroString::operator<(const BroString &bs) const
108 : : {
109 : 0 : return Bstr_cmp(this, &bs) < 0;
110 : : }
111 : :
112 : 0 : void BroString::Adopt(byte_vec bytes, int len)
113 : : {
114 : 0 : Reset();
115 : :
116 : 0 : b = bytes;
117 : :
118 : : // Check if the string ends with a NUL. If so, mark it as having
119 : : // a final NUL and adjust the length accordingly.
120 [ # # ]: 0 : final_NUL = (b[len-1] == '\0') ? 1 : 0;
121 : 0 : n = len - final_NUL;
122 : 0 : }
123 : :
124 : 50024 : void BroString::Set(const u_char* str, int len, int add_NUL)
125 : : {
126 : 50024 : Reset();
127 : :
128 : 50024 : n = len;
129 [ + - ]: 50024 : b = new u_char[add_NUL ? n + 1 : n];
130 : 50024 : memcpy(b, str, n);
131 : 50024 : final_NUL = add_NUL;
132 : :
133 [ + - ]: 50024 : if ( add_NUL )
134 : 50024 : b[n] = 0;
135 : :
136 : 50024 : use_free_to_delete = 0;
137 : 50024 : }
138 : :
139 : 27298 : void BroString::Set(const char* str)
140 : : {
141 : 27298 : Reset();
142 : :
143 : 27298 : n = strlen(str);
144 : 27298 : b = new u_char[n+1];
145 : 27298 : memcpy(b, str, n+1);
146 : 27298 : final_NUL = 1;
147 : 27298 : use_free_to_delete = 0;
148 : 27298 : }
149 : :
150 : 0 : void BroString::Set(const string& str)
151 : : {
152 : 0 : Reset();
153 : :
154 : 0 : n = str.size();
155 : 0 : b = new u_char[n+1];
156 : 0 : memcpy(b, str.c_str(), n+1);
157 : 0 : final_NUL = 1;
158 : 0 : use_free_to_delete = 0;
159 : 0 : }
160 : :
161 : 0 : void BroString::Set(const BroString& str)
162 : : {
163 : 0 : *this = str;
164 : 0 : }
165 : :
166 : 55213 : const char* BroString::CheckString() const
167 : : {
168 [ + + ]: 55213 : if ( n == 0 )
169 : 2 : return "";
170 : :
171 [ - + ]: 55211 : if ( memchr(b, '\0', n + final_NUL) != &b[n] )
172 : : {
173 : : // Either an embedded NUL, or no final NUL.
174 : 0 : char* exp_s = Render();
175 [ # # ]: 0 : if ( b[n-1] != '\0' )
176 : 0 : run_time("string without NUL terminator: \"%s\"", exp_s);
177 : : else
178 : 0 : run_time("string with embedded NUL: \"%s\"", exp_s);
179 : :
180 [ # # ]: 0 : delete [] exp_s;
181 : 0 : return "<string-with-NUL>";
182 : : }
183 : :
184 : 55213 : return (const char*) b;
185 : : }
186 : :
187 : 123072 : char* BroString::Render(int format, int* len) const
188 : : {
189 : : // Maxmimum character expansion is as \xHH, so a factor of 4.
190 : 123072 : char* s = new char[n*4 + 1]; // +1 is for final '\0'
191 : 123072 : char* sp = s;
192 : : int tmp_len;
193 : :
194 [ + + ]: 2497903 : for ( int i = 0; i < n; ++i )
195 : : {
196 [ - + ][ # # ]: 2374831 : if ( b[i] == '\0' && (format & ESC_NULL) )
197 : : {
198 : 0 : *sp++ = '\\'; *sp++ = '0';
199 : : }
200 : :
201 [ - + ][ # # ]: 2374831 : else if ( b[i] == '\x7f' && (format & ESC_DEL) )
202 : : {
203 : 0 : *sp++ = '^'; *sp++ = '?';
204 : : }
205 : :
206 [ + + ][ + - ]: 2374831 : else if ( b[i] <= 26 && (format & ESC_LOW) )
207 : : {
208 : 120 : *sp++ = '^'; *sp++ = b[i] + 'A' - 1;
209 : : }
210 : :
211 [ + + ][ - + ]: 2374711 : else if ( b[i] == '\\' && (format & ESC_ESC) )
212 : : {
213 : 0 : *sp++ = '\\'; *sp++ = '\\';
214 : : }
215 : :
216 [ + + ][ + + ]: 2374711 : else if ( (b[i] == '\'' || b[i] == '"') && (format & ESC_QUOT) )
[ - + ]
217 : : {
218 : 0 : *sp++ = '\\'; *sp++ = b[i];
219 : : }
220 : :
221 [ + - ][ - + ]: 2374711 : else if ( (b[i] < ' ' || b[i] > 126) && (format & ESC_HEX) )
[ # # ]
222 : : {
223 : : char hex_fmt[16];
224 : :
225 : 0 : *sp++ = '\\'; *sp++ = 'x';
226 : 0 : sprintf(hex_fmt, "%02x", b[i]);
227 : 0 : *sp++ = hex_fmt[0]; *sp++ = hex_fmt[1];
228 : : }
229 : :
230 [ + - ][ - + ]: 2374711 : else if ( (b[i] < ' ' || b[i] > 126) && (format & ESC_DOT) )
[ # # ]
231 : : {
232 : 0 : *sp++ = '.';
233 : : }
234 : :
235 : : else
236 : : {
237 : 2374711 : *sp++ = b[i];
238 : : }
239 : : }
240 : :
241 : 123072 : *sp++ = '\0'; // NUL-terminate.
242 : 123072 : tmp_len = sp - s;
243 : :
244 [ - + ]: 123072 : if ( (format & ESC_SER) )
245 : : {
246 : 0 : char* result = new char[tmp_len + 16];
247 : 0 : snprintf(result, tmp_len + 16, "%u ", tmp_len - 1);
248 : 0 : tmp_len += strlen(result);
249 : 0 : memcpy(result + strlen(result), s, sp - s);
250 [ # # ]: 0 : delete [] s;
251 : 0 : s = result;
252 : : }
253 : :
254 [ - + ]: 123072 : if ( len )
255 : 0 : *len = tmp_len;
256 : :
257 : 123072 : return s;
258 : : }
259 : :
260 : 0 : ostream& BroString::Render(ostream &os, int format) const
261 : : {
262 : 0 : char* tmp = Render(format);
263 : 0 : os << tmp;
264 [ # # ]: 0 : delete [] tmp;
265 : 0 : return os;
266 : : }
267 : :
268 : 0 : istream& BroString::Read(istream &is, int format)
269 : : {
270 [ # # ]: 0 : if ( (format & BroString::ESC_SER) )
271 : : {
272 : : int len;
273 : 0 : is >> len; // Get the length of the string
274 : :
275 : : char c;
276 : 0 : is.read(&c, 1); // Eat single whitespace
277 : :
278 : 0 : char* buf = new char[len+1];
279 : 0 : is.read(buf, len);
280 : 0 : buf[len] = '\0'; // NUL-terminate just for safety
281 : :
282 : 0 : Adopt((u_char*) buf, len+1);
283 : : }
284 : : else
285 : : {
286 : 0 : string str;
287 : 0 : is >> str;
288 : 0 : Set(str);
289 : : }
290 : :
291 : 0 : return is;
292 : : }
293 : :
294 : 8886 : void BroString::ToUpper()
295 : : {
296 [ + + ]: 92783 : for ( int i = 0; i < n; ++i )
297 [ + + ]: 83897 : if ( islower(b[i]) )
298 : 66490 : b[i] = toupper(b[i]);
299 : 8886 : }
300 : :
301 : 0 : BroString* BroString::GetSubstring(int start, int len) const
302 : : {
303 : : // This code used to live in bro.bif's sub_bytes() routine.
304 [ # # ][ # # ]: 0 : if ( start < 0 || start > n )
305 : 0 : return 0;
306 : :
307 [ # # ][ # # ]: 0 : if ( len < 0 || len > n - start )
308 : 0 : len = n - start;
309 : :
310 : 0 : return new BroString(&b[start], len, 1);
311 : : }
312 : :
313 : 0 : int BroString::FindSubstring(const BroString* s) const
314 : : {
315 : 0 : return strstr_n(n, b, s->Len(), s->Bytes());
316 : : }
317 : :
318 : 0 : BroString::Vec* BroString::Split(const BroString::IdxVec& indices) const
319 : : {
320 : : unsigned int i;
321 : :
322 [ # # ]: 0 : if ( indices.size() == 0 )
323 : 0 : return 0;
324 : :
325 : : // Copy input, ensuring space for "0":
326 : 0 : IdxVec idx(1 + indices.size());
327 : :
328 : 0 : idx[0] = 0;
329 : 0 : idx.insert(idx.end(), indices.begin(), indices.end());
330 : :
331 : : // Sanity checks.
332 [ # # ]: 0 : for ( i = 0; i < idx.size(); ++i )
333 [ # # ][ # # ]: 0 : if ( idx[i] >= n || idx[i] < 0 )
[ # # ]
334 : 0 : idx[i] = 0;
335 : :
336 : : // Sort it:
337 : 0 : sort(idx.begin(), idx.end());
338 : :
339 : : // Shuffle vector so duplicate entries are used only once:
340 : 0 : IdxVecIt end = unique(idx.begin(), idx.end());
341 : :
342 : : // Each element in idx is now the start index of a new
343 : : // substring, and we know that all indices are within [0, n].
344 : : //
345 : 0 : Vec* result = new Vec();
346 : 0 : int last_idx = -1;
347 : : int next_idx;
348 : 0 : i = 0;
349 : :
350 [ # # ]: 0 : for ( IdxVecIt it = idx.begin(); it != end; ++it, ++i )
351 : : {
352 [ # # ]: 0 : int len = (it + 1 == end) ? -1 : idx[i + 1] - idx[i];
353 : 0 : result->push_back(GetSubstring(idx[i], len));
354 : : }
355 : :
356 : 0 : return result;
357 : : }
358 : :
359 : 0 : VectorVal* BroString:: VecToPolicy(Vec* vec)
360 : : {
361 : : VectorVal* result =
362 : 0 : new VectorVal(internal_type("string_vec")->AsVectorType());
363 [ # # ]: 0 : if ( ! result )
364 : 0 : return 0;
365 : :
366 [ # # ]: 0 : for ( unsigned int i = 0; i < vec->size(); ++i )
367 : : {
368 : 0 : BroString* string = (*vec)[i];
369 : : StringVal* val = new StringVal(string->Len(),
370 : 0 : (const char*) string->Bytes());
371 : 0 : result->Assign(i+1, val, 0);
372 : : }
373 : :
374 : 0 : return result;
375 : : }
376 : :
377 : 0 : BroString::Vec* BroString::VecFromPolicy(VectorVal* vec)
378 : : {
379 : 0 : Vec* result = new Vec();
380 : :
381 : : // VectorVals start at index 1!
382 [ # # ]: 0 : for ( unsigned int i = 1; i <= vec->Size(); ++i )
383 : : {
384 : 0 : Val* v = vec->Lookup(i); // get the RecordVal
385 [ # # ]: 0 : if ( ! v )
386 : 0 : continue;
387 : :
388 : 0 : BroString* string = new BroString(*(v->AsString()));
389 : 0 : result->push_back(string);
390 : : }
391 : :
392 : 0 : return result;
393 : : }
394 : :
395 : 0 : char* BroString::VecToString(const Vec* vec)
396 : : {
397 : 0 : string result("[");
398 : :
399 [ # # ]: 0 : for ( BroString::VecCIt it = vec->begin(); it != vec->end(); ++it )
400 : : {
401 : 0 : result += (*it)->CheckString();
402 : 0 : result += ",";
403 : : }
404 : :
405 : 0 : result += "]";
406 : :
407 : 0 : return strdup(result.c_str());
408 : : }
409 : :
410 : : bool BroStringLenCmp::operator()(BroString * const& bst1,
411 : 0 : BroString * const& bst2)
412 : : {
413 : : return _increasing ? (bst1->Len() < bst2->Len()) :
414 [ # # ]: 0 : (bst1->Len() > bst2->Len());
415 : : }
416 : :
417 : 0 : ostream& operator<<(ostream& os, const BroString& bs)
418 : : {
419 : 0 : char* tmp = bs.Render(BroString::EXPANDED_STRING);
420 : 0 : os << tmp;
421 [ # # ]: 0 : delete [] tmp;
422 : 0 : return os;
423 : : }
424 : :
425 : 0 : int Bstr_eq(const BroString* s1, const BroString* s2)
426 : : {
427 [ # # ]: 0 : if ( s1->Len() != s2->Len() )
428 : 0 : return 0;
429 : :
430 : 0 : return memcmp(s1->Bytes(), s2->Bytes(), s1->Len()) == 0;
431 : : }
432 : :
433 : 48973 : int Bstr_cmp(const BroString* s1, const BroString* s2)
434 : : {
435 : 48973 : int n = min(s1->Len(), s2->Len());
436 : 48973 : int cmp = memcmp(s1->Bytes(), s2->Bytes(), n);
437 : :
438 [ + + + + ]: 48973 : if ( cmp || s1->Len() == s2->Len() )
[ + + ]
439 : 25578 : return cmp;
440 : :
441 : : // Compared equal, but one was shorter than the other. Treat
442 : : // it as less than the other.
443 [ + + ]: 23395 : if ( s1->Len() < s2->Len() )
444 : 21244 : return -1;
445 : : else
446 : 48973 : return 1;
447 : : }
448 : :
449 : 44128 : BroString* concatenate(std::vector<data_chunk_t>& v)
450 : : {
451 : 44128 : int n = v.size();
452 : 44128 : int len = 0;
453 : : int i;
454 [ + + ]: 62167 : for ( i = 0; i < n; ++i )
455 : 18039 : len += v[i].length;
456 : :
457 : 44128 : char* data = new char[len+1];
458 : :
459 : 44128 : char* b = data;
460 [ + + ]: 62167 : for ( i = 0; i < n; ++i )
461 : : {
462 : 18039 : memcpy(b, v[i].data, v[i].length);
463 : 18039 : b += v[i].length;
464 : : }
465 : :
466 : 44128 : *b = '\0';
467 : :
468 : 44128 : return new BroString(1, (byte_vec) data, len);
469 : : }
470 : :
471 : 7984 : BroString* concatenate(BroString::CVec& v)
472 : : {
473 : 7984 : int n = v.size();
474 : 7984 : int len = 0;
475 : : int i;
476 [ + + ]: 15968 : for ( i = 0; i < n; ++i )
477 : 7984 : len += v[i]->Len();
478 : :
479 : 7984 : char* data = new char[len+1];
480 : :
481 : 7984 : char* b = data;
482 [ + + ]: 15968 : for ( i = 0; i < n; ++i )
483 : : {
484 : 7984 : memcpy(b, v[i]->Bytes(), v[i]->Len());
485 : 7984 : b += v[i]->Len();
486 : : }
487 : 7984 : *b = '\0';
488 : :
489 : 7984 : return new BroString(1, (byte_vec) data, len);
490 : : }
491 : :
492 : 0 : BroString* concatenate(BroString::Vec& v)
493 : : {
494 : 0 : BroString::CVec cv;
495 : :
496 [ # # ]: 0 : for ( BroString::VecIt it = v.begin(); it != v.end(); ++it )
497 : 0 : cv.push_back(*it);
498 : :
499 : 0 : return concatenate(cv);
500 : : }
501 : :
502 : 9746 : void delete_strings(std::vector<const BroString*>& v)
503 : : {
504 [ + + ]: 17730 : for ( unsigned int i = 0; i < v.size(); ++i )
505 [ + - ]: 7984 : delete v[i];
506 : 9746 : v.clear();
507 [ + - ][ + - ]: 9752 : }
|