From 4a4fd4582feb9497e3ffd348a2fc019a7910d214 Mon Sep 17 00:00:00 2001 From: Alastair Stuart Date: Fri, 3 May 2013 23:30:40 -0500 Subject: [PATCH] base64: Added base64 --- base64.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 base64.c diff --git a/base64.c b/base64.c new file mode 100644 index 0000000..28e733d --- /dev/null +++ b/base64.c @@ -0,0 +1,171 @@ +/* + Copyright © 2013 Alastair Stuart + + This program is open source 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. +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VERSION "0.01" + +const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +const int padding_table[] = {0, 2, 1}; + +void base64_encode_block(uint8_t in[3], char out[5]) +{ + uint8_t octet_a = in[0]; + uint8_t octet_b = in[1]; + uint8_t octet_c = in[2]; + + uint32_t combined = (octet_a << 16) + (octet_b << 8) + octet_c; + + out[0] = base64_table[(combined >> 3 * 6) & 0x3F]; + out[1] = base64_table[(combined >> 2 * 6) & 0x3F]; + out[2] = base64_table[(combined >> 1 * 6) & 0x3F]; + out[3] = base64_table[(combined >> 0 * 6) & 0x3F]; + out[4] = '\0'; +} + +void usage(char* program) +{ + printf("Usage: %s [options] [file]\n", program); + printf("Encodes a file into base64..\n" + "\n" + " -w, --wrap [num] Wrap lines after [num] characters.\n" + "\n" + " --help Print this message.\n" + " --version Show version info.\n"); +} + +int main(int argc, char* argv[]) +{ + size_t line_width = 0; + size_t wrap = 76; + static struct option long_options[] = { + {"wrap", required_argument, NULL, 'w'}, + {"help", no_argument, NULL, 1}, + {"version", no_argument, NULL, 2}, + {NULL, 0, NULL, 0} + }; + + int c = 0; + while ((c = getopt_long(argc, argv, "w:", + long_options, NULL)) != -1) + { + switch (c) + { + case 'w': + // check if wrap argument is a valid number + for (size_t i = 0; i < strlen(optarg); i++) + { + if (!isdigit(optarg[i])) { + fprintf(stderr, "%s: invalid wrap size: %s\n", + argv[0], optarg); + return 1; + } + } + wrap = atoi(optarg); + break; + case 1: + usage(argv[0]); + return 0; + case 2: + printf("base64 (mutos) v"VERSION"\n"); + return 0; + default: + printf("Run '%s --help' for usage.\n", + argv[0]); + return 1; + } + } + + FILE* input = NULL; + char* filename = NULL; + + if ((argc - optind) > 1) { + fprintf(stderr, "%s: extra operand: %s\n", + argv[0], argv[optind+1]); + return 1; + } else if ((argc - optind) < 1) { + input = stdin; + filename = "stdin"; + } else { + input = fopen(argv[optind], "rb"); + filename = argv[optind]; + } + + if (!input) { + fprintf(stderr, "%s: %s: %s\n", + argv[0], strerror(errno), filename); + return 1; + } + + bool last_block = false; + + size_t length = 0; + while (!last_block) + { + int eof_count = 0; + + int c = 0; + + uint8_t block[3] = {0}; + block[0] = (c = fgetc(input)) != EOF ? c : 0; + if (c != EOF) { length++; } else { eof_count++; } + block[1] = (c = fgetc(input)) != EOF ? c : 0; + if (c != EOF) { length++; } else { eof_count++; } + block[2] = (c = fgetc(input)) != EOF ? c : 0; + if (c != EOF) { length++; } else { eof_count++; } + + if (feof(input)) { + last_block = true; + } + + if (eof_count == 3) { + break; + } + + char encoded[5] = {'\0'}; + base64_encode_block(block, encoded); + + if (last_block) { + for (int i = 0; i < padding_table[length % 3]; i++) + { + encoded[3-i] = '='; + } + } + + for (size_t i = 0; i < 4; i++) + { + printf("%c", encoded[i]); + line_width++; + if (wrap != 0) { + if (line_width % wrap == 0) { + printf("\n"); + line_width = 0; + } + } + } + } + printf("\n"); + + fclose(input); + + return 0; +} -- 2.11.4.GIT