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
output_binary(void * arg,const unsigned char * obuf,PRInt32 size)24 output_binary(void *arg, const unsigned 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 PRBool
isBase64Char(char c)39 isBase64Char(char c)
40 {
41 return ((c >= 'A' && c <= 'Z') ||
42 (c >= 'a' && c <= 'z') ||
43 (c >= '0' && c <= '9') ||
44 c == '+' || c == '/' ||
45 c == '=');
46 }
47
48 static SECStatus
decode_file(FILE * outFile,FILE * inFile)49 decode_file(FILE *outFile, FILE *inFile)
50 {
51 NSSBase64Decoder *cx;
52 SECStatus status = SECFailure;
53 char ibuf[4096];
54 const char *ptr;
55
56 cx = NSSBase64Decoder_Create(output_binary, outFile);
57 if (!cx) {
58 return -1;
59 }
60
61 for (;;) {
62 if (feof(inFile))
63 break;
64 if (!fgets(ibuf, sizeof(ibuf), inFile)) {
65 if (ferror(inFile)) {
66 PORT_SetError(SEC_ERROR_IO);
67 goto loser;
68 }
69 /* eof */
70 break;
71 }
72 for (ptr = ibuf; *ptr; ++ptr) {
73 char c = *ptr;
74 if (c == '\n' || c == '\r') {
75 break; /* found end of line */
76 }
77 if (!isBase64Char(c)) {
78 ptr = ibuf; /* ignore line */
79 break;
80 }
81 }
82 if (ibuf == ptr) {
83 continue; /* skip empty or non-base64 line */
84 }
85
86 status = NSSBase64Decoder_Update(cx, ibuf, ptr - ibuf);
87 if (status != SECSuccess)
88 goto loser;
89 }
90
91 return NSSBase64Decoder_Destroy(cx, PR_FALSE);
92
93 loser:
94 (void)NSSBase64Decoder_Destroy(cx, PR_TRUE);
95 return status;
96 }
97
98 static void
Usage(char * progName)99 Usage(char *progName)
100 {
101 fprintf(stderr,
102 "Usage: %s [-i input] [-o output]\n",
103 progName);
104 fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n",
105 "-i input");
106 fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n",
107 "-o output");
108 }
109
110 int
main(int argc,char ** argv)111 main(int argc, char **argv)
112 {
113 char *progName;
114 SECStatus rv;
115 FILE *inFile = NULL, *outFile = NULL;
116 PRBool closeIn = PR_TRUE, closeOut = PR_TRUE;
117 PLOptState *optstate = NULL;
118 PLOptStatus status;
119 int exitCode = -1;
120
121 progName = strrchr(argv[0], '/');
122 progName = progName ? progName + 1 : argv[0];
123
124 /* Parse command line arguments */
125 optstate = PL_CreateOptState(argc, argv, "?hi:o:");
126 while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) {
127 switch (optstate->option) {
128 case '?':
129 case 'h':
130 Usage(progName);
131 goto loser;
132 break;
133
134 case 'i':
135 inFile = fopen(optstate->value, "r");
136 if (!inFile) {
137 fprintf(stderr, "%s: unable to open \"%s\" for reading\n",
138 progName, optstate->value);
139 goto loser;
140 }
141 break;
142
143 case 'o':
144 outFile = fopen(optstate->value, "wb");
145 if (!outFile) {
146 fprintf(stderr, "%s: unable to open \"%s\" for writing\n",
147 progName, optstate->value);
148 goto loser;
149 }
150 break;
151 }
152 }
153 if (!inFile) {
154 inFile = stdin;
155 closeIn = PR_FALSE;
156 }
157 if (!outFile) {
158 #if defined(WIN32)
159 int smrv = _setmode(_fileno(stdout), _O_BINARY);
160 if (smrv == -1) {
161 fprintf(stderr,
162 "%s: Cannot change stdout to binary mode. Use -o option instead.\n",
163 progName);
164 goto loser;
165 }
166 #endif
167 outFile = stdout;
168 closeOut = PR_FALSE;
169 }
170 rv = decode_file(outFile, inFile);
171 if (rv != SECSuccess) {
172 fprintf(stderr, "%s: lossage: error=%d errno=%d\n",
173 progName, PORT_GetError(), errno);
174 goto loser;
175 }
176 exitCode = 0;
177 loser:
178 if (optstate) {
179 PL_DestroyOptState(optstate);
180 }
181 if (inFile && closeIn) {
182 fclose(inFile);
183 }
184 if (outFile && closeOut) {
185 fclose(outFile);
186 }
187 return exitCode;
188 }
189