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;
021
022/**
023 * Small class to decode and encode ISO-8859-1 strings while also validating
024 * them. Invalid characters are removed in the conversion.
025 * Non static because not all information can be returned by the methods.
026 *
027 * @author nicl
028 */
029public class ISO8859_1 {
030
031    /** Array of valid bytes according to the ISO-8859-1 specification. */
032    public static final byte[] validBytes = new byte[256];
033
034    /** Populate array of valid ISO-8859-1 bytes. */
035    static {
036        int i;
037        for (i=0; i<32; ++i) {
038            validBytes[i] = 0;
039        }
040        for (i=32; i<127; ++i) {
041            validBytes[i] = (byte)i;
042        }
043        validBytes[127] = 0;
044        for (i=128; i<256; ++i) {
045            validBytes[i] = (byte)i;
046        }
047    }
048
049    /**
050     * Construct an instance that can be used to convert and validate.
051     */
052    public ISO8859_1() {
053    }
054
055    /** Encoded string after call to encode method.
056     *  Invalid chars will have been removed if the method returns false. */
057    public byte[] encoded;
058
059    /**
060     * Converts a string to a byte array removing invalid characters in the
061     * process and returning the validity status. The converted byte array
062     * is accessible through a separate field.
063     * @param inStr string to be converted and validated
064     * @param exceptions invalid characters which are allowed
065     * @return validity status of string to byte array conversion
066     */
067    public boolean encode(String inStr, String exceptions) {
068        boolean valid = true;
069        StringBuffer sb = new StringBuffer();
070        ByteArrayOutputStream out = new ByteArrayOutputStream();
071        char c;
072        for (int i=0; i<inStr.length(); ++i) {
073            c = inStr.charAt(i);
074            if (c < 256) {
075                if (validBytes[c] != 0 || exceptions.indexOf(c) != -1) {
076                    sb.append((char)c);
077                    out.write(c);
078                } else {
079                    valid = false;
080                }
081            } else {
082                valid = false;
083            }
084        }
085        // Exposes a valid decoded string with invalid chars filtered out.
086        decoded = sb.toString();
087        encoded = out.toByteArray();
088        return valid;
089    }
090
091    /** Decode byte array after call to decode method.
092     *  Invalid chars will have been removed if the method returns false. */
093    public String decoded;
094
095    /**
096     * Converts a byte array to a string removing invalid characters in the
097     * process and returning the validity status. The converted string is
098     * accessible through a separate field.
099     * @param inBytes byte array to be converted and validated
100     * @param exceptions invalid characters which are allowed
101     * @return validity status of byte array to string conversion
102     */
103    public boolean decode(byte[] inBytes, String exceptions) {
104        boolean valid = true;
105        StringBuffer sb = new StringBuffer();
106        int c;
107        for (int i=0; i<inBytes.length; ++i) {
108            c = inBytes[i] & 255;
109            if (validBytes[c] != 0 || exceptions.indexOf(c) != -1 ) {
110                sb.append((char)c);
111            } else {
112                valid = false;
113            }
114        }
115        decoded = sb.toString();
116        return valid;
117    }
118
119}