package com.tesora.dve.common; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.lang.ref.SoftReference; 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.nio.charset.CodingErrorAction; import java.util.Arrays; public final class PECharsetUtils { public static final Charset UTF_8 = Charset.forName("UTF-8"); public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1"); private static ThreadLocal<SoftReference<CharsetDecoder>> decoder = new ThreadLocal<SoftReference<CharsetDecoder>>(); private static ThreadLocal<SoftReference<CharsetEncoder>> encoder = new ThreadLocal<SoftReference<CharsetEncoder>>(); public static final Charset latin1 = Charset.forName("ISO-8859-1"); private PECharsetUtils() { } private static <T> T deref(ThreadLocal<SoftReference<T>> tl) { SoftReference<T> sr = (SoftReference<T>) tl.get(); if (sr == null) return null; return sr.get(); } private static <T> void set(ThreadLocal<SoftReference<T>> tl, T ob) { tl.set(new SoftReference<T>(ob)); } public static String getString(byte[] bytesIn, Charset cs) { return getString(bytesIn, cs, false); } public static String getString(byte[] bytesIn, Charset cs, boolean checkIfValid ) { if ( checkIfValid ) return getString(bytesIn, cs, CodingErrorAction.REPORT); else return getString(bytesIn, cs, CodingErrorAction.REPLACE); } static String getString(byte[] bytesIn, Charset cs, CodingErrorAction cea) { CharsetDecoder cd = (CharsetDecoder) deref(decoder); if ((cd == null) || (!cs.name().equals(cd.charset().name()))) { cd = cs.newDecoder(); set(decoder, cd); } int en = scale(bytesIn.length, cd.maxCharsPerByte()); char[] charOut = new char[en]; if (bytesIn.length == 0) return new String(charOut); CharBuffer cb = CharBuffer.wrap(charOut); CoderResult cr = cd.onMalformedInput(cea).onUnmappableCharacter(cea) .decode(ByteBuffer.wrap(bytesIn), cb, true); if (cr.isMalformed() || cr.isUnmappable()) charOut = null; return ( charOut == null ? null : new String(safeTrim(charOut, cb.position()))); } public static byte[] getBytes(String stringIn, Charset cs) { return getBytes(stringIn, cs, false); } public static byte[] getBytes(String stringIn, Charset cs, boolean checkIfValid) { if ( checkIfValid ) return getBytes(stringIn, cs, CodingErrorAction.REPORT); else return getBytes(stringIn, cs, CodingErrorAction.REPLACE); } static byte[] getBytes(String stringIn, Charset cs, CodingErrorAction cea) { CharsetEncoder ce = (CharsetEncoder) deref(encoder); if ((ce == null) || (!cs.name().equals(ce.charset().name()))) { ce = cs.newEncoder(); set(encoder, ce); } int en = scale(stringIn.length(), ce.maxBytesPerChar()); byte[] bytesOut = new byte[en]; if (stringIn.length() == 0) return bytesOut; ByteBuffer bb = ByteBuffer.wrap(bytesOut); CoderResult cr = ce.onMalformedInput(cea).onUnmappableCharacter(cea) .encode(CharBuffer.wrap(stringIn), bb, true); if (cr.isMalformed() || cr.isUnmappable()) bytesOut = null; return safeTrim(bytesOut, bb.position()); } private static byte[] safeTrim(byte[] ba, int len) { if ( ba == null) return null; if (len == ba.length) return ba; else return Arrays.copyOf(ba, len); } private static char[] safeTrim(char[] ca, int len) { if ( ca == null) return null; if (len == ca.length) return ca; else return Arrays.copyOf(ca, len); } private static int scale(int len, float expansionFactor) { return (int) (len * (double) expansionFactor); } }