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); |
