diff options
Diffstat (limited to 'lib/string_helpers.c')
-rw-r--r-- | lib/string_helpers.c | 193 |
1 files changed, 80 insertions, 113 deletions
diff --git a/lib/string_helpers.c b/lib/string_helpers.c index 8f8c4417f228..1826c7407258 100644 --- a/lib/string_helpers.c +++ b/lib/string_helpers.c | |||
@@ -239,29 +239,21 @@ int string_unescape(char *src, char *dst, size_t size, unsigned int flags) | |||
239 | } | 239 | } |
240 | EXPORT_SYMBOL(string_unescape); | 240 | EXPORT_SYMBOL(string_unescape); |
241 | 241 | ||
242 | static int escape_passthrough(unsigned char c, char **dst, size_t *osz) | 242 | static bool escape_passthrough(unsigned char c, char **dst, char *end) |
243 | { | 243 | { |
244 | char *out = *dst; | 244 | char *out = *dst; |
245 | 245 | ||
246 | if (*osz < 1) | 246 | if (out < end) |
247 | return -ENOMEM; | 247 | *out = c; |
248 | 248 | *dst = out + 1; | |
249 | *out++ = c; | 249 | return true; |
250 | |||
251 | *dst = out; | ||
252 | *osz -= 1; | ||
253 | |||
254 | return 1; | ||
255 | } | 250 | } |
256 | 251 | ||
257 | static int escape_space(unsigned char c, char **dst, size_t *osz) | 252 | static bool escape_space(unsigned char c, char **dst, char *end) |
258 | { | 253 | { |
259 | char *out = *dst; | 254 | char *out = *dst; |
260 | unsigned char to; | 255 | unsigned char to; |
261 | 256 | ||
262 | if (*osz < 2) | ||
263 | return -ENOMEM; | ||
264 | |||
265 | switch (c) { | 257 | switch (c) { |
266 | case '\n': | 258 | case '\n': |
267 | to = 'n'; | 259 | to = 'n'; |
@@ -279,26 +271,25 @@ static int escape_space(unsigned char c, char **dst, size_t *osz) | |||
279 | to = 'f'; | 271 | to = 'f'; |
280 | break; | 272 | break; |
281 | default: | 273 | default: |
282 | return 0; | 274 | return false; |
283 | } | 275 | } |
284 | 276 | ||
285 | *out++ = '\\'; | 277 | if (out < end) |
286 | *out++ = to; | 278 | *out = '\\'; |
279 | ++out; | ||
280 | if (out < end) | ||
281 | *out = to; | ||
282 | ++out; | ||
287 | 283 | ||
288 | *dst = out; | 284 | *dst = out; |
289 | *osz -= 2; | 285 | return true; |
290 | |||
291 | return 1; | ||
292 | } | 286 | } |
293 | 287 | ||
294 | static int escape_special(unsigned char c, char **dst, size_t *osz) | 288 | static bool escape_special(unsigned char c, char **dst, char *end) |
295 | { | 289 | { |
296 | char *out = *dst; | 290 | char *out = *dst; |
297 | unsigned char to; | 291 | unsigned char to; |
298 | 292 | ||
299 | if (*osz < 2) | ||
300 | return -ENOMEM; | ||
301 | |||
302 | switch (c) { | 293 | switch (c) { |
303 | case '\\': | 294 | case '\\': |
304 | to = '\\'; | 295 | to = '\\'; |
@@ -310,71 +301,78 @@ static int escape_special(unsigned char c, char **dst, size_t *osz) | |||
310 | to = 'e'; | 301 | to = 'e'; |
311 | break; | 302 | break; |
312 | default: | 303 | default: |
313 | return 0; | 304 | return false; |
314 | } | 305 | } |
315 | 306 | ||
316 | *out++ = '\\'; | 307 | if (out < end) |
317 | *out++ = to; | 308 | *out = '\\'; |
309 | ++out; | ||
310 | if (out < end) | ||
311 | *out = to; | ||
312 | ++out; | ||
318 | 313 | ||
319 | *dst = out; | 314 | *dst = out; |
320 | *osz -= 2; | 315 | return true; |
321 | |||
322 | return 1; | ||
323 | } | 316 | } |
324 | 317 | ||
325 | static int escape_null(unsigned char c, char **dst, size_t *osz) | 318 | static bool escape_null(unsigned char c, char **dst, char *end) |
326 | { | 319 | { |
327 | char *out = *dst; | 320 | char *out = *dst; |
328 | 321 | ||
329 | if (*osz < 2) | ||
330 | return -ENOMEM; | ||
331 | |||
332 | if (c) | 322 | if (c) |
333 | return 0; | 323 | return false; |
334 | 324 | ||
335 | *out++ = '\\'; | 325 | if (out < end) |
336 | *out++ = '0'; | 326 | *out = '\\'; |
327 | ++out; | ||
328 | if (out < end) | ||
329 | *out = '0'; | ||
330 | ++out; | ||
337 | 331 | ||
338 | *dst = out; | 332 | *dst = out; |
339 | *osz -= 2; | 333 | return true; |
340 | |||
341 | return 1; | ||
342 | } | 334 | } |
343 | 335 | ||
344 | static int escape_octal(unsigned char c, char **dst, size_t *osz) | 336 | static bool escape_octal(unsigned char c, char **dst, char *end) |
345 | { | 337 | { |
346 | char *out = *dst; | 338 | char *out = *dst; |
347 | 339 | ||
348 | if (*osz < 4) | 340 | if (out < end) |
349 | return -ENOMEM; | 341 | *out = '\\'; |
350 | 342 | ++out; | |
351 | *out++ = '\\'; | 343 | if (out < end) |
352 | *out++ = ((c >> 6) & 0x07) + '0'; | 344 | *out = ((c >> 6) & 0x07) + '0'; |
353 | *out++ = ((c >> 3) & 0x07) + '0'; | 345 | ++out; |
354 | *out++ = ((c >> 0) & 0x07) + '0'; | 346 | if (out < end) |
347 | *out = ((c >> 3) & 0x07) + '0'; | ||
348 | ++out; | ||
349 | if (out < end) | ||
350 | *out = ((c >> 0) & 0x07) + '0'; | ||
351 | ++out; | ||
355 | 352 | ||
356 | *dst = out; | 353 | *dst = out; |
357 | *osz -= 4; | 354 | return true; |
358 | |||
359 | return 1; | ||
360 | } | 355 | } |
361 | 356 | ||
362 | static int escape_hex(unsigned char c, char **dst, size_t *osz) | 357 | static bool escape_hex(unsigned char c, char **dst, char *end) |
363 | { | 358 | { |
364 | char *out = *dst; | 359 | char *out = *dst; |
365 | 360 | ||
366 | if (*osz < 4) | 361 | if (out < end) |
367 | return -ENOMEM; | 362 | *out = '\\'; |
368 | 363 | ++out; | |
369 | *out++ = '\\'; | 364 | if (out < end) |
370 | *out++ = 'x'; | 365 | *out = 'x'; |
371 | *out++ = hex_asc_hi(c); | 366 | ++out; |
372 | *out++ = hex_asc_lo(c); | 367 | if (out < end) |
368 | *out = hex_asc_hi(c); | ||
369 | ++out; | ||
370 | if (out < end) | ||
371 | *out = hex_asc_lo(c); | ||
372 | ++out; | ||
373 | 373 | ||
374 | *dst = out; | 374 | *dst = out; |
375 | *osz -= 4; | 375 | return true; |
376 | |||
377 | return 1; | ||
378 | } | 376 | } |
379 | 377 | ||
380 | /** | 378 | /** |
@@ -426,19 +424,17 @@ static int escape_hex(unsigned char c, char **dst, size_t *osz) | |||
426 | * it if needs. | 424 | * it if needs. |
427 | * | 425 | * |
428 | * Return: | 426 | * Return: |
429 | * The amount of the characters processed to the destination buffer, or | 427 | * The total size of the escaped output that would be generated for |
430 | * %-ENOMEM if the size of buffer is not enough to put an escaped character is | 428 | * the given input and flags. To check whether the output was |
431 | * returned. | 429 | * truncated, compare the return value to osz. There is room left in |
432 | * | 430 | * dst for a '\0' terminator if and only if ret < osz. |
433 | * Even in the case of error @dst pointer will be updated to point to the byte | ||
434 | * after the last processed character. | ||
435 | */ | 431 | */ |
436 | int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | 432 | int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, |
437 | unsigned int flags, const char *esc) | 433 | unsigned int flags, const char *esc) |
438 | { | 434 | { |
439 | char *out = *dst, *p = out; | 435 | char *p = dst; |
436 | char *end = p + osz; | ||
440 | bool is_dict = esc && *esc; | 437 | bool is_dict = esc && *esc; |
441 | int ret = 0; | ||
442 | 438 | ||
443 | while (isz--) { | 439 | while (isz--) { |
444 | unsigned char c = *src++; | 440 | unsigned char c = *src++; |
@@ -458,55 +454,26 @@ int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, | |||
458 | (is_dict && !strchr(esc, c))) { | 454 | (is_dict && !strchr(esc, c))) { |
459 | /* do nothing */ | 455 | /* do nothing */ |
460 | } else { | 456 | } else { |
461 | if (flags & ESCAPE_SPACE) { | 457 | if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) |
462 | ret = escape_space(c, &p, &osz); | 458 | continue; |
463 | if (ret < 0) | 459 | |
464 | break; | 460 | if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end)) |
465 | if (ret > 0) | 461 | continue; |
466 | continue; | 462 | |
467 | } | 463 | if (flags & ESCAPE_NULL && escape_null(c, &p, end)) |
468 | 464 | continue; | |
469 | if (flags & ESCAPE_SPECIAL) { | ||
470 | ret = escape_special(c, &p, &osz); | ||
471 | if (ret < 0) | ||
472 | break; | ||
473 | if (ret > 0) | ||
474 | continue; | ||
475 | } | ||
476 | |||
477 | if (flags & ESCAPE_NULL) { | ||
478 | ret = escape_null(c, &p, &osz); | ||
479 | if (ret < 0) | ||
480 | break; | ||
481 | if (ret > 0) | ||
482 | continue; | ||
483 | } | ||
484 | 465 | ||
485 | /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ | 466 | /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ |
486 | if (flags & ESCAPE_OCTAL) { | 467 | if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end)) |
487 | ret = escape_octal(c, &p, &osz); | ||
488 | if (ret < 0) | ||
489 | break; | ||
490 | continue; | 468 | continue; |
491 | } | 469 | |
492 | if (flags & ESCAPE_HEX) { | 470 | if (flags & ESCAPE_HEX && escape_hex(c, &p, end)) |
493 | ret = escape_hex(c, &p, &osz); | ||
494 | if (ret < 0) | ||
495 | break; | ||
496 | continue; | 471 | continue; |
497 | } | ||
498 | } | 472 | } |
499 | 473 | ||
500 | ret = escape_passthrough(c, &p, &osz); | 474 | escape_passthrough(c, &p, end); |
501 | if (ret < 0) | ||
502 | break; | ||
503 | } | 475 | } |
504 | 476 | ||
505 | *dst = p; | 477 | return p - dst; |
506 | |||
507 | if (ret < 0) | ||
508 | return ret; | ||
509 | |||
510 | return p - out; | ||
511 | } | 478 | } |
512 | EXPORT_SYMBOL(string_escape_mem); | 479 | EXPORT_SYMBOL(string_escape_mem); |