瀏覽代碼

Remove dependency on DMDirc client, fix bits and pieces

master
Chris Smith 13 年之前
父節點
當前提交
ad63abe19a

+ 0
- 3
.gitmodules 查看文件

@@ -1,6 +1,3 @@
1
-[submodule "externals/dmdirc"]
2
-	path = externals/dmdirc
3
-	url = ssh://renji.org.uk/home/dmdirc/git/client/
4 1
 [submodule "externals/evetool"]
5 2
 	path = externals/evetool
6 3
 	url = ssh://renji.org.uk/home/chris/git/evetool/

+ 0
- 1
externals/dmdirc

@@ -1 +0,0 @@
1
-Subproject commit 8e2493dd6de5a9d4b63b1c40f24dd0ea1e28a215

+ 12
- 21
nbproject/build-impl.xml 查看文件

@@ -133,12 +133,11 @@ is divided into following sections:
133 133
         </condition>
134 134
         <condition property="have.sources">
135 135
             <or>
136
+                <available file="${src.src.dir}"/>
136 137
                 <available file="${src.src5.dir}"/>
137
-                <available file="${src.src6.dir}"/>
138 138
                 <available file="${src.src4.dir}"/>
139 139
                 <available file="${src.src2.dir}"/>
140 140
                 <available file="${src.src3.dir}"/>
141
-                <available file="${src.src.dir}"/>
142 141
                 <available file="${src.dir}"/>
143 142
             </or>
144 143
         </condition>
@@ -195,12 +194,11 @@ is divided into following sections:
195 194
         <!-- You can override this target in the ../build.xml file. -->
196 195
     </target>
197 196
     <target depends="-pre-init,-init-private,-init-user,-init-project,-do-init" name="-init-check">
197
+        <fail unless="src.src.dir">Must set src.src.dir</fail>
198 198
         <fail unless="src.src5.dir">Must set src.src5.dir</fail>
199
-        <fail unless="src.src6.dir">Must set src.src6.dir</fail>
200 199
         <fail unless="src.src4.dir">Must set src.src4.dir</fail>
201 200
         <fail unless="src.src2.dir">Must set src.src2.dir</fail>
202 201
         <fail unless="src.src3.dir">Must set src.src3.dir</fail>
203
-        <fail unless="src.src.dir">Must set src.src.dir</fail>
204 202
         <fail unless="src.dir">Must set src.dir</fail>
205 203
         <fail unless="test.src.dir">Must set test.src.dir</fail>
206 204
         <fail unless="build.dir">Must set build.dir</fail>
@@ -223,7 +221,7 @@ is divided into following sections:
223 221
     </target>
224 222
     <target depends="-init-ap-cmdline-properties" if="ap.supported.internal" name="-init-macrodef-javac-with-processors">
225 223
         <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
226
-            <attribute default="${src.src5.dir}:${src.src6.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.src.dir}:${src.dir}" name="srcdir"/>
224
+            <attribute default="${src.src.dir}:${src.src5.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.dir}" name="srcdir"/>
227 225
             <attribute default="${build.classes.dir}" name="destdir"/>
228 226
             <attribute default="${javac.classpath}" name="classpath"/>
229 227
             <attribute default="${javac.processorpath}" name="processorpath"/>
@@ -263,7 +261,7 @@ is divided into following sections:
263 261
     </target>
264 262
     <target depends="-init-ap-cmdline-properties" name="-init-macrodef-javac-without-processors" unless="ap.supported.internal">
265 263
         <macrodef name="javac" uri="http://www.netbeans.org/ns/j2se-project/3">
266
-            <attribute default="${src.src5.dir}:${src.src6.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.src.dir}:${src.dir}" name="srcdir"/>
264
+            <attribute default="${src.src.dir}:${src.src5.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.dir}" name="srcdir"/>
267 265
             <attribute default="${build.classes.dir}" name="destdir"/>
268 266
             <attribute default="${javac.classpath}" name="classpath"/>
269 267
             <attribute default="${javac.processorpath}" name="processorpath"/>
@@ -295,7 +293,7 @@ is divided into following sections:
295 293
     </target>
296 294
     <target depends="-init-macrodef-javac-with-processors,-init-macrodef-javac-without-processors" name="-init-macrodef-javac">
297 295
         <macrodef name="depend" uri="http://www.netbeans.org/ns/j2se-project/3">
298
-            <attribute default="${src.src5.dir}:${src.src6.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.src.dir}:${src.dir}" name="srcdir"/>
296
+            <attribute default="${src.src.dir}:${src.src5.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.dir}" name="srcdir"/>
299 297
             <attribute default="${build.classes.dir}" name="destdir"/>
300 298
             <attribute default="${javac.classpath}" name="classpath"/>
301 299
             <sequential>
@@ -589,17 +587,16 @@ is divided into following sections:
589 587
                 <include name="*"/>
590 588
             </dirset>
591 589
         </pathconvert>
592
-        <j2seproject3:depend srcdir="${src.src5.dir}:${src.src6.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.src.dir}:${src.dir}:${build.generated.subdirs}"/>
590
+        <j2seproject3:depend srcdir="${src.src.dir}:${src.src5.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.dir}:${build.generated.subdirs}"/>
593 591
     </target>
594 592
     <target depends="init,deps-jar,-pre-pre-compile,-pre-compile, -copy-persistence-xml,-compile-depend" if="have.sources" name="-do-compile">
595 593
         <j2seproject3:javac gensrcdir="${build.generated.sources.dir}"/>
596 594
         <copy todir="${build.classes.dir}">
595
+            <fileset dir="${src.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
597 596
             <fileset dir="${src.src5.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
598
-            <fileset dir="${src.src6.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
599 597
             <fileset dir="${src.src4.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
600 598
             <fileset dir="${src.src2.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
601 599
             <fileset dir="${src.src3.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
602
-            <fileset dir="${src.src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
603 600
             <fileset dir="${src.dir}" excludes="${build.classes.excludes},${excludes}" includes="${includes}"/>
604 601
         </copy>
605 602
     </target>
