Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / core / base64.c
1 /*
2  * Copyright (C) 2009 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  */
19
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdint.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <assert.h>
27 #include <ipxe/base64.h>
28
29 /** @file
30  *
31  * Base64 encoding
32  *
33  */
34
35 static const char base64[64] =
36         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
37
38 /**
39  * Base64-encode data
40  *
41  * @v raw               Raw data
42  * @v len               Length of raw data
43  * @v encoded           Buffer for encoded string
44  *
45  * The buffer must be the correct length for the encoded string.  Use
46  * something like
47  *
48  *     char buf[ base64_encoded_len ( len ) + 1 ];
49  *
50  * (the +1 is for the terminating NUL) to provide a buffer of the
51  * correct size.
52  */
53 void base64_encode ( const uint8_t *raw, size_t len, char *encoded ) {
54         const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
55         uint8_t *encoded_bytes = ( ( uint8_t * ) encoded );
56         size_t raw_bit_len = ( 8 * len );
57         unsigned int bit;
58         unsigned int byte;
59         unsigned int shift;
60         unsigned int tmp;
61
62         for ( bit = 0 ; bit < raw_bit_len ; bit += 6 ) {
63                 byte = ( bit / 8 );
64                 shift = ( bit % 8 );
65                 tmp = ( raw_bytes[byte] << shift );
66                 if ( ( byte + 1 ) < len )
67                         tmp |= ( raw_bytes[ byte + 1 ] >> ( 8 - shift ) );
68                 tmp = ( ( tmp >> 2 ) & 0x3f );
69                 *(encoded_bytes++) = base64[tmp];
70         }
71         for ( ; ( bit % 8 ) != 0 ; bit += 6 )
72                 *(encoded_bytes++) = '=';
73         *(encoded_bytes++) = '\0';
74
75         DBG ( "Base64-encoded to \"%s\":\n", encoded );
76         DBG_HDA ( 0, raw, len );
77         assert ( strlen ( encoded ) == base64_encoded_len ( len ) );
78 }
79
80 /**
81  * Base64-decode string
82  *
83  * @v encoded           Encoded string
84  * @v raw               Raw data
85  * @ret len             Length of raw data, or negative error
86  *
87  * The buffer must be large enough to contain the decoded data.  Use
88  * something like
89  *
90  *     char buf[ base64_decoded_max_len ( encoded ) ];
91  *
92  * to provide a buffer of the correct size.
93  */
94 int base64_decode ( const char *encoded, uint8_t *raw ) {
95         const uint8_t *encoded_bytes = ( ( const uint8_t * ) encoded );
96         uint8_t *raw_bytes = ( ( uint8_t * ) raw );
97         uint8_t encoded_byte;
98         char *match;
99         int decoded;
100         unsigned int bit = 0;
101         unsigned int pad_count = 0;
102         size_t len;
103
104         /* Zero the raw data */
105         memset ( raw, 0, base64_decoded_max_len ( encoded ) );
106
107         /* Decode string */
108         while ( ( encoded_byte = *(encoded_bytes++) ) ) {
109
110                 /* Ignore whitespace characters */
111                 if ( isspace ( encoded_byte ) )
112                         continue;
113
114                 /* Process pad characters */
115                 if ( encoded_byte == '=' ) {
116                         if ( pad_count >= 2 ) {
117                                 DBG ( "Base64-encoded string \"%s\" has too "
118                                       "many pad characters\n", encoded );
119                                 return -EINVAL;
120                         }
121                         pad_count++;
122                         bit -= 2; /* unused_bits = ( 2 * pad_count ) */
123                         continue;
124                 }
125                 if ( pad_count ) {
126                         DBG ( "Base64-encoded string \"%s\" has invalid pad "
127                               "sequence\n", encoded );
128                         return -EINVAL;
129                 }
130
131                 /* Process normal characters */
132                 match = strchr ( base64, encoded_byte );
133                 if ( ! match ) {
134                         DBG ( "Base64-encoded string \"%s\" contains invalid "
135                               "character '%c'\n", encoded, encoded_byte );
136                         return -EINVAL;
137                 }
138                 decoded = ( match - base64 );
139
140                 /* Add to raw data */
141                 decoded <<= 2;
142                 raw_bytes[ bit / 8 ] |= ( decoded >> ( bit % 8 ) );
143                 raw_bytes[ bit / 8 + 1 ] |= ( decoded << ( 8 - ( bit % 8 ) ) );
144                 bit += 6;
145         }
146
147         /* Check that we decoded a whole number of bytes */
148         if ( ( bit % 8 ) != 0 ) {
149                 DBG ( "Base64-encoded string \"%s\" has invalid bit length "
150                       "%d\n", encoded, bit );
151                 return -EINVAL;
152         }
153         len = ( bit / 8 );
154
155         DBG ( "Base64-decoded \"%s\" to:\n", encoded );
156         DBG_HDA ( 0, raw, len );
157         assert ( len <= base64_decoded_max_len ( encoded ) );
158
159         /* Return length in bytes */
160         return ( len );
161 }