Mercurial > libbase64
view base64.c @ 27:77b935a269b4
base64: fix signedness warning
author | David Demelier <markand@malikania.fr> |
---|---|
date | Fri, 14 May 2021 16:20:29 +0200 |
parents | 2a0d6539ab60 |
children | 94c8fd9ab0ee |
line wrap: on
line source
/* * base64.h -- base64 encoding and decoding * * Copyright (c) 2013-2020 David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <assert.h> #include <ctype.h> #include <errno.h> #include <string.h> #include "base64.h" bool b64_isbase64(unsigned char ch) { return isalnum(ch) || ch == '+' || ch == '/'; } bool b64_isvalid(unsigned char ch) { return b64_isbase64(ch) || ch == '='; } unsigned char b64_lookup(unsigned char value) { assert(value < 64); static const char *table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; return table[value]; } unsigned char b64_rlookup(unsigned char ch) { assert(b64_isbase64(ch)); if (ch >= '0' && ch <= '9') return ch + 4; if (ch >= 'A' && ch <= 'Z') return ch - 65; if (ch >= 'a' && ch <= 'z') return ch - 71; return ch == '+' ? 62U : 63U; } size_t b64_decode_length(size_t srcsz) { return 3 * srcsz / 4; } size_t b64_encode_length(size_t srcsz) { return 4 * (srcsz / 3 + 1); } size_t b64_encode(const char src[], size_t srcsz, char dst[], size_t dstsz) { assert(src); assert(dst); size_t nwritten = 0; if (srcsz == (size_t)-1) srcsz = strlen(src); while (srcsz && dstsz) { char inputbuf[3] = { 0 }; int count = 0; while (srcsz && count < 3) { inputbuf[count++] = *src++; --srcsz; } if (dstsz < 4) { errno = ERANGE; return -1; } *dst++ = b64_lookup(inputbuf[0] >> 2 & 0x3f); *dst++ = b64_lookup((inputbuf[0] << 4 & 0x3f) | (inputbuf[1] >> 4 & 0x0f)); if (count < 2) *dst++ = '='; else *dst++ = b64_lookup((inputbuf[1] << 2 & 0x3c) | (inputbuf[2] >> 6 & 0x03)); if (count < 3) *dst++ = '='; else *dst++ = b64_lookup(inputbuf[2] & 0x3f); nwritten += 4; dstsz -= 4; } /* Not enough room to store '\0'. */ if (dstsz == 0) { errno = ERANGE; return -1; } *dst = '\0'; return nwritten; } size_t b64_decode(const char src[], size_t srcsz, char dst[], size_t dstsz) { assert(src); assert(dst); size_t nwritten = 0; if (srcsz == (size_t)-1) srcsz = strlen(src); while (srcsz && dstsz) { signed char inputbuf[4] = { -1, -1, -1, -1 }; size_t parsed = 0, required; for (; srcsz && parsed < 4; parsed++) { /* '=' is only allowed in last 2 characters. */ if ((*src == '=' && parsed <= 1) || !b64_isvalid(*src)) goto eilseq; if (b64_isbase64(*src)) inputbuf[parsed] = b64_rlookup(*src); ++src; --srcsz; } if (parsed != 4) goto eilseq; if (inputbuf[3] != -1) required = 3; else if (inputbuf[2] != -1) required = 2; else required = 1; if (required >= dstsz) goto erange; *dst++ = ((inputbuf[0] << 2) & 0xfc) | ((inputbuf[1] >> 4) & 0x03); if (inputbuf[2] != -1) { *dst++ = ((inputbuf[1] << 4) & 0xf0) | ((inputbuf[2] >> 2) & 0x0f); required = 2; } if (inputbuf[3] != -1) { /* "XY=Z" is not allowed. */ if (inputbuf[2] == -1) goto eilseq; *dst++ = ((inputbuf[2] << 6) & 0xc0) | (inputbuf[3] & 0x3f); required = 3; } nwritten += required; dstsz -= required; } /* Not enough room to store '\0'. */ if (dstsz == 0) goto erange; *dst = '\0'; return nwritten; eilseq: errno = EILSEQ; return -1; erange: errno = ERANGE; return -1; }