@@ -621,7 +618,7 @@ is divided into following sections:
621 618
     <target depends="init,deps-jar,-pre-pre-compile" name="-do-compile-single">
622 619
         <fail unless="javac.includes">Must select some files in the IDE or set javac.includes</fail>
623 620
         <j2seproject3:force-recompile/>
624
-        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.src5.dir}:${src.src6.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.src.dir}:${src.dir}"/>
621
+        <j2seproject3:javac excludes="" gensrcdir="${build.generated.sources.dir}" includes="${javac.includes}" sourcepath="${src.src.dir}:${src.src5.dir}:${src.src4.dir}:${src.src2.dir}:${src.src3.dir}:${src.dir}"/>
625 622
     </target>
626 623
     <target name="-post-compile-single">
627 624
         <!-- Empty placeholder for easier customization. -->
@@ -832,10 +829,10 @@ is divided into following sections:
832 829
             <classpath>
833 830
                 <path path="${javac.classpath}"/>
834 831
             </classpath>
835
-            <fileset dir="${src.src5.dir}" excludes="${excludes}" includes="${includes}">
832
+            <fileset dir="${src.src.dir}" excludes="${excludes}" includes="${includes}">
836 833
                 <filename name="**/*.java"/>
837 834
             </fileset>
838
-            <fileset dir="${src.src6.dir}" excludes="${excludes}" includes="${includes}">
835
+            <fileset dir="${src.src5.dir}" excludes="${excludes}" includes="${includes}">
839 836
                 <filename name="**/*.java"/>
840 837
             </fileset>
841 838
             <fileset dir="${src.src4.dir}" excludes="${excludes}" includes="${includes}">
@@ -847,9 +844,6 @@ is divided into following sections:
847 844
             <fileset dir="${src.src3.dir}" excludes="${excludes}" includes="${includes}">
848 845
                 <filename name="**/*.java"/>
849 846
             </fileset>
850
-            <fileset dir="${src.src.dir}" excludes="${excludes}" includes="${includes}">
851
-                <filename name="**/*.java"/>
852
-            </fileset>
853 847
             <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
854 848
                 <filename name="**/*.java"/>
855 849
             </fileset>
@@ -858,10 +852,10 @@ is divided into following sections:
858 852
             </fileset>
859 853
         </javadoc>
860 854
         <copy todir="${dist.javadoc.dir}">
861
-            <fileset dir="${src.src5.dir}" excludes="${excludes}" includes="${includes}">
855
+            <fileset dir="${src.src.dir}" excludes="${excludes}" includes="${includes}">
862 856
                 <filename name="**/doc-files/**"/>
863 857
             </fileset>
864
-            <fileset dir="${src.src6.dir}" excludes="${excludes}" includes="${includes}">
858
+            <fileset dir="${src.src5.dir}" excludes="${excludes}" includes="${includes}">
865 859
                 <filename name="**/doc-files/**"/>
866 860
             </fileset>
867 861
             <fileset dir="${src.src4.dir}" excludes="${excludes}" includes="${includes}">
@@ -873,9 +867,6 @@ is divided into following sections:
873 867
             <fileset dir="${src.src3.dir}" excludes="${excludes}" includes="${includes}">
874 868
                 <filename name="**/doc-files/**"/>
875 869
             </fileset>
876
-            <fileset dir="${src.src.dir}" excludes="${excludes}" includes="${includes}">
877
-                <filename name="**/doc-files/**"/>
878
-            </fileset>
879 870
             <fileset dir="${src.dir}" excludes="${excludes}" includes="${includes}">
880 871
                 <filename name="**/doc-files/**"/>
881 872
             </fileset>

+ 3
- 3
nbproject/genfiles.properties 查看文件

@@ -1,8 +1,8 @@
1
-build.xml.data.CRC32=3f367bc6
1
+build.xml.data.CRC32=3df6429b
2 2
 build.xml.script.CRC32=d4296ee3
3 3
 build.xml.stylesheet.CRC32=28e38971@1.40.0.45
4 4
 # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml.
5 5
 # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you.
6
-nbproject/build-impl.xml.data.CRC32=3f367bc6
7
-nbproject/build-impl.xml.script.CRC32=d8234de7
6
+nbproject/build-impl.xml.data.CRC32=3df6429b
7
+nbproject/build-impl.xml.script.CRC32=292a7a81
8 8
 nbproject/build-impl.xml.stylesheet.CRC32=fce8b508@1.40.0.45

+ 2
- 3
nbproject/project.properties 查看文件

@@ -24,7 +24,7 @@ dist.dir=dist
24 24
 dist.jar=${dist.dir}/charliebravo.jar
25 25
 dist.javadoc.dir=${dist.dir}/javadoc
26 26
 endorsed.classpath=
27
-excludes=com/dmdirc/addons/nowplaying/,com/dmdirc/addons/systray/,com/dmdirc/addons/nickcolours/,com/dmdirc/addons/lagdisplay/,com/dmdirc/addons/mediasource_*/,com/dmdirc/addons/ui_swing/,com/dmdirc/addons/dcc/,com/dmdirc/addons/windowstatus/,com/dmdirc/addons/osd/,com/dmdirc/addons/logging/,com/dmdirc/addons/addonbrowser/,uk/co/md87/evetool/ui/,uk/co/md87/evetool/Main.java
27
+excludes=com/dmdirc/addons/addonbrowser/, com/dmdirc/addons/audio/, com/dmdirc/addons/calc/Calc*.java, com/dmdirc/addons/dcc/, com/dmdirc/addons/dcop/, com/dmdirc/addons/dns/, com/dmdirc/addons/freedesktop_notifications/, com/dmdirc/addons/identd/, com/dmdirc/addons/lagdisplay/, com/dmdirc/addons/logging/, com/dmdirc/addons/mediasource_*/, com/dmdirc/addons/nowplaying/, com/dmdirc/addons/nickcolours/, com/dmdirc/addons/osd/, com/dmdirc/addons/parserdebug/, com/dmdirc/addons/parser_*/, com/dmdirc/addons/redirect/, com/dmdirc/addons/relaybot/, com/dmdirc/addons/scriptplugin/, com/dmdirc/addons/serverlists/, com/dmdirc/addons/systray/, com/dmdirc/addons/tabcompletion_*/, com/dmdirc/addons/time/, com/dmdirc/addons/ui_*/, com/dmdirc/addons/urlcatcher/, com/dmdirc/addons/userlevel/, com/dmdirc/addons/windowstatus/, uk/co/md87/evetool/ui/, uk/co/md87/evetool/Main.java
28 28
 file.reference.commons-codec-1.3.jar=externals/dmdirc-plugins/lib/commons-codec-1.3.jar
