📄 base64.w
字号:
byte a[4], b[4], o[3]; for (i = 0; i < 4; i++) { int c = insig(); if (c == EOF) { if (errcheck && (i > 0)) { fprintf(stderr, "Input file incomplete.\n"); exit(1); } return; } if (dtable[c] & 0x80) { if (errcheck) { fprintf(stderr, "Illegal character '%c' in input file.\n", c); exit(1); } /* Ignoring errors: discard invalid character. */ i--; continue; } a[i] = (byte) c; b[i] = (byte) dtable[c]; } o[0] = (b[0] << 2) | (b[1] >> 4); o[1] = (b[1] << 4) | (b[2] >> 2); o[2] = (b[2] << 6) | b[3]; i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3); if (fwrite(o, i, 1, fo) == EOF) { exit(1); } if (i < 3) { return; } } @t\4@> @q Fix bad tab thanks to lint comment. @>}@ Procedure |initialise decode table| creates the lookup table used to map base64 characters into their binary values from 0 to 63. The table is built in this rather curious way in order to be properly initialised for both ASCII-based systems and those using EBCDIC, where the letters are not contiguous. (EBCDIC fixes courtesy of Ch.F.) In EBCDIC systems character codes for letters are not consecutive; the initialisation must be split to accommodate the EBCDIC consecutive letters: \centerline{ A--I J--R S--Z a--i j--r s--z} This code works on ASCII as well as EBCDIC systems.@<Initialise decode table@>= for (i = 0; i < 255; i++) { dtable[i] = 0x80; } for (i = 'A'; i <= 'I'; i++) { dtable[i] = 0 + (i - 'A'); } for (i = 'J'; i <= 'R'; i++) { dtable[i] = 9 + (i - 'J'); } for (i = 'S'; i <= 'Z'; i++) { dtable[i] = 18 + (i - 'S'); } for (i = 'a'; i <= 'i'; i++) { dtable[i] = 26 + (i - 'a'); } for (i = 'j'; i <= 'r'; i++) { dtable[i] = 35 + (i - 'j'); } for (i = 's'; i <= 'z'; i++) { dtable[i] = 44 + (i - 's'); } for (i = '0'; i <= '9'; i++) { dtable[i] = 52 + (i - '0'); } dtable['+'] = 62; dtable['/'] = 63; dtable['='] = 0;@** Utility functions.@ Procedure |usage|prints how-to-call information.@cstatic void usage(void){ printf("%s -- Encode/decode file as base64. Call:\n", PRODUCT); printf(" %s [-e / -d] [options] [infile] [outfile]\n", PRODUCT); printf("\n"); printf("Options:\n"); printf(" --copyright Print copyright information\n"); printf(" -d, --decode Decode base64 encoded file\n"); printf(" -e, --encode Encode file into base64\n"); printf(" -n, --noerrcheck Ignore errors when decoding\n"); printf(" -u, --help Print this message\n"); printf(" --version Print version number\n"); printf("\n"); printf("by John Walker\n"); printf("http://www.fourmilab.ch/\n");}@** Main program.@cint main(int argc, char *argv[]){ extern char *optarg; /* Imported from |getopt| */ extern int optind; int f, decoding = FALSE, opt;#ifdef FORCE_BINARY_IO int in_std = TRUE, out_std = TRUE;#endif char *cp; /* 2000-12-20 Ch.F. UNIX/390 C compiler (cc) does not allow initialisation of static variables with non static right-value during variable declaration; it was moved from declaration to main function start. */ fi = stdin; fo = stdout;@<Process command-line options@>;@\@<Process command-line arguments@>;@\@<Force binary I/O where required@>;@\ if (decoding) { decode(); } else { encode(); } return 0;}@We use |getopt| to process command line options. Thispermits aggregation of options without arguments andboth \.{-d}{\it arg} and \.{-d} {\it arg} syntax.@<Process command-line options@>= while ((opt = getopt(argc, argv, "denu-:")) != -1) { switch (opt) { case 'd': /* -d Decode */ decoding = TRUE; break; case 'e': /* -e Encode */ decoding = FALSE; break; case 'n': /* -n Suppress error checking */ errcheck = FALSE; break; case 'u': /* -u Print how-to-call information */ case '?': usage(); return 0; case '-': /* -- Extended options */ switch (optarg[0]) { case 'c': /* --copyright */ printf("This program is in the public domain.\n"); return 0; case 'd': /* --decode */ decoding = TRUE; break; case 'e': /* -encode */ decoding = FALSE; break; case 'h': /* --help */ usage(); return 0; case 'n': /* --noerrcheck */ errcheck = FALSE; break; case 'v': /* --version */ printf("%s %s\n", PRODUCT, VERSION); printf("Last revised: %s\n", REVDATE); printf("The latest version is always available\n"); printf("at http://www.fourmilab.ch/webtools/base64\n"); return 0; } } }@This code is executed after |getopt| has completed parsingcommand line options. At this point the external variable|optind| in |getopt| contains the index of the firstargument in the |argv[]| array.@<Process command-line arguments@>= f = 0; for (; optind < argc; optind++) { cp = argv[optind]; switch (f) { /** Warning! On systems which distinguish text mode and binary I/O (MS-DOS, Macintosh, etc.) the modes in these open statements will have to be made conditional based upon whether an encode or decode is being done, which will have to be specified earlier. But it's worse: if input or output is from standard input or output, the mode will have to be changed on the fly, which is generally system and compiler dependent. 'Twasn't me who couldn't conform to Unix CR/LF convention, so don't ask me to write the code to work around Apple and Microsoft's incompatible standards. **/ case 0: if (strcmp(cp, "-") != 0) { if ((fi = fopen(cp,#ifdef FORCE_BINARY_IO decoding ? "r" : "rb"#else "r"#endif )) == NULL) { fprintf(stderr, "Cannot open input file %s\n", cp); return 2; }#ifdef FORCE_BINARY_IO in_std = FALSE;#endif } f++; break; case 1: if (strcmp(cp, "-") != 0) { if ((fo = fopen(cp,#ifdef FORCE_BINARY_IO decoding ? "wb" : "w"#else "w"#endif )) == NULL) { fprintf(stderr, "Cannot open output file %s\n", cp); return 2; }#ifdef FORCE_BINARY_IO out_std = FALSE;#endif } f++; break; default: fprintf(stderr, "Too many file names specified.\n"); usage(); return 2; } }@On WIN32, if the binary stream is the default of \.{stdin}/\.{stdout},we must place this stream, opened in text mode (translationof CR to CR/LF) by default, into binary mode (no EOLtranslation). If you port this code to other platformswhich distinguish between text and binary file I/O(for example, the Macintosh), you'll need to add equivalentcode here.The following code sets the already-open standard stream tobinary mode on Microsoft Visual C 5.0 (Monkey C). If you'reusing a different version or compiler, you may need someother incantation to cancel the text translation spell.@<Force binary I/O where required@>=#ifdef FORCE_BINARY_IO if ((decoding && out_std) || ((!decoding) && in_std)) {#ifdef _WIN32 _setmode(_fileno(decoding ? fo : fi), O_BINARY);#endif }#endif@** Index.The following is a cross-reference table for \.{base64}.Single-character identifiers are not indexed, nor arereserved words. Underlined entries indicate wherean identifier was declared.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -