btoa.c (5933B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #include "plgetopt.h" 6 #include "secutil.h" 7 #include "nssb64.h" 8 #include <errno.h> 9 10 #if defined(XP_WIN) || (defined(__sun) && !defined(SVR4)) 11 #if !defined(WIN32) 12 extern int fread(char *, size_t, size_t, FILE *); 13 extern int fwrite(char *, size_t, size_t, FILE *); 14 extern int fprintf(FILE *, char *, ...); 15 #endif 16 #endif 17 18 #if defined(WIN32) 19 #include "fcntl.h" 20 #include "io.h" 21 #endif 22 23 static PRInt32 24 output_ascii(void *arg, const char *obuf, PRInt32 size) 25 { 26 FILE *outFile = arg; 27 int nb; 28 29 nb = fwrite(obuf, 1, size, outFile); 30 if (nb != size) { 31 PORT_SetError(SEC_ERROR_IO); 32 return -1; 33 } 34 35 return nb; 36 } 37 38 static SECStatus 39 encode_file(FILE *outFile, FILE *inFile) 40 { 41 NSSBase64Encoder *cx; 42 int nb; 43 SECStatus status = SECFailure; 44 unsigned char ibuf[4096]; 45 46 cx = NSSBase64Encoder_Create(output_ascii, outFile); 47 if (!cx) { 48 return -1; 49 } 50 51 for (;;) { 52 if (feof(inFile)) 53 break; 54 nb = fread(ibuf, 1, sizeof(ibuf), inFile); 55 if (nb != sizeof(ibuf)) { 56 if (nb == 0) { 57 if (ferror(inFile)) { 58 PORT_SetError(SEC_ERROR_IO); 59 goto loser; 60 } 61 /* eof */ 62 break; 63 } 64 } 65 66 status = NSSBase64Encoder_Update(cx, ibuf, nb); 67 if (status != SECSuccess) 68 goto loser; 69 } 70 71 status = NSSBase64Encoder_Destroy(cx, PR_FALSE); 72 if (status != SECSuccess) 73 return status; 74 75 /* 76 * Add a trailing CRLF. Note this must be done *after* the call 77 * to Destroy above (because only then are we sure all data has 78 * been written out). 79 */ 80 fwrite("\r\n", 1, 2, outFile); 81 return SECSuccess; 82 83 loser: 84 (void)NSSBase64Encoder_Destroy(cx, PR_TRUE); 85 return status; 86 } 87 88 static void 89 Usage(char *progName) 90 { 91 fprintf(stderr, 92 "Usage: %s [-i input] [-o output]\n", 93 progName); 94 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", 95 "-i input"); 96 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", 97 "-o output"); 98 fprintf(stderr, "%-20s Wrap output in BEGIN/END lines and the given suffix\n", 99 "-w suffix"); 100 fprintf(stderr, "%-20s (use \"c\" as a shortcut for suffix CERTIFICATE)\n", 101 ""); 102 } 103 104 int 105 main(int argc, char **argv) 106 { 107 char *progName; 108 SECStatus rv; 109 FILE *inFile = NULL, *outFile = NULL; 110 PRBool closeIn = PR_TRUE, closeOut = PR_TRUE; 111 PLOptState *optstate = NULL; 112 PLOptStatus status; 113 char *suffix = NULL; 114 int exitCode = -1; 115 116 progName = strrchr(argv[0], '/'); 117 if (!progName) 118 progName = strrchr(argv[0], '\\'); 119 progName = progName ? progName + 1 : argv[0]; 120 121 /* Parse command line arguments */ 122 optstate = PL_CreateOptState(argc, argv, "i:o:w:"); 123 PORT_Assert(optstate); 124 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { 125 switch (optstate->option) { 126 default: 127 Usage(progName); 128 goto loser; 129 break; 130 131 case 'i': 132 inFile = fopen(optstate->value, "rb"); 133 if (!inFile) { 134 fprintf(stderr, "%s: unable to open \"%s\" for reading\n", 135 progName, optstate->value); 136 goto loser; 137 } 138 break; 139 140 case 'o': 141 outFile = fopen(optstate->value, "wb"); 142 if (!outFile) { 143 fprintf(stderr, "%s: unable to open \"%s\" for writing\n", 144 progName, optstate->value); 145 goto loser; 146 } 147 break; 148 149 case 'w': 150 if (!strcmp(optstate->value, "c")) 151 suffix = strdup("CERTIFICATE"); 152 else 153 suffix = strdup(optstate->value); 154 break; 155 } 156 } 157 if (status == PL_OPT_BAD) 158 Usage(progName); 159 if (!inFile) { 160 #if defined(WIN32) 161 /* If we're going to read binary data from stdin, we must put stdin 162 ** into O_BINARY mode or else incoming \r\n's will become \n's. 163 */ 164 165 int smrv = _setmode(_fileno(stdin), _O_BINARY); 166 if (smrv == -1) { 167 fprintf(stderr, 168 "%s: Cannot change stdin to binary mode. Use -i option instead.\n", 169 progName); 170 goto loser; 171 } 172 #endif 173 inFile = stdin; 174 closeIn = PR_FALSE; 175 } 176 if (!outFile) { 177 #if defined(WIN32) 178 /* We're going to write binary data to stdout. We must put stdout 179 ** into O_BINARY mode or else outgoing \r\n's will become \r\r\n's. 180 */ 181 182 int smrv = _setmode(_fileno(stdout), _O_BINARY); 183 if (smrv == -1) { 184 fprintf(stderr, 185 "%s: Cannot change stdout to binary mode. Use -o option instead.\n", 186 progName); 187 goto loser; 188 } 189 #endif 190 outFile = stdout; 191 closeOut = PR_FALSE; 192 } 193 if (suffix) { 194 fprintf(outFile, "-----BEGIN %s-----\n", suffix); 195 } 196 rv = encode_file(outFile, inFile); 197 if (rv != SECSuccess) { 198 fprintf(stderr, "%s: lossage: error=%d errno=%d\n", 199 progName, PORT_GetError(), errno); 200 goto loser; 201 } 202 if (suffix) { 203 fprintf(outFile, "-----END %s-----\n", suffix); 204 } 205 exitCode = 0; 206 loser: 207 PL_DestroyOptState(optstate); 208 if (inFile && closeIn) { 209 fclose(inFile); 210 } 211 if (outFile && closeOut) { 212 fclose(outFile); 213 } 214 if (suffix) { 215 PORT_Free(suffix); 216 } 217 return exitCode; 218 }