summaryrefslogtreecommitdiffstats
path: root/gl/base64.c
diff options
context:
space:
mode:
authorThomas Guyot-Sionnest <dermoth@aei.ca>2009-01-15 04:22:57 -0500
committerThomas Guyot-Sionnest <dermoth@aei.ca>2009-01-15 05:19:08 -0500
commit71cdb52799220f8d9052643baf1d3e9836a9c755 (patch)
tree27aee97a35d9ab51f0d8f64a46690bd41a5f8c1b /gl/base64.c
parentf7afa46586645e50498d8b2d0c67884f014dc3a4 (diff)
downloadmonitoring-plugins-71cdb52799220f8d9052643baf1d3e9836a9c755.tar.gz
Sync with gnulib
Diffstat (limited to 'gl/base64.c')
-rw-r--r--gl/base64.c273
1 files changed, 212 insertions, 61 deletions
diff --git a/gl/base64.c b/gl/base64.c
index e67075d1..42ccc9c2 100644
--- a/gl/base64.c
+++ b/gl/base64.c
@@ -52,6 +52,8 @@
52/* Get UCHAR_MAX. */ 52/* Get UCHAR_MAX. */
53#include <limits.h> 53#include <limits.h>
54 54
55#include <string.h>
56
55/* C89 compliant way to cast 'char' to 'unsigned char'. */ 57/* C89 compliant way to cast 'char' to 'unsigned char'. */
56static inline unsigned char 58static inline unsigned char
57to_uchar (char ch) 59to_uchar (char ch)
@@ -300,89 +302,237 @@ isbase64 (char ch)
300 return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)]; 302 return uchar_in_range (to_uchar (ch)) && 0 <= b64[to_uchar (ch)];
301} 303}
302 304
303/* Decode base64 encoded input array IN of length INLEN to output 305/* Initialize decode-context buffer, CTX. */
304 array OUT that can hold *OUTLEN bytes. Return true if decoding was 306void
305 successful, i.e. if the input was valid base64 data, false 307base64_decode_ctx_init (struct base64_decode_context *ctx)
306 otherwise. If *OUTLEN is too small, as many bytes as possible will
307 be written to OUT. On return, *OUTLEN holds the length of decoded
308 bytes in OUT. Note that as soon as any non-alphabet characters are
309 encountered, decoding is stopped and false is returned. This means
310 that, when applicable, you must remove any line terminators that is
311 part of the data stream before calling this function. */
312bool
313base64_decode (const char *restrict in, size_t inlen,
314 char *restrict out, size_t *outlen)
315{ 308{
316 size_t outleft = *outlen; 309 ctx->i = 0;
310}
317 311
318 while (inlen >= 2) 312/* If CTX->i is 0 or 4, there are four or more bytes in [*IN..IN_END), and
319 { 313 none of those four is a newline, then return *IN. Otherwise, copy up to
320 if (!isbase64 (in[0]) || !isbase64 (in[1])) 314 4 - CTX->i non-newline bytes from that range into CTX->buf, starting at
321 break; 315 index CTX->i and setting CTX->i to reflect the number of bytes copied,
316 and return CTX->buf. In either case, advance *IN to point to the byte
317 after the last one processed, and set *N_NON_NEWLINE to the number of
318 verified non-newline bytes accessible through the returned pointer. */
319static inline char *
320get_4 (struct base64_decode_context *ctx,
321 char const *restrict *in, char const *restrict in_end,
322 size_t *n_non_newline)
323{
324 if (ctx->i == 4)
325 ctx->i = 0;
322 326
323 if (outleft) 327 if (ctx->i == 0)
328 {
329 char const *t = *in;
330 if (4 <= in_end - *in && memchr (t, '\n', 4) == NULL)
324 { 331 {
325 *out++ = ((b64[to_uchar (in[0])] << 2) 332 /* This is the common case: no newline. */
326 | (b64[to_uchar (in[1])] >> 4)); 333 *in += 4;
327 outleft--; 334 *n_non_newline = 4;
335 return (char *) t;
328 } 336 }
337 }
329 338
330 if (inlen == 2) 339 {
331 break; 340 /* Copy non-newline bytes into BUF. */
341 char const *p = *in;
342 while (p < in_end)
343 {
344 char c = *p++;
345 if (c != '\n')
346 {
347 ctx->buf[ctx->i++] = c;
348 if (ctx->i == 4)
349 break;
350 }
351 }
352
353 *in = p;
354 *n_non_newline = ctx->i;
355 return ctx->buf;
356 }
357}
358
359#define return_false \
360 do \
361 { \
362 *outp = out; \
363 return false; \
364 } \
365 while (false)
366
367/* Decode up to four bytes of base64-encoded data, IN, of length INLEN
368 into the output buffer, *OUT, of size *OUTLEN bytes. Return true if
369 decoding is successful, false otherwise. If *OUTLEN is too small,
370 as many bytes as possible are written to *OUT. On return, advance
371 *OUT to point to the byte after the last one written, and decrement
372 *OUTLEN to reflect the number of bytes remaining in *OUT. */
373static inline bool
374decode_4 (char const *restrict in, size_t inlen,
375 char *restrict *outp, size_t *outleft)
376{
377 char *out = *outp;
378 if (inlen < 2)
379 return false;
380
381 if (!isbase64 (in[0]) || !isbase64 (in[1]))
382 return false;
383
384 if (*outleft)
385 {
386 *out++ = ((b64[to_uchar (in[0])] << 2)
387 | (b64[to_uchar (in[1])] >> 4));
388 --*outleft;
389 }
390
391 if (inlen == 2)
392 return_false;
393
394 if (in[2] == '=')
395 {
396 if (inlen != 4)
397 return_false;
398
399 if (in[3] != '=')
400 return_false;
401 }
402 else
403 {
404 if (!isbase64 (in[2]))
405 return_false;
332 406
333 if (in[2] == '=') 407 if (*outleft)
334 { 408 {
335 if (inlen != 4) 409 *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0)
336 break; 410 | (b64[to_uchar (in[2])] >> 2));
411 --*outleft;
412 }
337 413
338 if (in[3] != '=') 414 if (inlen == 3)
339 break; 415 return_false;
340 416
417 if (in[3] == '=')
418 {
419 if (inlen != 4)
420 return_false;
341 } 421 }
342 else 422 else
343 { 423 {
344 if (!isbase64 (in[2])) 424 if (!isbase64 (in[3]))
345 break; 425 return_false;
346 426
347 if (outleft) 427 if (*outleft)
348 { 428 {
349 *out++ = (((b64[to_uchar (in[1])] << 4) & 0xf0) 429 *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
350 | (b64[to_uchar (in[2])] >> 2)); 430 | b64[to_uchar (in[3])]);
351 outleft--; 431 --*outleft;
352 } 432 }
433 }
434 }
353 435
354 if (inlen == 3) 436 *outp = out;
355 break; 437 return true;
438}
356 439
357 if (in[3] == '=') 440/* Decode base64-encoded input array IN of length INLEN to output array
358 { 441 OUT that can hold *OUTLEN bytes. The input data may be interspersed
359 if (inlen != 4) 442 with newlines. Return true if decoding was successful, i.e. if the
360 break; 443 input was valid base64 data, false otherwise. If *OUTLEN is too
361 } 444 small, as many bytes as possible will be written to OUT. On return,
362 else 445 *OUTLEN holds the length of decoded bytes in OUT. Note that as soon
446 as any non-alphabet, non-newline character is encountered, decoding
447 is stopped and false is returned. If INLEN is zero, then process
448 only whatever data is stored in CTX.
449
450 Initially, CTX must have been initialized via base64_decode_ctx_init.
451 Subsequent calls to this function must reuse whatever state is recorded
452 in that buffer. It is necessary for when a quadruple of base64 input
453 bytes spans two input buffers.
454
455 If CTX is NULL then newlines are treated as garbage and the input
456 buffer is processed as a unit. */
457
458bool
459base64_decode_ctx (struct base64_decode_context *ctx,
460 const char *restrict in, size_t inlen,
461 char *restrict out, size_t *outlen)
462{
463 size_t outleft = *outlen;
464 bool ignore_newlines = ctx != NULL;
465 bool flush_ctx = false;
466 unsigned int ctx_i = 0;
467
468 if (ignore_newlines)
469 {
470 ctx_i = ctx->i;
471 flush_ctx = inlen == 0;
472 }
473
474
475 while (true)
476 {
477 size_t outleft_save = outleft;
478 if (ctx_i == 0 && !flush_ctx)
479 {
480 while (true)
363 { 481 {
364 if (!isbase64 (in[3])) 482 /* Save a copy of outleft, in case we need to re-parse this
483 block of four bytes. */
484 outleft_save = outleft;
485 if (!decode_4 (in, inlen, &out, &outleft))
365 break; 486 break;
366 487
367 if (outleft) 488 in += 4;
368 { 489 inlen -= 4;
369 *out++ = (((b64[to_uchar (in[2])] << 6) & 0xc0)
370 | b64[to_uchar (in[3])]);
371 outleft--;
372 }
373 } 490 }
374 } 491 }
375 492
376 in += 4; 493 if (inlen == 0 && !flush_ctx)
377 inlen -= 4; 494 break;
495
496 /* Handle the common case of 72-byte wrapped lines.
497 This also handles any other multiple-of-4-byte wrapping. */
498 if (inlen && *in == '\n' && ignore_newlines)
499 {
500 ++in;
501 --inlen;
502 continue;
503 }
504
505 /* Restore OUT and OUTLEFT. */
506 out -= outleft_save - outleft;
507 outleft = outleft_save;
508
509 {
510 char const *in_end = in + inlen;
511 char const *non_nl;
512
513 if (ignore_newlines)
514 non_nl = get_4 (ctx, &in, in_end, &inlen);
515 else
516 non_nl = in; /* Might have nl in this case. */
517
518 /* If the input is empty or consists solely of newlines (0 non-newlines),
519 then we're done. Likewise if there are fewer than 4 bytes when not
520 flushing context and not treating newlines as garbage. */
521 if (inlen == 0 || (inlen < 4 && !flush_ctx && ignore_newlines))
522 {
523 inlen = 0;
524 break;
525 }
526 if (!decode_4 (non_nl, inlen, &out, &outleft))
527 break;
528
529 inlen = in_end - in;
530 }
378 } 531 }
379 532
380 *outlen -= outleft; 533 *outlen -= outleft;
381 534
382 if (inlen != 0) 535 return inlen == 0;
383 return false;
384
385 return true;
386} 536}
387 537
388/* Allocate an output buffer in *OUT, and decode the base64 encoded 538/* Allocate an output buffer in *OUT, and decode the base64 encoded
@@ -397,12 +547,13 @@ base64_decode (const char *restrict in, size_t inlen,
397 input was invalid, in which case *OUT is NULL and *OUTLEN is 547 input was invalid, in which case *OUT is NULL and *OUTLEN is
398 undefined. */ 548 undefined. */
399bool 549bool
400base64_decode_alloc (const char *in, size_t inlen, char **out, 550base64_decode_alloc_ctx (struct base64_decode_context *ctx,
401 size_t *outlen) 551 const char *in, size_t inlen, char **out,
552 size_t *outlen)
402{ 553{
403 /* This may allocate a few bytes too much, depending on input, 554 /* This may allocate a few bytes too many, depending on input,
404 but it's not worth the extra CPU time to compute the exact amount. 555 but it's not worth the extra CPU time to compute the exact size.
405 The exact amount is 3 * inlen / 4, minus 1 if the input ends 556 The exact size is 3 * inlen / 4, minus 1 if the input ends
406 with "=" and minus another 1 if the input ends with "==". 557 with "=" and minus another 1 if the input ends with "==".
407 Dividing before multiplying avoids the possibility of overflow. */ 558 Dividing before multiplying avoids the possibility of overflow. */
408 size_t needlen = 3 * (inlen / 4) + 2; 559 size_t needlen = 3 * (inlen / 4) + 2;
@@ -411,7 +562,7 @@ base64_decode_alloc (const char *in, size_t inlen, char **out,
411 if (!*out) 562 if (!*out)
412 return true; 563 return true;
413 564
414 if (!base64_decode (in, inlen, *out, &needlen)) 565 if (!base64_decode_ctx (ctx, in, inlen, *out, &needlen))
415 { 566 {
416 free (*out); 567 free (*out);
417 *out = NULL; 568 *out = NULL;