base64.cpp revision c7814cf6e1240a519cbec0441e033d0e2470ed00
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * IPRT - Base64, MIME content transfer encoding.
c7814cf6e1240a519cbec0441e033d0e2470ed00vboxsync * Copyright (C) 2009-2012 Oracle Corporation
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * available from http://www.virtualbox.org. This file is free software;
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * you can redistribute it and/or modify it under the terms of the GNU
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * General Public License (GPL) as published by the Free Software
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * The contents of this file may alternatively be used under the terms
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * of the Common Development and Distribution License Version 1.0
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * VirtualBox OSE distribution, in which case the provisions of the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * CDDL are applicable instead of those of the GPL.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * You may elect to license modified versions of this file under the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * terms and conditions of either the GPL or the CDDL or both.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync/*******************************************************************************
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync* Header Files *
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync*******************************************************************************/
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync/*******************************************************************************
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync* Defined Constants And Macros *
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync*******************************************************************************/
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync/** The line length used for encoding. */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync/** @name Special g_au8CharToVal values
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync/*******************************************************************************
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync* Global Variables *
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync*******************************************************************************/
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync/** Base64 character to value. (RFC 2045)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * ASSUMES ASCII / UTF-8. */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xff, 0xff, /* 0x00..0x0f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10..0x1f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, /* 0x20..0x2f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xe0, 0xff, 0xff, /* 0x30..0x3f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, /* 0x40..0x4f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50..0x5f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, /* 0x60..0x6f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70..0x7f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80..0x8f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90..0x9f */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0..0xaf */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0..0xbf */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0..0xcf */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0..0xdf */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0..0xef */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff /* 0xf0..0xff */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync/** Value to Base64 character. (RFC 2045) */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Perform table sanity checks on the first call.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsyncstatic void rtBase64Sanity(void)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync static bool s_fSane = false;
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync for (unsigned i = 0; i < 64; i++)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync for (unsigned i = 0; i < 256; i++)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync && i == '=')
8c23479fc4c929145ab67254ffe3ab13ce6dc434vboxsync || (i == '\r'))) /* Carriage return is handled as a space character as well. */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync#endif /* RT_STRICT */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Calculates the decoded data size for a Base64 encoded string.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @returns The length in bytes. -1 if the encoding is bad.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param pszString The Base64 encoded string.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param ppszEnd If not NULL, this will point to the first char
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * following the Base64 encoded text block. If
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * NULL the entire string is assumed to be Base64.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsyncRTDECL(ssize_t) RTBase64DecodedSize(const char *pszString, char **ppszEnd)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Walk the string until a non-encoded or non-space character is encountered.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync /* advance */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Padding can only be found at the end and there is
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * only 1 or 2 padding chars. Deal with it first.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync unsigned cbPad = 0;
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Invalid char and no where to indicate where the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Base64 text ends? Return failure.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Recalc 6-bit to 8-bit and adjust for padding.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Decodes a Base64 encoded string into the buffer supplied by the caller.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @returns IPRT status code.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. pcbActual will not
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * be set, nor will ppszEnd.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @retval VERR_INVALID_BASE64_ENCODING if the encoding is wrong.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param pszString The Base64 string. Whether the entire string or
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * just the start of the string is in Base64 depends
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * on whether ppszEnd is specified or not.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param pvData Where to store the decoded data.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param cbData The size of the output buffer that pvData points to.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param pcbActual Where to store the actual number of bytes returned.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Optional.
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * @param ppszEnd Indicates that the string may contain other stuff
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * after the Base64 encoded data when not NULL. Will
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * be set to point to the first char that's not part of
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * the encoding. If NULL the entire string must be part
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * of the Base64 encoded data.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsyncRTDECL(int) RTBase64Decode(const char *pszString, void *pvData, size_t cbData, size_t *pcbActual, char **ppszEnd)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Process input in groups of 4 input / 3 output chars.
710a6316a22868b04400caf79719f96c18163cd3vboxsync uint8_t u8Trio[3] = { 0, 0, 0 }; /* shuts up gcc */
909b49e9391c03444e8aadbc0d9b5ff78669cfb2vboxsync unsigned c6Bits = 0;
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync /* The first 6-bit group. */
909b49e9391c03444e8aadbc0d9b5ff78669cfb2vboxsync while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync /* The second 6-bit group. */
909b49e9391c03444e8aadbc0d9b5ff78669cfb2vboxsync while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync /* The third 6-bit group. */
909b49e9391c03444e8aadbc0d9b5ff78669cfb2vboxsync while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync /* The fourth 6-bit group. */
909b49e9391c03444e8aadbc0d9b5ff78669cfb2vboxsync while ((u8 = g_au8CharToVal[ch = *pszString]) == BASE64_SPACE)
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync /* flush the trio */
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Padding can only be found at the end and there is
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * only 1 or 2 padding chars. Deal with it first.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync unsigned cbPad = 0;
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Invalid char and no where to indicate where the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Base64 text ends? Return failure.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Check padding vs. pending sextets, if anything left to do finish it off.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Set optional return values and return successfully.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Calculates the length of the Base64 encoding of a given number of bytes of
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * This will assume line breaks every 64 chars. A RTBase64EncodedLengthEx
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * function can be added if closer control over the output is found to be
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * required.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @returns The Base64 string length.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param cbData The number of bytes to encode.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync AssertReturn(sizeof(size_t) == sizeof(uint64_t), ~(size_t)0);
2400ef9ff1502b88791bf36bc8aeac8dfa57c91cvboxsync cch += ((cch - 1) / RTBASE64_LINE_LEN) * RTBASE64_EOL_SIZE;
2400ef9ff1502b88791bf36bc8aeac8dfa57c91cvboxsync cch += ((cch - 1) / RTBASE64_LINE_LEN) * RTBASE64_EOL_SIZE;
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * Encodes the specifed data into a Base64 string, the caller supplies the
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * output buffer.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * This will make the same assumptions about line breaks and EOL size as
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * RTBase64EncodedLength() does. A RTBase64EncodeEx function can be added if
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * more strict control over the output formatting is found necessary.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @returns IRPT status code.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @retval VERR_BUFFER_OVERFLOW if the output buffer is too small. The buffer
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * may contain an invalid Base64 string.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param pvData The data to encode.
b0ab7e3ff45cca3c9755432dde464562cdde61f0vboxsync * @param cbData The number of bytes to encode.
df5f1b4303be82a000284349e9392beb9f1b6f11vboxsync * @param pszBuf Where to put the Base64 string.
df5f1b4303be82a000284349e9392beb9f1b6f11vboxsync * @param cbBuf The size of the output buffer, including the terminator.
df5f1b4303be82a000284349e9392beb9f1b6f11vboxsync * @param pcchActual The actual number of characters returned.
df5f1b4303be82a000284349e9392beb9f1b6f11vboxsyncRTDECL(int) RTBase64Encode(const void *pvData, size_t cbData, char *pszBuf, size_t cbBuf, size_t *pcchActual)
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync * Process whole "trios" of input data.
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync /* encode */
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync pchDst[1] = g_szValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync pchDst[2] = g_szValToChar[((u8B << 2) & 0x3f) | (u8C >> 6)];
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync /* advance */
c0e1b51d9d294f2826624ff25a2b759aab3ef5f9vboxsync /* deal out linefeeds */
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync * Deal with the odd bytes and string termination.
9f9488dd30b14c1591d8bcad931ab508095217c9vboxsync pchDst[1] = g_szValToChar[((u8A << 4) & 0x3f) | (u8B >> 4)];