29 29
 file.reference.commons-lang-2.4.jar=externals/dmdirc-plugins/lib/commons-lang-2.4.jar
30 30
 file.reference.jaxen-core.jar=externals/evetool/lib/jaxen-core.jar
@@ -99,10 +99,9 @@ run.test.classpath=\
99 99
     ${build.test.classes.dir}
100 100
 source.encoding=UTF-8
101 101
 src.dir=src
102
-src.src.dir=externals/dmdirc/src
102
+src.src.dir=externals/dmdirc-util/src
103 103
 src.src2.dir=externals/evetool/src
104 104
 src.src3.dir=externals/dmdirc-plugins/src
105 105
 src.src4.dir=externals/util/src
106 106
 src.src5.dir=externals/dmdirc-parser/src
107
-src.src6.dir=externals/dmdirc-util/src
108 107
 test.src.dir=test

+ 1
- 2
nbproject/project.xml 查看文件

@@ -6,12 +6,11 @@
6 6
             <name>charliebravo</name>
7 7
             <minimum-ant-version>1.6.5</minimum-ant-version>
8 8
             <source-roots>
9
+                <root id="src.src.dir"/>
9 10
                 <root id="src.src5.dir"/>
10
-                <root id="src.src6.dir"/>
11 11
                 <root id="src.src4.dir"/>
12 12
                 <root id="src.src2.dir"/>
13 13
                 <root id="src.src3.dir"/>
14
-                <root id="src.src.dir"/>
15 14
                 <root id="src.dir"/>
16 15
             </source-roots>
17 16
             <test-roots>

+ 50
- 0
src/com/md87/charliebravo/CharlieBravo.java 查看文件

@@ -97,5 +97,55 @@ public class CharlieBravo implements Runnable, Post005Listener,
97 97
     public void onDataOut(final Parser tParser, final Date date, final String sData, final boolean bFromParser) {
98 98
         System.out.println(">>> " + sData);
99 99
     }
100
+    
101
+    /**
102
+     * Tests for and adds one component of the duration format.
103
+     *
104
+     * @param builder The string builder to append text to
105
+     * @param current The number of seconds in the duration
106
+     * @param duration The number of seconds in this component
107
+     * @param name The name of this component
108
+     * @return The number of seconds used by this component
109
+     */
110
+    private static int doDuration(final StringBuilder builder, final int current,
111
+            final int duration, final String name) {
112
+        int res = 0;
113
+
114
+        if (current >= duration) {
115
+            final int units = current / duration;
116
+            res = units * duration;
117
+
118
+            if (builder.length() > 0) {
119
+                builder.append(", ");
120
+            }
121
+
122
+            builder.append(units);
123
+            builder.append(' ');
124
+            builder.append(name + (units != 1 ? 's' : ""));
125
+        }
126
+
127
+        return res;
128
+    }
129
+
130
+    
131
+    /**
132
+     * Formats the specified number of seconds as a string containing the
133
+     * number of days, hours, minutes and seconds.
134
+     *
135
+     * @param duration The duration in seconds to be formatted
136
+     * @return A textual version of the duration
137
+     */
138
+    public static String formatDuration(final int duration) {
139
+        final StringBuilder buff = new StringBuilder();
140
+
141
+        int seconds = duration;
142
+
143
+        seconds -= doDuration(buff, seconds, 60*60*24, "day");
144
+        seconds -= doDuration(buff, seconds, 60*60, "hour");
145
+        seconds -= doDuration(buff, seconds, 60, "minute");
146
+        seconds -= doDuration(buff, seconds, 1, "second");
147
+
148
+        return buff.length() == 0 ? "0 seconds" : buff.toString();
149
+    }
100 150
 
101 151
 }

+ 4
- 4
src/com/md87/charliebravo/commands/SkillCommand.java 查看文件

@@ -22,7 +22,7 @@
22 22
 
23 23
 package com.md87.charliebravo.commands;
24 24
 
25
-import com.dmdirc.ui.messages.Formatter;
25
+import com.md87.charliebravo.CharlieBravo;
26 26
 import com.md87.charliebravo.Command;
27 27
 import com.md87.charliebravo.CommandOptions;
28 28
 import com.md87.charliebravo.ConfigCache;
