📄 base64.java
字号:
/* * Base64 encoding and decoding. * Copyright (C) 2001-2002 Stephen Ostermiller * http://ostermiller.org/contact.pl?regarding=Java+Utilities * * 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 2 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. * * See COPYING.TXT for details. */package com.Ostermiller.util;import java.io.*;import gnu.getopt.*;import java.text.MessageFormat;import java.util.ResourceBundle;import java.util.Locale;/** * Implements Base64 encoding and decoding as defined by RFC 2045: "Multipurpose Internet * Mail Extensions (MIME) Part One: Format of Internet Message Bodies" page 23. * More information about this class is available from <a target="_top" href= * "http://ostermiller.org/utils/Base64.html">ostermiller.org</a>. * * <blockquote> * <p>The Base64 Content-Transfer-Encoding is designed to represent * arbitrary sequences of octets in a form that need not be humanly * readable. The encoding and decoding algorithms are simple, but the * encoded data are consistently only about 33 percent larger than the * unencoded data. This encoding is virtually identical to the one used * in Privacy Enhanced Mail (PEM) applications, as defined in RFC 1421.</p> * * <p>A 65-character subset of US-ASCII is used, enabling 6 bits to be * represented per printable character. (The extra 65th character, "=", * is used to signify a special processing function.)</p> * * <p>NOTE: This subset has the important property that it is represented * identically in all versions of ISO 646, including US-ASCII, and all * characters in the subset are also represented identically in all * versions of EBCDIC. Other popular encodings, such as the encoding * used by the uuencode utility, Macintosh binhex 4.0 [RFC-1741], and * the base85 encoding specified as part of Level 2 PostScript, do no * share these properties, and thus do not fulfill the portability * requirements a binary transport encoding for mail must meet.</p> * * <p>The encoding process represents 24-bit groups of input bits as output * strings of 4 encoded characters. Proceeding from left to right, a * 24-bit input group is formed by concatenating 3 8bit input groups. * These 24 bits are then treated as 4 concatenated 6-bit groups, each * of which is translated into a single digit in the base64 alphabet. * When encoding a bit stream via the base64 encoding, the bit stream * must be presumed to be ordered with the most-significant-bit first. * That is, the first bit in the stream will be the high-order bit in * the first 8bit byte, and the eighth bit will be the low-order bit in * the first 8bit byte, and so on.</p> * * <p>Each 6-bit group is used as an index into an array of 64 printable * characters. The character referenced by the index is placed in the * output string. These characters, identified in Table 1, below, are * selected so as to be universally representable, and the set excludes * characters with particular significance to SMTP (e.g., ".", CR, LF) * and to the multipart boundary delimiters defined in RFC 2046 (e.g., * "-").</p> * <pre> * Table 1: The Base64 Alphabet * * Value Encoding Value Encoding Value Encoding Value Encoding * 0 A 17 R 34 i 51 z * 1 B 18 S 35 j 52 0 * 2 C 19 T 36 k 53 1 * 3 D 20 U 37 l 54 2 * 4 E 21 V 38 m 55 3 * 5 F 22 W 39 n 56 4 * 6 G 23 X 40 o 57 5 * 7 H 24 Y 41 p 58 6 * 8 I 25 Z 42 q 59 7 * 9 J 26 a 43 r 60 8 * 10 K 27 b 44 s 61 9 * 11 L 28 c 45 t 62 + * 12 M 29 d 46 u 63 / * 13 N 30 e 47 v * 14 O 31 f 48 w (pad) = * 15 P 32 g 49 x * 16 Q 33 h 50 y * </pre> * <p>The encoded output stream must be represented in lines of no more * than 76 characters each. All line breaks or other characters no * found in Table 1 must be ignored by decoding software. In base64 * data, characters other than those in Table 1, line breaks, and other * white space probably indicate a transmission error, about which a * warning message or even a message rejection might be appropriate * under some circumstances.</p> * * <p>Special processing is performed if fewer than 24 bits are available * at the end of the data being encoded. A full encoding quantum is * always completed at the end of a body. When fewer than 24 input bits * are available in an input group, zero bits are added (on the right) * to form an integral number of 6-bit groups. Padding at the end of * the data is performed using the "=" character. Since all base64 * input is an integral number of octets, only the following cases can * arise: (1) the final quantum of encoding input is an integral * multiple of 24 bits; here, the final unit of encoded output will be * an integral multiple of 4 characters with no "=" padding, (2) the * final quantum of encoding input is exactly 8 bits; here, the final * unit of encoded output will be two characters followed by two "=" * padding characters, or (3) the final quantum of encoding input is * exactly 16 bits; here, the final unit of encoded output will be three * characters followed by one "=" padding character.</p> * * <p>Because it is used only for padding at the end of the data, the * occurrence of any "=" characters may be taken as evidence that the * end of the data has been reached (without truncation in transit). No * such assurance is possible, however, when the number of octets * transmitted was a multiple of three and no "=" characters are * present.</p> * * <p>Any characters outside of the base64 alphabet are to be ignored in * base64-encoded data.</p> * * <p>Care must be taken to use the proper octets for line breaks if base64 * encoding is applied directly to text material that has not been * converted to canonical form. In particular, text line breaks must be * converted into CRLF sequences prior to base64 encoding. The * important thing to note is that this may be done directly by the * encoder rather than in a prior canonicalization step in some * implementations.</p> * * <p>NOTE: There is no need to worry about quoting potential boundary * delimiters within base64-encoded bodies within multipart entities * because no hyphen characters are used in the base64 encoding.</p> * </blockquote> * * @author Stephen Ostermiller http://ostermiller.org/contact.pl?regarding=Java+Utilities * @since ostermillerutils 1.00.00 */public class Base64 { /** * Symbol that represents the end of an input stream * * @since ostermillerutils 1.00.00 */ private static final int END_OF_INPUT = -1; /** * A character that is not a valid base 64 character. * * @since ostermillerutils 1.00.00 */ private static final int NON_BASE_64 = -1; /** * A character that is not a valid base 64 character. * * @since ostermillerutils 1.00.00 */ private static final int NON_BASE_64_WHITESPACE = -2; /** * A character that is not a valid base 64 character. * * @since ostermillerutils 1.00.00 */ private static final int NON_BASE_64_PADDING = -3; /** * This class need not be instantiated, all methods are static. * * @since ostermillerutils 1.00.00 */ private Base64(){ } /** * Table of the sixty-four characters that are used as * the Base64 alphabet: [A-Za-z0-9+/] * * @since ostermillerutils 1.00.00 */ protected static final byte[] base64Chars = { 'A','B','C','D','E','F','G','H', 'I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X', 'Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n', 'o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3', '4','5','6','7','8','9','+','/', }; /** * Reverse lookup table for the Base64 alphabet. * reversebase64Chars[byte] gives n for the nth Base64 * character or negative if a character is not a Base64 character. * * @since ostermillerutils 1.00.00 */ protected static final byte[] reverseBase64Chars = new byte[0x100]; static { // Fill in NON_BASE_64 for all characters to start with for (int i=0; i<reverseBase64Chars.length; i++){ reverseBase64Chars[i] = NON_BASE_64; } // For characters that are base64Chars, adjust // the reverse lookup table. for (byte i=0; i < base64Chars.length; i++){ reverseBase64Chars[base64Chars[i]] = i; } reverseBase64Chars[' '] = NON_BASE_64_WHITESPACE; reverseBase64Chars['\n'] = NON_BASE_64_WHITESPACE; reverseBase64Chars['\r'] = NON_BASE_64_WHITESPACE; reverseBase64Chars['\t'] = NON_BASE_64_WHITESPACE; reverseBase64Chars['\f'] = NON_BASE_64_WHITESPACE; reverseBase64Chars['='] = NON_BASE_64_PADDING; } /** * Version number of this program * * @since ostermillerutils 1.00.00 */ public static final String version = "1.2"; /** * Locale specific strings displayed to the user. * * @since ostermillerutils 1.00.00 */ protected static ResourceBundle labels = ResourceBundle.getBundle("com.Ostermiller.util.Base64", Locale.getDefault()); private static final int ACTION_GUESS = 0; private static final int ACTION_ENCODE = 1; private static final int ACTION_DECODE = 2; private static final int ARGUMENT_GUESS = 0; private static final int ARGUMENT_STRING = 1; private static final int ARGUMENT_FILE = 2; /** * Converts the line ending on files, or standard input. * Run with --help argument for more information. * * @param args Command line arguments. * * @since ostermillerutils 1.00.00 */ public static void main(String[] args){ // create the command line options that we are looking for LongOpt[] longopts = { new LongOpt(labels.getString("help.option"), LongOpt.NO_ARGUMENT, null, 1), new LongOpt(labels.getString("version.option"), LongOpt.NO_ARGUMENT, null, 2), new LongOpt(labels.getString("about.option"), LongOpt.NO_ARGUMENT, null, 3), new LongOpt(labels.getString("encode.option"), LongOpt.NO_ARGUMENT, null, 'e'), new LongOpt(labels.getString("lines.option"), LongOpt.NO_ARGUMENT, null, 'l'), new LongOpt(labels.getString("nolines.option"), LongOpt.NO_ARGUMENT, null, 6), new LongOpt(labels.getString("decode.option"), LongOpt.NO_ARGUMENT, null, 'd'), new LongOpt(labels.getString("decodeall.option"), LongOpt.NO_ARGUMENT, null, 'a'), new LongOpt(labels.getString("decodegood.option"), LongOpt.NO_ARGUMENT, null, 5), new LongOpt(labels.getString("guess.option"), LongOpt.NO_ARGUMENT, null, 'g'), new LongOpt(labels.getString("ext.option"), LongOpt.OPTIONAL_ARGUMENT, null, 'x'), new LongOpt(labels.getString("force.option"), LongOpt.NO_ARGUMENT, null, 'f'), new LongOpt(labels.getString("quiet.option"), LongOpt.NO_ARGUMENT, null, 'q'), new LongOpt(labels.getString("reallyquiet.option"), LongOpt.NO_ARGUMENT, null, 'Q'), new LongOpt(labels.getString("verbose.option"), LongOpt.NO_ARGUMENT, null, 'v'), new LongOpt(labels.getString("noforce.option"), LongOpt.NO_ARGUMENT, null, 4), new LongOpt(labels.getString("file.option"), LongOpt.NO_ARGUMENT, null, 7), new LongOpt(labels.getString("string.option"), LongOpt.NO_ARGUMENT, null, 8), new LongOpt(labels.getString("newline.option"), LongOpt.NO_ARGUMENT, null, 'n'), new LongOpt(labels.getString("nonewline.option"), LongOpt.NO_ARGUMENT, null, 9), }; String oneLetterOptions = "eldagx::fqQvVn"; Getopt opts = new Getopt(labels.getString("base64"), args, oneLetterOptions, longopts); int action = ACTION_GUESS; String extension = "base64"; boolean force = false; boolean printMessages = true; boolean printErrors = true; boolean forceDecode = false; boolean lineBreaks = true; int argumentType = ARGUMENT_GUESS; boolean decodeEndLine = false; int c; while ((c = opts.getopt()) != -1){ switch(c){ case 1:{ // print out the help message String[] helpFlags = new String[]{ "--" + labels.getString("help.option"), "--" + labels.getString("version.option"), "--" + labels.getString("about.option"), "-g --" + labels.getString("guess.option"), "-e --" + labels.getString("encode.option"), "-l --" + labels.getString("lines.option"), "--" + labels.getString("nolines.option"), "-d --" + labels.getString("decode.option"), "-a --" + labels.getString("decodeall.option"), "--" + labels.getString("decodegood.option"), "-x --" + labels.getString("ext.option") + " <" + labels.getString("ext.option") + ">", "-f --" + labels.getString("force.option"), "--" + labels.getString("noforce.option"), "-v --" + labels.getString("verbose.option"), "-q --" + labels.getString("quiet.option"), "-Q --" + labels.getString("reallyquiet.option"), "--" + labels.getString("file.option"), "--" + labels.getString("string.option"), "-n --" + labels.getString("newline.option"), "--" + labels.getString("nonewline.option"), }; int maxLength = 0; for (int i=0; i<helpFlags.length; i++){ maxLength = Math.max(maxLength, helpFlags[i].length()); } maxLength += 2; System.out.println( labels.getString("base64") + " [-" + StringHelper.replace(oneLetterOptions, ":", "") + "] <" + labels.getString("files") + ">\n" + labels.getString("purpose.message") + "\n" + " " + labels.getString("stdin.message") + "\n" + " " + StringHelper.postpad(helpFlags[0] ,maxLength, ' ') + labels.getString("help.message") + "\n" + " " + StringHelper.postpad(helpFlags[1] ,maxLength, ' ') + labels.getString("version.message") + "\n" + " " + StringHelper.postpad(helpFlags[2] ,maxLength, ' ') + labels.getString("about.message") + "\n" + " " + StringHelper.postpad(helpFlags[3] ,maxLength, ' ') + labels.getString("g.message") + " (" + labels.getString("default") + ")\n" + " " + StringHelper.postpad(helpFlags[4] ,maxLength, ' ') + labels.getString("e.message") + "\n" + " " + StringHelper.postpad(helpFlags[5] ,maxLength, ' ') + labels.getString("l.message") + " (" + labels.getString("default") + ")\n" + " " + StringHelper.postpad(helpFlags[6] ,maxLength, ' ') + labels.getString("nolines.message") + "\n" + " " + StringHelper.postpad(helpFlags[7] ,maxLength, ' ') + labels.getString("d.message") + "\n" + " " + StringHelper.postpad(helpFlags[8] ,maxLength, ' ') + labels.getString("a.message") + "\n" + " " + StringHelper.postpad(helpFlags[9] ,maxLength, ' ') + labels.getString("decodegood.message") + " (" + labels.getString("default") + ")\n" + " " + StringHelper.postpad(helpFlags[10] ,maxLength, ' ') + labels.getString("x.message") + "\n" + " " + StringHelper.postpad(helpFlags[11] ,maxLength, ' ') + labels.getString("f.message") + "\n" + " " + StringHelper.postpad(helpFlags[12] ,maxLength, ' ') + labels.getString("noforce.message") + " (" + labels.getString("default") + ")\n" + " " + StringHelper.postpad(helpFlags[13] ,maxLength, ' ') + labels.getString("v.message") + " (" + labels.getString("default") + ")\n" + " " + StringHelper.postpad(helpFlags[14] ,maxLength, ' ') + labels.getString("q.message") + "\n" + " " + StringHelper.postpad(helpFlags[15] ,maxLength, ' ') + labels.getString("Q.message") + "\n" + " " + StringHelper.postpad(helpFlags[16] ,maxLength, ' ') + labels.getString("file.message") + "\n" + " " + StringHelper.postpad(helpFlags[17] ,maxLength, ' ') + labels.getString("string.message") + "\n" + " " + StringHelper.postpad(helpFlags[18] ,maxLength, ' ') + labels.getString("newline.message") + "\n" + " " + StringHelper.postpad(helpFlags[19] ,maxLength, ' ') + labels.getString("nonewline.message") + "\n" ); System.exit(0); } break; case 2:{ // print out the version message System.out.println(MessageFormat.format(labels.getString("version"), new String[] {version})); System.exit(0); } break; case 3:{ System.out.println( labels.getString("base64") + " -- " + labels.getString("purpose.message") + "\n" + MessageFormat.format(labels.getString("copyright"), new String[] {"2001-2002", "Stephen Ostermiller (http://ostermiller.org/contact.pl?regarding=Java+Utilities)"}) + "\n\n" + labels.getString("license") ); System.exit(0); } break; case 'd':{ action = ACTION_DECODE; } break; case 'a':{ forceDecode = true; } break; case 5:{ forceDecode = false; } break; case 'e':{ action = ACTION_ENCODE; } break; case 'l':{ lineBreaks = true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -