001/**
002 * Java Web Archive Toolkit - Software to read and validate ARC, WARC
003 * and GZip files. (http://jwat.org/)
004 * Copyright 2011-2012 Netarkivet.dk (http://netarkivet.dk/)
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.jwat.common;
019
020import java.io.ByteArrayOutputStream;
021import java.util.Arrays;
022
023/**
024 * Base2 encoder/decoder implementation.
025 *
026 * @author nicl
027 */
028public class Base2 {
029
030    /** Ascii table used to encode. */
031    public static String[] encodeTab = {
032        "0000",
033        "0001",
034        "0010",
035        "0011",
036        "0100",
037        "0101",
038        "0110",
039        "0111",
040        "1000",
041        "1001",
042        "1010",
043        "1011",
044        "1100",
045        "1101",
046        "1110",
047        "1111"
048    };
049
050    /** Table used to decode. */
051    public static byte[] decodeTab = new byte[ 256 ];
052
053    /** Populate decode table. */
054    static {
055        Arrays.fill( decodeTab, (byte)0xff );
056        decodeTab[ '0' ] = 0;
057        decodeTab[ '1' ] = 1;
058    }
059
060    /**
061     * Static class.
062     */
063    protected Base2() {
064    }
065
066    /**
067     * Decodes an encoded string.
068     * @param in encoded string.
069     * @return decoded string or null
070     */
071    public static String decodeToString(String in) {
072        if (in == null) {
073            return null;
074        }
075        if (in.length() == 0) {
076            return "";
077        }
078        StringBuffer out = new StringBuffer( 256 );
079        boolean b = true;
080        int idx = 0;
081        char cin;
082        int mod = 0;
083        int cIdx;
084        int cout = 0;
085        while ( b ) {
086            if ( idx < in.length() ) {
087                cin = in.charAt( idx++ );
088                cIdx = decodeTab[ cin ];
089                if ( cIdx != -1 ) {
090                    cout = (cout << 1) | cIdx;
091                    mod = ( mod + 1 ) % 8;
092                    if ( mod == 0 ) {
093                        out.append( (char)cout );
094                        cout = 0;
095                    }
096                }
097                else {
098                    return null;
099                }
100            }
101            else {
102                b = false;
103            }
104        }
105        if ( mod == 0 ) {
106            return out.toString();
107        }
108        else {
109            return null;
110        }
111    }
112
113    /**
114     * Decodes an encoded string.
115     * @param in encoded string.
116     * @return decoded byte array or null
117     */
118    public static byte[] decodeToArray(String in) {
119        if (in == null) {
120            return null;
121        }
122        if (in.length() == 0) {
123            return new byte[0];
124        }
125        ByteArrayOutputStream out = new ByteArrayOutputStream();
126        boolean b = true;
127        int idx = 0;
128        char cin;
129        int mod = 0;
130        int cIdx;
131        int cout = 0;
132        while ( b ) {
133            if ( idx < in.length() ) {
134                cin = in.charAt( idx++ );
135                cIdx = decodeTab[ cin ];
136                if ( cIdx != -1 ) {
137                    cout = (cout << 1) | cIdx;
138                    mod = ( mod + 1 ) % 8;
139                    if ( mod == 0 ) {
140                        out.write( cout );
141                    }
142                }
143                else {
144                    return null;
145                }
146            }
147            else {
148                b = false;
149            }
150        }
151        if ( mod == 0 ) {
152            return out.toByteArray();
153        }
154        else {
155            return null;
156        }
157    }
158
159    /**
160     * Encodes a string.
161     * @param in unencoded text string.
162     * @return encoded string or null
163     */
164    public static String encodeString(String in) {
165        if (in == null) {
166            return null;
167        }
168        if (in.length() == 0) {
169            return "";
170        }
171        StringBuffer out = new StringBuffer( in.length() << 3 );
172        int cin;
173        for ( int i=0; i<in.length(); ++i ) {
174            cin = in.charAt( i );
175            if ( cin < 256 ) {
176                out.append( encodeTab[ (cin >> 4) & 15  ] );
177                out.append( encodeTab[ cin & 15 ] );
178            }
179            else {
180                return null;
181            }
182        }
183        return out.toString();
184    }
185
186    /**
187     * Encodes a byte array.
188     * @param in byte array.
189     * @return encoded string or null
190     */
191    public static String encodeArray(byte[] in) {
192        if (in == null) {
193            return null;
194        }
195        if (in.length == 0) {
196            return "";
197        }
198        StringBuffer out = new StringBuffer( in.length << 3 );
199        for ( int i=0; i<in.length; ++i ) {
200            out.append( encodeTab[ (in[ i ] >> 4) & 15  ] );
201            out.append( encodeTab[ in[ i ] & 15 ] );
202        }
203        return out.toString();
204    }
205
206    /**
207     * Insert regular delimiters in a string.
208     * @param inStr input string
209     * @param width interval width
210     * @param delimiter delimit character
211     * @return input string with delimiters inserted at specified intervals
212     */
213    public static String delimit(String inStr, int width, char delimiter) {
214        if (inStr == null) {
215            return null;
216        }
217        if (inStr.length() == 0) {
218            return "";
219        }
220        if ( width <= 0 ) {
221            return inStr;
222        }
223        StringBuffer outSb = new StringBuffer( inStr.length() + (inStr.length() + width - 1) / width );
224        int idx = 0;
225        int lIdx = width;
226        while ( idx < inStr.length() ) {
227            if ( idx == lIdx ) {
228                outSb.append( delimiter );
229                lIdx += width;
230            }
231            outSb.append( inStr.charAt( idx++ ) );
232        }
233        return outSb.toString();
234    }
235
236}