| /* |
| * Copyright 2015-2018 Rivoreo |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation, either version 3 of the License, or (at your |
| * option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| */ |
| |
| // Based on public domain code from Wikibooks |
| |
| #include "base64.h" |
| #include <stddef.h> |
| #include <stdint.h> |
| |
| int base64_encode(const void *data_buf, size_t data_len, char *result, size_t out_buffer_size, int flags) { |
| static const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| const uint8_t *data = (const uint8_t *)data_buf; |
| size_t out_i = 0; |
| size_t x; |
| uint32_t n = 0; |
| uint8_t n0, n1, n2, n3; |
| |
| /* Increment over the length of the string, three characters at a time */ |
| for (x = 0; x < data_len; x += 3) { |
| /* These three 8-bit (ASCII) characters become one 24-bit number */ |
| |
| /* parenthesis needed; compiler depending on flags can do the |
| shifting before conversion to uint32_t, resulting to 0 */ |
| n = ((uint32_t)data[x]) << 16; |
| |
| if((x+1) < data_len) { |
| /* parenthesis needed; compiler depending on flags |
| can do the shifting before conversion to uint32_t, |
| resulting to 0 */ |
| n += ((uint32_t)data[x+1]) << 8; |
| } |
| |
| if((x+2) < data_len) n += data[x+2]; |
| |
| /* this 24-bit number gets separated into four 6-bit numbers */ |
| n0 = (uint8_t)(n >> 18) & 63; |
| n1 = (uint8_t)(n >> 12) & 63; |
| n2 = (uint8_t)(n >> 6) & 63; |
| n3 = (uint8_t)n & 63; |
| |
| /* |
| * if we have one byte available, then its encoding is spread |
| * out over two characters |
| */ |
| if(out_i >= out_buffer_size) return -1; /* indicate failure: buffer too small */ |
| result[out_i++] = base64chars[n0]; |
| if(out_i >= out_buffer_size) return -1; /* indicate failure: buffer too small */ |
| result[out_i++] = base64chars[n1]; |
| |
| /* |
| * if we have only two bytes available, then their encoding is |
| * spread out over three chars |
| */ |
| if((x+1) < data_len) { |
| if(out_i >= out_buffer_size) return -1; /* indicate failure: buffer too small */ |
| result[out_i++] = base64chars[n2]; |
| } |
| |
| /* |
| * if we have all three bytes available, then their encoding is spread |
| * out over four characters |
| */ |
| if((x+2) < data_len) { |
| if(out_i >= out_buffer_size) return -1; /* indicate failure: buffer too small */ |
| result[out_i++] = base64chars[n3]; |
| } |
| } |
| |
| if(flags & BASE64_ADD_PADDING) { |
| /* |
| * Create and add padding that is required if we did not have a multiple of 3 |
| * number of characters available |
| */ |
| int pad_count = data_len % 3; |
| while(pad_count % 3) { |
| if(out_i >= out_buffer_size) return -1; |
| result[out_i++] = '='; |
| pad_count++; |
| } |
| } |
| |
| if(out_i >= out_buffer_size) return -1; /* indicate failure: buffer too small */ |
| result[out_i] = 0; |
| |
| return 0; /* indicate success */ |
| } |