*** /dev/null Sat Nov 23 01:28:35 2024
--- - Sat Nov 23 01:28:35 2024
***************
*** 0 ****
--- 1,365 ----
+ /*
+ ** Str - String Library
+ ** Copyright (c) 1999-2000 Ralf S. Engelschall <rse@engelschall.com>
+ **
+ ** This file is part of Str, a string handling and manipulation
+ ** library which can be found at http://www.engelschall.com/sw/str/.
+ **
+ ** Permission to use, copy, modify, and 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.
+ **
+ ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
+ ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ ** SUCH DAMAGE.
+ **
+ ** str_convert.c: string to byte conversions and vice versa
+ */
+
+ #include "str_p.h"
+
+ /*
+ * Copyright (c) 1996, 1998 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM 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.
+ */
+
+ /*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+ #include <string.h>
+ #include <ctype.h>
+
+ /*
+ * Encoding (Base256->Base64):
+ * Base256: 3 bytes, |11111111| |22222222| |33333333|
+ * Base64: 4 bytes, |XX111111| |XX112222| |XX222233| |XX333333|
+ *
+ * Decoding (Base64->Base256):
+ * Base64: 4 bytes, |XX111111| |XX222222| |XX333333| |XX444444|
+ * Base256: 3 bytes, |11111122| |22223333| |33444444|
+ *
+ * -
+ *
+ * The following encoding technique is taken from RFC 1521 by Borenstein
+ * and Freed. It is reproduced here in a slightly edited form for
+ * convenience.
+ *
+ * A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ * represented per printable character. (The extra 65th character, "=",
+ * is used to signify a special processing function.)
+ *
+ * The encoding process represents 24-bit groups of input bits as output
+ * strings of 4 encoded characters. Proceeding from left to right, a
+ * 24-bit input group is formed by concatenating 3 8-bit input groups.
+ * These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ * of which is translated into a single digit in the base64 alphabet.
+ *
+ * Each 6-bit group is used as an index into an array of 64 printable
+ * characters. The character referenced by the index is placed in the
+ * output string.
+ *
+ * Table 1: The Base64 Alphabet
+ *
+ * Value Encoding Value Encoding Value Encoding Value Encoding
+ * 0 A 17 R 34 i 51 z
+ * 1 B 18 S 35 j 52 0
+ * 2 C 19 T 36 k 53 1
+ * 3 D 20 U 37 l 54 2
+ * 4 E 21 V 38 m 55 3
+ * 5 F 22 W 39 n 56 4
+ * 6 G 23 X 40 o 57 5
+ * 7 H 24 Y 41 p 58 6
+ * 8 I 25 Z 42 q 59 7
+ * 9 J 26 a 43 r 60 8
+ * 10 K 27 b 44 s 61 9
+ * 11 L 28 c 45 t 62 +
+ * 12 M 29 d 46 u 63 /
+ * 13 N 30 e 47 v
+ * 14 O 31 f 48 w (pad) =
+ * 15 P 32 g 49 x
+ * 16 Q 33 h 50 y
+ *
+ * Special processing is performed if fewer than 24 bits are available
+ * at the end of the data being encoded. A full encoding quantum is
+ * always completed at the end of a quantity. When fewer than 24 input
+ * bits are available in an input group, zero bits are added (on the
+ * right) to form an integral number of 6-bit groups. Padding at the
+ * end of the data is performed using the '=' character.
+ *
+ * Since all base64 input is an integral number of octets, only the
+ * following cases can arise:
+ *
+ * (1) the final quantum of encoding input is an integral
+ * multiple of 24 bits; here, the final unit of encoded
+ * output will be an integral multiple of 4 characters
+ * with no "=" padding,
+ * (2) the final quantum of encoding input is exactly 16 bits;
+ * here, the final unit of encoded output will be three
+ * characters followed by one "=" padding character, or
+ * (3) the final quantum of encoding input is exactly 8 bits;
+ * here, the final unit of encoded output will be two
+ * characters followed by two "=" padding characters.
+ */
+
+ static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+ static const char Pad64 = '=';
+
+ /* encoding: binary -> base64 */
+ static int
+ base64_encode(
+ char *dst, str_size_t dstlen,
+ unsigned char const *src, str_size_t srclen,
+ int strict)
+ {
+ str_size_t dstpos;
+ unsigned char input[3];
+ unsigned char output[4];
+ int ocnt;
+ str_size_t i;
+
+ if (srclen == 0)
+ return -1;
+ if (dst == NULL) {
+ /* just calculate required length of dst */
+ dstlen = (((srclen + 2) / 3) * 4);
+ if (strict)
+ dstlen += (dstlen / 72);
+ return dstlen;
+ }
+
+ /* bulk encoding */
+ dstpos = 0;
+ ocnt = 0;
+ while (srclen >= 3) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclen -= 3;
+
+ output[0] = (input[0] >> 2);
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = (input[2] & 0x3f);
+
+ if (dstpos + 4 > dstlen)
+ return -1;
+ dst[dstpos++] = Base64[output[0]];
+ dst[dstpos++] = Base64[output[1]];
+ dst[dstpos++] = Base64[output[2]];
+ dst[dstpos++] = Base64[output[3]];
+ if (strict)
+ if (++ocnt % (72/4) == 0)
+ dst[dstpos++] = '\n';
+ }
+
+ /* now worry about padding with remaining 1 or 2 bytes */
+ if (srclen != 0) {
+ input[0] = input[1] = input[2] = NUL;
+ for (i = 0; i < srclen; i++)
+ input[i] = *src++;
+
+ output[0] = (input[0] >> 2);
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+
+ if (dstpos + 4 > dstlen)
+ return -1;
+ dst[dstpos++] = Base64[output[0]];
+ dst[dstpos++] = Base64[output[1]];
+ if (srclen == 1)
+ dst[dstpos++] = Pad64;
+ else
+ dst[dstpos++] = Base64[output[2]];
+ dst[dstpos++] = Pad64;
+ }
+
+ if (dstpos >= dstlen)
+ return -1;
+ dst[dstpos] = NUL;
+
+ return dstpos;
+ }
+
+ /* decoding: base64 -> binary */
+ static int
+ base64_decode(
+ unsigned char *dst, str_size_t dstlen,
+ char const *src, str_size_t srclen)
+ {
+ int dstidx, state, ch = 0;
+ unsigned char res;
+ char *pos;
+
+ if (srclen == 0)
+ srclen = strlen(src);
+ state = 0;
+ dstidx = 0;
+ res = 0;
+ while (srclen-- > 0) {
+ ch = *src++;
+ if (isascii(ch) && isspace(ch)) /* Skip whitespace anywhere */
+ continue;
+ if (ch == Pad64)
+ break;
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character */
+ return -1;
+ switch (state) {
+ case 0:
+ if (dst != NULL) {
+ if ((str_size_t)dstidx >= dstlen)
+ return -1;
+ dst[dstidx] = ((pos - Base64) << 2);
+ }
+ state = 1;
+ break;
+ case 1:
+ if (dst != NULL) {
+ if ((str_size_t)dstidx >= dstlen)
+ return -1;
+ dst[dstidx] |= ((pos - Base64) >> 4);
+ res = (((pos - Base64) & 0x0f) << 4);
+ }
+ dstidx++;
+ state = 2;
+ break;
+ case 2:
+ if (dst != NULL) {
+ if ((str_size_t)dstidx >= dstlen)
+ return -1;
+ dst[dstidx] = res | ((pos - Base64) >> 2);
+ res = ((pos - Base64) & 0x03) << 6;
+ }
+ dstidx++;
+ state = 3;
+ break;
+ case 3:
+ if (dst != NULL) {
+ if ((str_size_t)dstidx >= dstlen)
+ return -1;
+ dst[dstidx] = res | (pos - Base64);
+ }
+ dstidx++;
+ state = 0;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return -1;
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+ while (srclen-- > 0) {
+ ch = *src++;
+ if (!(isascii(ch) && isspace(ch)))
+ break;
+ }
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return -1;
+ /* FALLTHROUGH */
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+ while (srclen-- > 0) {
+ ch = *src++;
+ if (!(isascii(ch) && isspace(ch)))
+ return -1;
+ }
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (dst != NULL && res != 0)
+ return -1;
+ default:
+ break;
+ }
+ }
+ else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return -1;
+ }
+
+ return dstidx;
+ }
+
+ /*
+ * The API Function
+ */
+ int str_base64(char *s, str_size_t n, unsigned char *ucp, str_size_t ulen, int mode)
+ {
+ int rv;
+
+ if (mode & STR_BASE64_ENCODE)
+ rv = base64_encode(s, n, ucp, ulen, mode & STR_BASE64_STRICT ? TRUE : FALSE);
+ else if (mode & STR_BASE64_DECODE)
+ rv = base64_decode(ucp, ulen, s, n);
+ else
+ return -1;
+ return rv;
+ }
+
|