All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.schlichtherle.nio.charset.OctetCharset Maven / Gradle / Ivy

/*
 * Copyright (C) 2005-2010 Schlichtherle IT Services
 *
 * 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 de.schlichtherle.nio.charset;

import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.util.Arrays;

/**
 * A memory efficient base class for simple 8 bit (octet) character sets.
 *
 * @author Christian Schlichtherle
 * @version $Id: OctetCharset.java 5e709f50671d 2010/11/05 11:52:07 christian $
 */
public abstract class OctetCharset extends Charset {

    /**
     * Use this character in the lookup table provided to the constructor for
     * every character that does not have a replacement in 16 bit Unicode.
     */
    protected static final char REPLACEMENT = 0xFFFD;

    private final char[] byte2char;
    private final char[][] char2byte;

    protected OctetCharset(
            final String cname,
            final String[] aliases,
            final char[] byte2char) {
        super(cname, aliases);

        // Construct sparse inverse lookup table.
        final char[][] char2byte = new char[256][];
        for (char i = 0; i < 256; i++) {
            final char c = byte2char[i];
            if (c == REPLACEMENT)
                continue;

            final int hi = c >>> 8;
            final int lo = c & 0xFF;
            char[] table = char2byte[hi];
            if (table == null) {
                table = new char[256];
                Arrays.fill(table, REPLACEMENT);
                char2byte[hi] = table;
            }
            table[lo] = i;
        }

        this.byte2char = byte2char;
        this.char2byte = char2byte;
    }

    public boolean contains(Charset cs) {
        return this.getClass().isInstance(cs);
    }

    public CharsetEncoder newEncoder() {
        return new Encoder();
    }

    protected class Encoder extends CharsetEncoder {
        protected Encoder() {
            super(OctetCharset.this, 1, 1);
        }

        protected CoderResult encodeLoop(
                final CharBuffer in,
                final ByteBuffer out) {
            final char[][] c2b = char2byte;
            while (in.hasRemaining()) {
                if (!out.hasRemaining())
                    return CoderResult.OVERFLOW;
                final char c = in.get();
                final int hi = c >>> 8;
                final int lo = c & 0xFF;
                final char[] table = c2b[hi];
                final char b;
                if (table == null || (b = table[lo]) == REPLACEMENT) { // char is unsigned!
                    in.position(in.position() - 1); // push back
                    return CoderResult.unmappableForLength(1);
                }
                out.put((byte) b); // char is unsigned!
            }
            return CoderResult.UNDERFLOW;
        }
    }

    public CharsetDecoder newDecoder() {
        return new Decoder();
    }

    protected class Decoder extends CharsetDecoder {
        protected Decoder() {
            super(OctetCharset.this, 1, 1);
        }

        protected CoderResult decodeLoop(
                final ByteBuffer in,
                final CharBuffer out) {
            final char[] b2c = byte2char;
            while (in.hasRemaining()) {
                if (!out.hasRemaining())
                    return CoderResult.OVERFLOW;
                final char c = b2c[in.get() & 0xFF];
                if (c == REPLACEMENT) {
                    in.position(in.position() - 1); // push back
                    return CoderResult.unmappableForLength(1);
                }
                out.put(c);
            }
            return CoderResult.UNDERFLOW;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy