aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smack/util/Base32Encoder.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/jivesoftware/smack/util/Base32Encoder.java')
-rw-r--r--src/org/jivesoftware/smack/util/Base32Encoder.java184
1 files changed, 184 insertions, 0 deletions
diff --git a/src/org/jivesoftware/smack/util/Base32Encoder.java b/src/org/jivesoftware/smack/util/Base32Encoder.java
new file mode 100644
index 0000000..0a4ea21
--- /dev/null
+++ b/src/org/jivesoftware/smack/util/Base32Encoder.java
@@ -0,0 +1,184 @@
+/**
+ * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.jivesoftware.smack.util;
+
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Base32 string encoding is useful for when filenames case-insensitive filesystems are encoded.
+ * Base32 representation takes roughly 20% more space then Base64.
+ *
+ * @author Florian Schmaus
+ * Based on code by Brian Wellington (bwelling@xbill.org)
+ * @see <a href="http://en.wikipedia.org/wiki/Base32">Base32 Wikipedia entry<a>
+ *
+ */
+public class Base32Encoder implements StringEncoder {
+
+ private static Base32Encoder instance = new Base32Encoder();
+ private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ2345678";
+
+ private Base32Encoder() {
+ // Use getInstance()
+ }
+
+ public static Base32Encoder getInstance() {
+ return instance;
+ }
+
+ @Override
+ public String decode(String str) {
+ ByteArrayOutputStream bs = new ByteArrayOutputStream();
+ byte[] raw = str.getBytes();
+ for (int i = 0; i < raw.length; i++) {
+ char c = (char) raw[i];
+ if (!Character.isWhitespace(c)) {
+ c = Character.toUpperCase(c);
+ bs.write((byte) c);
+ }
+ }
+
+ while (bs.size() % 8 != 0)
+ bs.write('8');
+
+ byte[] in = bs.toByteArray();
+
+ bs.reset();
+ DataOutputStream ds = new DataOutputStream(bs);
+
+ for (int i = 0; i < in.length / 8; i++) {
+ short[] s = new short[8];
+ int[] t = new int[5];
+
+ int padlen = 8;
+ for (int j = 0; j < 8; j++) {
+ char c = (char) in[i * 8 + j];
+ if (c == '8')
+ break;
+ s[j] = (short) ALPHABET.indexOf(in[i * 8 + j]);
+ if (s[j] < 0)
+ return null;
+ padlen--;
+ }
+ int blocklen = paddingToLen(padlen);
+ if (blocklen < 0)
+ return null;
+
+ // all 5 bits of 1st, high 3 (of 5) of 2nd
+ t[0] = (s[0] << 3) | s[1] >> 2;
+ // lower 2 of 2nd, all 5 of 3rd, high 1 of 4th
+ t[1] = ((s[1] & 0x03) << 6) | (s[2] << 1) | (s[3] >> 4);
+ // lower 4 of 4th, high 4 of 5th
+ t[2] = ((s[3] & 0x0F) << 4) | ((s[4] >> 1) & 0x0F);
+ // lower 1 of 5th, all 5 of 6th, high 2 of 7th
+ t[3] = (s[4] << 7) | (s[5] << 2) | (s[6] >> 3);
+ // lower 3 of 7th, all of 8th
+ t[4] = ((s[6] & 0x07) << 5) | s[7];
+
+ try {
+ for (int j = 0; j < blocklen; j++)
+ ds.writeByte((byte) (t[j] & 0xFF));
+ } catch (IOException e) {
+ }
+ }
+
+ return new String(bs.toByteArray());
+ }
+
+ @Override
+ public String encode(String str) {
+ byte[] b = str.getBytes();
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+
+ for (int i = 0; i < (b.length + 4) / 5; i++) {
+ short s[] = new short[5];
+ int t[] = new int[8];
+
+ int blocklen = 5;
+ for (int j = 0; j < 5; j++) {
+ if ((i * 5 + j) < b.length)
+ s[j] = (short) (b[i * 5 + j] & 0xFF);
+ else {
+ s[j] = 0;
+ blocklen--;
+ }
+ }
+ int padlen = lenToPadding(blocklen);
+
+ // convert the 5 byte block into 8 characters (values 0-31).
+
+ // upper 5 bits from first byte
+ t[0] = (byte) ((s[0] >> 3) & 0x1F);
+ // lower 3 bits from 1st byte, upper 2 bits from 2nd.
+ t[1] = (byte) (((s[0] & 0x07) << 2) | ((s[1] >> 6) & 0x03));
+ // bits 5-1 from 2nd.
+ t[2] = (byte) ((s[1] >> 1) & 0x1F);
+ // lower 1 bit from 2nd, upper 4 from 3rd
+ t[3] = (byte) (((s[1] & 0x01) << 4) | ((s[2] >> 4) & 0x0F));
+ // lower 4 from 3rd, upper 1 from 4th.
+ t[4] = (byte) (((s[2] & 0x0F) << 1) | ((s[3] >> 7) & 0x01));
+ // bits 6-2 from 4th
+ t[5] = (byte) ((s[3] >> 2) & 0x1F);
+ // lower 2 from 4th, upper 3 from 5th;
+ t[6] = (byte) (((s[3] & 0x03) << 3) | ((s[4] >> 5) & 0x07));
+ // lower 5 from 5th;
+ t[7] = (byte) (s[4] & 0x1F);
+
+ // write out the actual characters.
+ for (int j = 0; j < t.length - padlen; j++) {
+ char c = ALPHABET.charAt(t[j]);
+ os.write(c);
+ }
+ }
+ return new String(os.toByteArray());
+ }
+
+ private static int lenToPadding(int blocklen) {
+ switch (blocklen) {
+ case 1:
+ return 6;
+ case 2:
+ return 4;
+ case 3:
+ return 3;
+ case 4:
+ return 1;
+ case 5:
+ return 0;
+ default:
+ return -1;
+ }
+ }
+
+ private static int paddingToLen(int padlen) {
+ switch (padlen) {
+ case 6:
+ return 1;
+ case 4:
+ return 2;
+ case 3:
+ return 3;
+ case 1:
+ return 4;
+ case 0:
+ return 5;
+ default:
+ return -1;
+ }
+ }
+
+}