@@ -67,7 +67,7 @@ public class SkillCommand implements Command {
67 67
                         response.sendMessage("you are currently training "
68 68
                                 + skill.getSkill().getName() + " to level "
69 69
                                 + skill.getTargetLevel() + ". It will finish in "
70
-                                + Formatter.formatDuration((int) (skill.getEndTime()
70
+                                + CharlieBravo.formatDuration((int) (skill.getEndTime()
71 71
                                 .getTime() - System.currentTimeMillis()) / 1000));
72 72
                     } else {
73 73
                         response.sendMessage("You are not training anything", true);
@@ -102,10 +102,10 @@ public class SkillCommand implements Command {
102 102
         public void execute(InputHandler handler, Response response, String line) throws Exception {
103 103
             response.setInheritFollows(true);
104 104
             response.sendMessage("the result has been cached for " +
105
-                    Formatter.formatDuration((int) (System.currentTimeMillis()
105
+                    CharlieBravo.formatDuration((int) (System.currentTimeMillis()
106 106
                     - apiresponse.getApiResult().getCachedSince().getTime()) / 1000)
107 107
                     + ", and will expire in " +
108
-                    Formatter.formatDuration((int) (apiresponse.getApiResult()
108
+                    CharlieBravo.formatDuration((int) (apiresponse.getApiResult()
109 109
                     .getCachedUntil().getTime() - System.currentTimeMillis()) / 1000));
110 110
         }
111 111
 

+ 2
- 2
src/com/md87/charliebravo/commands/WhoisCommand.java 查看文件

@@ -23,7 +23,7 @@
23 23
 package com.md87.charliebravo.commands;
24 24
 
25 25
 import com.dmdirc.parser.interfaces.ClientInfo;
26
-import com.dmdirc.ui.messages.Formatter;
26
+import com.md87.charliebravo.CharlieBravo;
27 27
 import com.md87.charliebravo.Command;
28 28
 import com.md87.charliebravo.InputHandler;
29 29
 import com.md87.charliebravo.Response;
@@ -51,7 +51,7 @@ public class WhoisCommand implements Command {
51 51
                     }
52 52
 
53 53
                     response.sendMessage(line + " last authenticated with me "
54
-                            + Formatter.formatDuration((int)
54
+                            + CharlieBravo.formatDuration((int)
55 55
                             (System.currentTimeMillis() -
56 56
                             Long.valueOf(handler.getConfig().getOption(line, "internal.lastseen")))
57 57
                             / 1000)

+ 758
- 0
src/net/miginfocom/Base64.java 查看文件

@@ -0,0 +1,758 @@
1
+package net.miginfocom;
2
+
3
+import java.util.Arrays;
4
+
5
+/**
6
+ * A very fast and memory efficient class to encode and decode to and from
7
+ * BASE64 in full accordance
8
+ * with RFC 2045.<br>
9
+ * <br>
10
+ * On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is
11
+ * about 10 times faster
12
+ * on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays
13
+ * (10000 - 1000000 bytes)
14
+ * compared to <code>sun.misc.Encoder()/Decoder()</code>.<br>
15
+ * <br>
16
+ * 
17
+ * On byte arrays the encoder is about 20% faster than Jakarta Commons Base64
18
+ * Codec for encode and
19
+ * about 50% faster for decoding large arrays. This implementation is about
20
+ * twice as fast on very small
21
+ * arrays (&lt 30 bytes). If source/destination is a <code>String</code> this
22
+ * version is about three times as fast due to the fact that the Commons Codec
23
+ * result has to be recoded
24
+ * to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br>
25
+ * <br>
26
+ * 
27
+ * This encode/decode algorithm doesn't create any temporary arrays as many
28
+ * other codecs do, it only
29
+ * allocates the resulting array. This produces less garbage and it is possible
30
+ * to handle arrays twice
31
+ * as large as algorithms that create a temporary array. (E.g. Jakarta Commons
32
+ * Codec). It is unknown
33
+ * whether Sun's <code>sun.misc.Encoder()/Decoder()</code> produce temporary
34
+ * arrays but since performance
35
+ * is quite low it probably does.<br>
36
+ * <br>
37
+ * 
38
+ * The encoder produces the same output as the Sun one except that the Sun's
39
+ * encoder appends
40
+ * a trailing line separator if the last character isn't a pad. Unclear why but
41
+ * it only adds to the
42
+ * length and is probably a side effect. Both are in conformance with RFC 2045
43
+ * though.<br>
44
+ * Commons codec seem to always att a trailing line separator.<br>
45
+ * <br>
46
+ * 
47
+ * <b>Note!</b>
48
+ * The encode/decode method pairs (types) come in three versions with the
49
+ * <b>exact</b> same algorithm and
50
+ * thus a lot of code redundancy. This is to not create any temporary arrays for
51
+ * transcoding to/from different
52
+ * format types. The methods not used can simply be commented out.<br>
53
+ * <br>
54
+ * 
55
+ * There is also a "fast" version of all decode methods that works the same way
56
+ * as the normal ones, but
57
+ * har a few demands on the decoded input. Normally though, these fast verions
58
+ * should be used if the source if
59
+ * the input is known and it hasn't bee tampered with.<br>
60
+ * <br>
61
+ * 
62
+ * If you find the code useful or you find a bug, please send me a note at
63
+ * base64 @ miginfocom . com.
64
+ * 
65
+ * Licence (BSD):
66
+ * ==============
67
+ * 
68
+ * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
69
+ * All rights reserved.
70
+ * 
71
+ * Redistribution and use in source and binary forms, with or without
72
+ * modification,
73
+ * are permitted provided that the following conditions are met:
74
+ * Redistributions of source code must retain the above copyright notice, this
75
+ * list
76
+ * of conditions and the following disclaimer.
77
+ * Redistributions in binary form must reproduce the above copyright notice,
78
+ * this
79
+ * list of conditions and the following disclaimer in the documentation and/or
80
+ * other
81
+ * materials provided with the distribution.
82
+ * Neither the name of the MiG InfoCom AB nor the names of its contributors may
83
+ * be
84
+ * used to endorse or promote products derived from this software without
85
+ * specific
86
+ * prior written permission.
87
+ * 
88
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
89
+ * AND
90
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
91
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
92
+ * DISCLAIMED.
93
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
94
+ * DIRECT,
95
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
96
+ * (INCLUDING,
97
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
98
+ * DATA,
99
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
100
+ * LIABILITY,
101
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
102
+ * OTHERWISE)
103
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
104
+ * POSSIBILITY
105
+ * OF SUCH DAMAGE.
106
+ * 
107
+ * @version 2.2
108
+ * @author Mikael Grev
109
+ *         Date: 2004-aug-02
110
+ *         Time: 11:31:11
111
+ */
112
+
113
+public class Base64 {
114
+    private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
115
+            .toCharArray();
116
+    private static final int[] IA = new int[256];
117
+    static {
118
+        Arrays.fill(IA, -1);
119
+        for (int i = 0, iS = CA.length; i < iS; i++) {
120
+            IA[CA[i]] = i;
121
+        }
122
+        IA['='] = 0;
123
+    }
124
+
125
+    // ****************************************************************************************
126
+    // * char[] version
127
+    // ****************************************************************************************
128
+
129
+    /**
130
+     * Encodes a raw byte array into a BASE64 <code>char[]</code> representation
131
+     * i accordance with RFC 2045.
132
+     * 
133
+     * @param sArr
134
+     *            The bytes to convert. If <code>null</code> or length 0 an
135
+     *            empty array will be returned.
136
+     * @param lineSep
137
+     *            Optional "\r\n" after 76 characters, unless end of file.<br>
138
+     *            No line separator will be in breach of RFC 2045 which
139
+     *            specifies max 76 per line but will be a
140
+     *            little faster.
141
+     * @return A BASE64 encoded array. Never <code>null</code>.
142
+     */
143
+    public static final char[] encodeToChar(final byte[] sArr,
144
+            final boolean lineSep) {
145
+        // Check special case
146
+        final int sLen = sArr != null ? sArr.length : 0;
147
+        if (sLen == 0) {
148
+            return new char[0];
149
+        }
150
+
151
+        final int eLen = sLen / 3 * 3; // Length of even 24-bits.
152
+        final int cCnt = (sLen - 1) / 3 + 1 << 2; // Returned character count
153
+        final int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length
154
+                                                                      // of
155
+                                                                      // returned
156
+                                                                      // array
157
+        final char[] dArr = new char[dLen];
158
+
159
+        // Encode even 24-bits
160
+        for (int s = 0, d = 0, cc = 0; s < eLen;) {
161
+            // Copy next three bytes into lower 24 bits of int, paying attension
162
+            // to sign.
163
+            final int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8
164
+                    | sArr[s++] & 0xff;
165
+
166
+            // Encode the int into four chars
167
+            dArr[d++] = CA[i >>> 18 & 0x3f];
168
+            dArr[d++] = CA[i >>> 12 & 0x3f];
169
+            dArr[d++] = CA[i >>> 6 & 0x3f];
170
+            dArr[d++] = CA[i & 0x3f];
171
+
172
+            // Add optional line separator
173
+            if (lineSep && ++cc == 19 && d < dLen - 2) {
174
+                dArr[d++] = '\r';
175
+                dArr[d++] = '\n';
176
+                cc = 0;
177
+            }
178
+        }
179
+
180
+        // Pad and encode last bits if source isn't even 24 bits.
181
+        final int left = sLen - eLen; // 0 - 2.
182
+        if (left > 0) {
183
+            // Prepare the int
184
+            final int i = (sArr[eLen] & 0xff) << 10
185
+                    | (left == 2 ? (sArr[sLen - 1] & 0xff) << 2 : 0);
186
+
187
+            // Set last four chars
188
+            dArr[dLen - 4] = CA[i >> 12];
189
+            dArr[dLen - 3] = CA[i >>> 6 & 0x3f];
190
+            dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : '=';
191
+            dArr[dLen - 1] = '=';
192
+        }
193
+        return dArr;
194
+    }
195
+
196
+    /**
197
+     * Decodes a BASE64 encoded char array. All illegal characters will be
198
+     * ignored and can handle both arrays with
199
+     * and without line separators.
200
+     * 
201
+     * @param sArr
202
+     *            The source array. <code>null</code> or length 0 will return an
203
+     *            empty array.
204
+     * @return The decoded array of bytes. May be of length 0. Will be
205
+     *         <code>null</code> if the legal characters
206
+     *         (including '=') isn't divideable by 4. (I.e. definitely
207
+     *         corrupted).
208
+     */
209
+    public static final byte[] decode(final char[] sArr) {
210
+        // Check special case
211
+        final int sLen = sArr != null ? sArr.length : 0;
212
+        if (sLen == 0) {
213
+            return new byte[0];
214
+        }
215
+
216
+        // Count illegal characters (including '\r', '\n') to know what size the
217
+        // returned array will be,
218
+        // so we don't have to reallocate & copy it later.
219
+        int sepCnt = 0; // Number of separator characters. (Actually illegal
220
+                        // characters, but that's a bonus...)
221
+        for (int i = 0; i < sLen; i++) {
222
+            if (IA[sArr[i]] < 0) {
223
+                sepCnt++;
224
+            }
225
+        }
226
+
227
+        // Check so that legal chars (including '=') are evenly divideable by 4
228
+        // as specified in RFC 2045.
229
+        if ((sLen - sepCnt) % 4 != 0) {
230
+            return null;
231
+        }
232
+
233
+        int pad = 0;
234
+        for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;) {
235
+            if (sArr[i] == '=') {
236
+                pad++;
237
+            }
238
+        }
239
+
240
+        final int len = ((sLen - sepCnt) * 6 >> 3) - pad;
241
+
242
+        final byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
243
+
244
+        for (int s = 0, d = 0; d < len;) {
245
+            // Assemble three bytes into an int from four "valid" characters.
246
+            int i = 0;
247
+            for (int j = 0; j < 4; j++) { // j only increased if a valid char
248
+                                          // was found.
249
+                final int c = IA[sArr[s++]];
250
+                if (c >= 0) {
251
+                    i |= c << 18 - j * 6;
252
+                } else {
253
+                    j--;
254
+                }
255
+            }
256
+            // Add the bytes
257
+            dArr[d++] = (byte) (i >> 16);
258
+            if (d < len) {
259
+                dArr[d++] = (byte) (i >> 8);
260
+                if (d < len) {
261
+                    dArr[d++] = (byte) i;
262
+                }
263
+            }
264
+        }
265
+        return dArr;
266
+    }
267
+
268
+    /**
269
+     * Decodes a BASE64 encoded char array that is known to be resonably well
270
+     * formatted. The method is about twice as
271
+     * fast as {@link #decode(char[])}. The preconditions are:<br>
272
+     * + The array must have a line length of 76 chars OR no line separators at
273
+     * all (one line).<br>
274
+     * + Line separator must be "\r\n", as specified in RFC 2045
275
+     * + The array must not contain illegal characters within the encoded string<br>
276
+     * + The array CAN have illegal characters at the beginning and end, those
277
+     * will be dealt with appropriately.<br>
278
+     * 
279
+     * @param sArr
280
+     *            The source array. Length 0 will return an empty array.
281
+     *            <code>null</code> will throw an exception.
282
+     * @return The decoded array of bytes. May be of length 0.
283
+     */
284
+    public static final byte[] decodeFast(final char[] sArr) {
285
+        // Check special case
286
+        final int sLen = sArr.length;
287
+        if (sLen == 0) {
288
+            return new byte[0];
289
+        }
290
+
291
+        int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
292
+
293
+        // Trim illegal chars from start
294
+        while (sIx < eIx && IA[sArr[sIx]] < 0) {
295
+            sIx++;
296
+        }
297
+
298
+        // Trim illegal chars from end
299
+        while (eIx > 0 && IA[sArr[eIx]] < 0) {
300
+            eIx--;
301
+        }
302
+
303
+        // get the padding count (=) (0, 1 or 2)
304
+        final int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count
305
+                                                                               // '='
306
+                                                                               // at
307
+                                                                               // end.
308
+        final int cCnt = eIx - sIx + 1; // Content count including possible
309
+                                        // separators
310
+        final int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1
311
+                : 0;
312
+
313
+        final int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of
314
+                                                          // decoded bytes
315
+        final byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
316
+
317
+        // Decode all but the last 0 - 2 bytes.
318
+        int d = 0;
319
+        for (int cc = 0, eLen = len / 3 * 3; d < eLen;) {
320
+            // Assemble three bytes into an int from four "valid" characters.
321
+            final int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12
322
+                    | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
323
+
324
+            // Add the bytes
325
+            dArr[d++] = (byte) (i >> 16);
326
+            dArr[d++] = (byte) (i >> 8);
327
+            dArr[d++] = (byte) i;
328
+
329
+            // If line separator, jump over it.
330
+            if (sepCnt > 0 && ++cc == 19) {
331
+                sIx += 2;
332
+                cc = 0;
333
+            }
334
+        }
335
+
336
+        if (d < len) {
337
+            // Decode last 1-3 bytes (incl '=') into 1-3 bytes
338
+            int i = 0;
339
+            for (int j = 0; sIx <= eIx - pad; j++) {
340
+                i |= IA[sArr[sIx++]] << 18 - j * 6;
341
+            }
342
+
343
+            for (int r = 16; d < len; r -= 8) {
344
+                dArr[d++] = (byte) (i >> r);
345
+            }
346
+        }
347
+
348
+        return dArr;
349
+    }
350
+
351
+    // ****************************************************************************************
352
+    // * byte[] version
353
+    // ****************************************************************************************
354
+
355
+    /**
356
+     * Encodes a raw byte array into a BASE64 <code>byte[]</code> representation
357
+     * i accordance with RFC 2045.
358
+     * 
359
+     * @param sArr
360
+     *            The bytes to convert. If <code>null</code> or length 0 an
361
+     *            empty array will be returned.
362
+     * @param lineSep
363
+     *            Optional "\r\n" after 76 characters, unless end of file.<br>
364
+     *            No line separator will be in breach of RFC 2045 which
365
+     *            specifies max 76 per line but will be a
366
+     *            little faster.
367
+     * @return A BASE64 encoded array. Never <code>null</code>.
368
+     */
369
+    public static final byte[] encodeToByte(final byte[] sArr,
370
+            final boolean lineSep) {
371
+        // Check special case
372
+        final int sLen = sArr != null ? sArr.length : 0;
373
+        if (sLen == 0) {
374
+            return new byte[0];
375
+        }
376
+
377
+        final int eLen = sLen / 3 * 3; // Length of even 24-bits.
378
+        final int cCnt = (sLen - 1) / 3 + 1 << 2; // Returned character count
379
+        final int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length
380
+                                                                      // of
381
+                                                                      // returned
382
+                                                                      // array
383
+        final byte[] dArr = new byte[dLen];
384
+
385
+        // Encode even 24-bits
386
+        for (int s = 0, d = 0, cc = 0; s < eLen;) {
387
+            // Copy next three bytes into lower 24 bits of int, paying attension
388
+            // to sign.
389
+            final int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8
390
+                    | sArr[s++] & 0xff;
391
+
392
+            // Encode the int into four chars
393
+            dArr[d++] = (byte) CA[i >>> 18 & 0x3f];
394
+            dArr[d++] = (byte) CA[i >>> 12 & 0x3f];
395
+            dArr[d++] = (byte) CA[i >>> 6 & 0x3f];
396
+            dArr[d++] = (byte) CA[i & 0x3f];
397
+
398
+            // Add optional line separator
399
+            if (lineSep && ++cc == 19 && d < dLen - 2) {
400
+                dArr[d++] = '\r';
401
+                dArr[d++] = '\n';
402
+                cc = 0;
403
+            }
404
+        }
405
+
406
+        // Pad and encode last bits if source isn't an even 24 bits.
407
+        final int left = sLen - eLen; // 0 - 2.
408
+        if (left > 0) {
409
+            // Prepare the int
410
+            final int i = (sArr[eLen] & 0xff) << 10
411
+                    | (left == 2 ? (sArr[sLen - 1] & 0xff) << 2 : 0);
412
+
413
+            // Set last four chars
414
+            dArr[dLen - 4] = (byte) CA[i >> 12];
415
+            dArr[dLen - 3] = (byte) CA[i >>> 6 & 0x3f];
416
+            dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) '=';
417
+            dArr[dLen - 1] = '=';
418
+        }
419
+        return dArr;
420
+    }
421
+
422
+    /**
423
+     * Decodes a BASE64 encoded byte array. All illegal characters will be
424
+     * ignored and can handle both arrays with
425
+     * and without line separators.
426
+     * 
427
+     * @param sArr
428
+     *            The source array. Length 0 will return an empty array.
429
+     *            <code>null</code> will throw an exception.
430
+     * @return The decoded array of bytes. May be of length 0. Will be
431
+     *         <code>null</code> if the legal characters
432
+     *         (including '=') isn't divideable by 4. (I.e. definitely
433
+     *         corrupted).
434
+     */
435
+    public static final byte[] decode(final byte[] sArr) {
436
+        // Check special case
437
+        final int sLen = sArr.length;
438
+
439
+        // Count illegal characters (including '\r', '\n') to know what size the
440
+        // returned array will be,
441
+        // so we don't have to reallocate & copy it later.
442
+        int sepCnt = 0; // Number of separator characters. (Actually illegal
443
+                        // characters, but that's a bonus...)
444
+        for (int i = 0; i < sLen; i++) {
445
+            if (IA[sArr[i] & 0xff] < 0) {
446
+                sepCnt++;
447
+            }
448
+        }
449
+
450
+        // Check so that legal chars (including '=') are evenly divideable by 4
451
+        // as specified in RFC 2045.
452
+        if ((sLen - sepCnt) % 4 != 0) {
453
+            return null;
454
+        }
455
+
456
+        int pad = 0;
457
+        for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;) {
458
+            if (sArr[i] == '=') {
459
+                pad++;
460
+            }
461
+        }
462
+
463
+        final int len = ((sLen - sepCnt) * 6 >> 3) - pad;
464
+
465
+        final byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
466
+
467
+        for (int s = 0, d = 0; d < len;) {
468
+            // Assemble three bytes into an int from four "valid" characters.
469
+            int i = 0;
470
+            for (int j = 0; j < 4; j++) { // j only increased if a valid char
471
+                                          // was found.
472
+                final int c = IA[sArr[s++] & 0xff];
473
+                if (c >= 0) {
474
+                    i |= c << 18 - j * 6;
475
+                } else {
476
+                    j--;
477
+                }
478
+            }
479
+
480
+            // Add the bytes
481
+            dArr[d++] = (byte) (i >> 16);
482
+            if (d < len) {
483
+                dArr[d++] = (byte) (i >> 8);
484
+                if (d < len) {
485
+                    dArr[d++] = (byte) i;
486
+                }
487
+            }
488
+        }
489
+
490
+        return dArr;
491
+    }
492
+
493
+    /**
494
+     * Decodes a BASE64 encoded byte array that is known to be resonably well
495
+     * formatted. The method is about twice as
496
+     * fast as {@link #decode(byte[])}. The preconditions are:<br>
497
+     * + The array must have a line length of 76 chars OR no line separators at
498
+     * all (one line).<br>
499
+     * + Line separator must be "\r\n", as specified in RFC 2045
500
+     * + The array must not contain illegal characters within the encoded string<br>
501
+     * + The array CAN have illegal characters at the beginning and end, those
502
+     * will be dealt with appropriately.<br>
503
+     * 
504
+     * @param sArr
505
+     *            The source array. Length 0 will return an empty array.
506
+     *            <code>null</code> will throw an exception.
507
+     * @return The decoded array of bytes. May be of length 0.
508
+     */
509
+    public static final byte[] decodeFast(final byte[] sArr) {
510
+        // Check special case
511
+        final int sLen = sArr.length;
512
+        if (sLen == 0) {
513
+            return new byte[0];
514
+        }
515
+
516
+        int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
517
+
518
+        // Trim illegal chars from start
519
+        while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0) {
520
+            sIx++;
521
+        }
522
+
523
+        // Trim illegal chars from end
524
+        while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0) {
525
+            eIx--;
526
+        }
527
+
528
+        // get the padding count (=) (0, 1 or 2)
529
+        final int pad = sArr[eIx] == '=' ? (sArr[eIx - 1] == '=' ? 2 : 1) : 0; // Count
530
+                                                                               // '='
531
+                                                                               // at
532
+                                                                               // end.
533
+        final int cCnt = eIx - sIx + 1; // Content count including possible
534
+                                        // separators
535
+        final int sepCnt = sLen > 76 ? (sArr[76] == '\r' ? cCnt / 78 : 0) << 1
536
+                : 0;
537
+
538
+        final int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of
539
+                                                          // decoded bytes
540
+        final byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
541
+
542
+        // Decode all but the last 0 - 2 bytes.
543
+        int d = 0;
544
+        for (int cc = 0, eLen = len / 3 * 3; d < eLen;) {
545
+            // Assemble three bytes into an int from four "valid" characters.
546
+            final int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12
547
+                    | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
548
+
549
+            // Add the bytes
550
+            dArr[d++] = (byte) (i >> 16);
551
+            dArr[d++] = (byte) (i >> 8);
552
+            dArr[d++] = (byte) i;
553
+
554
+            // If line separator, jump over it.
555
+            if (sepCnt > 0 && ++cc == 19) {
556
+                sIx += 2;
557
+                cc = 0;
558
+            }
559
+        }
560
+
561
+        if (d < len) {
562
+            // Decode last 1-3 bytes (incl '=') into 1-3 bytes
563
+            int i = 0;
564
+            for (int j = 0; sIx <= eIx - pad; j++) {
565
+                i |= IA[sArr[sIx++]] << 18 - j * 6;
566
+            }
567
+
568
+            for (int r = 16; d < len; r -= 8) {
569
+                dArr[d++] = (byte) (i >> r);
570
+            }
571
+        }
572
+
573
+        return dArr;
574
+    }
575
+
576
+    // ****************************************************************************************
577
+    // * String version
578
+    // ****************************************************************************************
579
+
580
+    /**
581
+     * Encodes a raw byte array into a BASE64 <code>String</code> representation
582
+     * i accordance with RFC 2045.
583
+     * 
584
+     * @param sArr
585
+     *            The bytes to convert. If <code>null</code> or length 0 an
586
+     *            empty array will be returned.
587
+     * @param lineSep
588
+     *            Optional "\r\n" after 76 characters, unless end of file.<br>
589
+     *            No line separator will be in breach of RFC 2045 which
590
+     *            specifies max 76 per line but will be a
591
+     *            little faster.
592
+     * @return A BASE64 encoded array. Never <code>null</code>.
593
+     */
594
+    public static final String encodeToString(final byte[] sArr,
595
+            final boolean lineSep) {
596
+        // Reuse char[] since we can't create a String incrementally anyway and
597
+        // StringBuffer/Builder would be slower.
598
+        return new String(encodeToChar(sArr, lineSep));
599
+    }
600
+
601
+    /**
602
+     * Decodes a BASE64 encoded <code>String</code>. All illegal characters will
603
+     * be ignored and can handle both strings with
604
+     * and without line separators.<br>
605
+     * <b>Note!</b> It can be up to about 2x the speed to call
606
+     * <code>decode(str.toCharArray())</code> instead. That
607
+     * will create a temporary array though. This version will use
608
+     * <code>str.charAt(i)</code> to iterate the string.
609
+     * 
610
+     * @param str
611
+     *            The source string. <code>null</code> or length 0 will return
612
+     *            an empty array.
613
+     * @return The decoded array of bytes. May be of length 0. Will be
614
+     *         <code>null</code> if the legal characters
615
+     *         (including '=') isn't divideable by 4. (I.e. definitely
616
+     *         corrupted).
617
+     */
618
+    public static final byte[] decode(final String str) {
619
+        // Check special case
620
+        final int sLen = str != null ? str.length() : 0;
621
+        if (sLen == 0) {
622
+            return new byte[0];
623
+        }
624
+
625
+        // Count illegal characters (including '\r', '\n') to know what size the
626
+        // returned array will be,
627
+        // so we don't have to reallocate & copy it later.
628
+        int sepCnt = 0; // Number of separator characters. (Actually illegal
629
+                        // characters, but that's a bonus...)
630
+        for (int i = 0; i < sLen; i++) {
631
+            if (IA[str.charAt(i)] < 0) {
632
+                sepCnt++;
633
+            }
634
+        }
635
+
636
+        // Check so that legal chars (including '=') are evenly divideable by 4
637
+        // as specified in RFC 2045.
638
+        if ((sLen - sepCnt) % 4 != 0) {
639
+            return null;
640
+        }
641
+
642
+        // Count '=' at end
643
+        int pad = 0;
644
+        for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;) {
645
+            if (str.charAt(i) == '=') {
646
+                pad++;
647
+            }
648
+        }
649
+
650
+        final int len = ((sLen - sepCnt) * 6 >> 3) - pad;
651
+
652
+        final byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
653
+
654
+        for (int s = 0, d = 0; d < len;) {
655
+            // Assemble three bytes into an int from four "valid" characters.
656
+            int i = 0;
657
+            for (int j = 0; j < 4; j++) { // j only increased if a valid char
658
+                                          // was found.
659
+                final int c = IA[str.charAt(s++)];
660
+                if (c >= 0) {
661
+                    i |= c << 18 - j * 6;
662
+                } else {
663
+                    j--;
664
+                }
665
+            }
666
+            // Add the bytes
667
+            dArr[d++] = (byte) (i >> 16);
668
+            if (d < len) {
669
+                dArr[d++] = (byte) (i >> 8);
670
+                if (d < len) {
671
+                    dArr[d++] = (byte) i;
672
+                }
673
+            }
674
+        }
675
+        return dArr;
676
+    }
677
+
678
+    /**
679
+     * Decodes a BASE64 encoded string that is known to be resonably well
680
+     * formatted. The method is about twice as
681
+     * fast as {@link #decode(String)}. The preconditions are:<br>
682
+     * + The array must have a line length of 76 chars OR no line separators at
683
+     * all (one line).<br>
684
+     * + Line separator must be "\r\n", as specified in RFC 2045
685
+     * + The array must not contain illegal characters within the encoded string<br>
686
+     * + The array CAN have illegal characters at the beginning and end, those
687
+     * will be dealt with appropriately.<br>
688
+     * 
689
+     * @param s
690
+     *            The source string. Length 0 will return an empty array.
691
+     *            <code>null</code> will throw an exception.
692
+     * @return The decoded array of bytes. May be of length 0.
693
+     */
694
+    public static final byte[] decodeFast(final String s) {
695
+        // Check special case
696
+        final int sLen = s.length();
697
+        if (sLen == 0) {
698
+            return new byte[0];
699
+        }
700
+
701
+        int sIx = 0, eIx = sLen - 1; // Start and end index after trimming.
702
+
703
+        // Trim illegal chars from start
704
+        while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) {
705
+            sIx++;
706
+        }
707
+
708
+        // Trim illegal chars from end
709
+        while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) {
710
+            eIx--;
711
+        }
712
+
713
+        // get the padding count (=) (0, 1 or 2)
714
+        final int pad = s.charAt(eIx) == '=' ? (s.charAt(eIx - 1) == '=' ? 2
715
+                : 1) : 0; // Count '=' at end.
716
+        final int cCnt = eIx - sIx + 1; // Content count including possible
717
+                                        // separators
718
+        final int sepCnt = sLen > 76 ? (s.charAt(76) == '\r' ? cCnt / 78 : 0) << 1
719
+                : 0;
720
+
721
+        final int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of
722
+                                                          // decoded bytes
723
+        final byte[] dArr = new byte[len]; // Preallocate byte[] of exact length
724
+
725
+        // Decode all but the last 0 - 2 bytes.
726
+        int d = 0;
727
+        for (int cc = 0, eLen = len / 3 * 3; d < eLen;) {
728
+            // Assemble three bytes into an int from four "valid" characters.
729
+            final int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12
730
+                    | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
731
+
732
+            // Add the bytes
733
+            dArr[d++] = (byte) (i >> 16);
734
+            dArr[d++] = (byte) (i >> 8);
735
+            dArr[d++] = (byte) i;
736
+
737
+            // If line separator, jump over it.
738
+            if (sepCnt > 0 && ++cc == 19) {
739
+                sIx += 2;
740
+                cc = 0;
741
+            }
742
+        }
743
+
744
+        if (d < len) {
745
+            // Decode last 1-3 bytes (incl '=') into 1-3 bytes
746
+            int i = 0;
747
+            for (int j = 0; sIx <= eIx - pad; j++) {
748
+                i |= IA[s.charAt(sIx++)] << 18 - j * 6;
749
+            }
750
+
751
+            for (int r = 16; d < len; r -= 8) {
752
+                dArr[d++] = (byte) (i >> r);
753
+            }
754
+        }
755
+
756
+        return dArr;
757
+    }
758
+}

Loading…
取消
儲存