1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the copyright holder nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
15
16THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28#include "rtp_base64.h"
29
30/******************************************************************************
31Defines and constants.
32******************************************************************************/
33
34#define LOWEST_BASE64_CHAR '+'
35#define HIGHEST_BASE64_CHAR 'z'
36#define IN_BASE64_RANGE(C) ((C) >= LOWEST_BASE64_CHAR && (C) <= HIGHEST_BASE64_CHAR)
37
38/** Used as a marker in the lookup table to indicate an invalid Base64 character */
39#define INVALID 0xFF
40
41/* Reduced lookup table for translating a character to a 6-bit value. The
42 * table starts at the lowest Base64 character, '+' */
43uint8_t base64_decode_lookup[] = {
44 62, INVALID, 62, INVALID, 63, /* '+' to '/' */
45 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, /* '0' to '9' */
46 INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, /* ':' to '@' */
47 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, /* 'A' to 'T' */
48 20, 21, 22, 23, 24, 25, /* 'U' to 'Z' */
49 INVALID, INVALID, INVALID, INVALID, 63, INVALID, /* '[' to '`' */
50 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, /* 'a' to 'r' */
51 44, 45, 46, 47, 48, 49, 50, 51 /* 's' to 'z' */
52};
53
54/******************************************************************************
55Type definitions
56******************************************************************************/
57
58/******************************************************************************
59Function prototypes
60******************************************************************************/
61
62/******************************************************************************
63Local Functions
64******************************************************************************/
65
66/*****************************************************************************
67Functions exported as part of the Base64 API
68 *****************************************************************************/
69
70/*****************************************************************************/
71uint32_t rtp_base64_byte_length(const char *str, uint32_t str_len)
72{
73 uint32_t character_count = 0;
74 uint32_t ii;
75 char cc;
76
77 /* Scan through string until either a pad ('=') character or the end is
78 * reached. Ignore characters that are not part of the Base64 alphabet.
79 * Number of bytes should then be 3/4 of the character count. */
80
81 for (ii = 0; ii < str_len; ii++)
82 {
83 cc = *str++;
84 if (cc == '=')
85 break; /* Found a pad character: stop */
86
87 if (!IN_BASE64_RANGE(cc))
88 continue; /* Ignore invalid character */
89
90 if (base64_decode_lookup[cc - LOWEST_BASE64_CHAR] != INVALID)
91 character_count++;
92 }
93
94 return (character_count * 3) >> 2;
95}
96
97/*****************************************************************************/
98uint8_t *rtp_base64_decode(const char *str, uint32_t str_len, uint8_t *buffer, uint32_t buffer_len)
99{
100 uint32_t character_count = 0;
101 uint32_t value = 0;
102 uint32_t ii;
103 char cc;
104 uint8_t lookup;
105
106 /* Build up sets of four characters (ignoring invalid ones) to generate
107 * triplets of bytes, until either the end of the string or the pad ('=')
108 * characters are reached. */
109
110 for (ii = 0; ii < str_len; ii++)
111 {
112 cc = *str++;
113 if (cc == '=')
114 break; /* Found a pad character: stop */
115
116 if (!IN_BASE64_RANGE(cc))
117 continue; /* Ignore invalid character */
118
119 lookup = base64_decode_lookup[cc - LOWEST_BASE64_CHAR];
120 if (lookup == INVALID)
121 continue; /* Ignore invalid character */
122
123 value = (value << 6) | lookup;
124 character_count++;
125
126 if (character_count == 4)
127 {
128 if (buffer_len < 3)
129 return NULL; /* Not enough room in the output buffer */
130
131 *buffer++ = (uint8_t)(value >> 16);
132 *buffer++ = (uint8_t)(value >> 8);
133 *buffer++ = (uint8_t)(value );
134 buffer_len -= 3;
135
136 character_count = 0;
137 value = 0;
138 }
139 }
140
141 /* If there were extra characters on the end, these need to be handled to get
142 * the last one or two bytes. */
143
144 switch (character_count)
145 {
146 case 0: /* Nothing more to do, the final bytes were converted in the loop */
147 break;
148 case 2: /* One additional byte, padded with four zero bits */
149 if (!buffer_len)
150 return NULL;
151 *buffer++ = (uint8_t)(value >> 4);
152 break;
153 case 3: /* Two additional bytes, padded with two zero bits */
154 if (buffer_len < 2)
155 return NULL;
156 *buffer++ = (uint8_t)(value >> 10);
157 *buffer++ = (uint8_t)(value >> 2);
158 break;
159 default: /* This is an invalid Base64 encoding */
160 return NULL;
161 }
162
163 /* Return number of bytes written to the buffer */
164 return buffer;
165}
166