jnr.ffi.provider.converters.StringUtil Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jnr-ffi Show documentation
Show all versions of jnr-ffi Show documentation
A library for invoking native functions from java
The newest version!
/*
* Copyright (C) 2012 Wayne Meissner
*
* This file is part of the JNR project.
*
* 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 jnr.ffi.provider.converters;
import jnr.ffi.annotations.Encoding;
import jnr.ffi.mapper.MethodParameterContext;
import jnr.ffi.mapper.ToNativeContext;
import java.lang.annotation.Annotation;
import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.nio.ByteBuffer;
import java.nio.charset.CharacterCodingException;
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;
import java.util.Collection;
final class StringUtil {
private StringUtil() {}
static CharsetEncoder getEncoder(Charset charset, ThreadLocal> localEncoder) {
Reference ref = localEncoder.get();
CharsetEncoder encoder;
return ref != null && (encoder = ref.get()) != null && encoder.charset() == charset
? encoder : initEncoder(charset, localEncoder);
}
static CharsetDecoder getDecoder(Charset charset, ThreadLocal> localDecoder) {
Reference ref = localDecoder.get();
CharsetDecoder decoder;
return ref != null && (decoder = ref.get()) != null && decoder.charset() == charset
? decoder : initDecoder(charset, localDecoder);
}
private static CharsetEncoder initEncoder(Charset charset, ThreadLocal> localEncoder) {
CharsetEncoder encoder = charset.newEncoder();
encoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
localEncoder.set(new SoftReference(encoder));
return encoder;
}
private static CharsetDecoder initDecoder(Charset charset, ThreadLocal> localDecoder) {
CharsetDecoder decoder = charset.newDecoder();
decoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE);
localDecoder.set(new SoftReference(decoder));
return decoder;
}
static Charset getCharset(ToNativeContext toNativeContext) {
Charset charset = Charset.defaultCharset();
if (toNativeContext instanceof MethodParameterContext) {
// See if the interface class has a global @Encoding declaration
Charset cs = getEncodingCharset(Arrays.asList(((MethodParameterContext) toNativeContext).getMethod().getDeclaringClass().getAnnotations()));
if (cs != null) {
charset = cs;
}
// Allow each method to override the default
cs = getEncodingCharset(Arrays.asList(((MethodParameterContext) toNativeContext).getMethod().getAnnotations()));
if (cs != null) {
charset = cs;
}
}
// Override on a per-parameter basis
Charset cs = getEncodingCharset(toNativeContext.getAnnotations());
if (cs != null) {
charset = cs;
}
return charset;
}
private static Charset getEncodingCharset(Collection annotations) {
for (Annotation a : annotations) {
if (a instanceof Encoding) {
return Charset.forName(((Encoding) a).value());
}
}
return null;
}
static void throwException(CoderResult result) {
try {
result.throwException();
} catch (RuntimeException re) {
throw re;
} catch (CharacterCodingException cce) {
throw new RuntimeException(cce);
}
}
private static final Charset UTF8 = Charset.forName("UTF-8");
private static final Charset USASCII = Charset.forName("US-ASCII");
private static final Charset ISO8859_1 = Charset.forName("ISO-8859-1");
private static final Charset UTF16 = Charset.forName("UTF-16");
private static final Charset UTF16LE = Charset.forName("UTF-16LE");
private static final Charset UTF16BE = Charset.forName("UTF-16BE");
static int terminatorWidth(Charset charset) {
if (charset.equals(UTF8) || charset.equals(USASCII) || charset.equals(ISO8859_1)) {
return 1;
} else if (charset.equals(UTF16) || charset.equals(UTF16LE) || charset.equals(UTF16BE)) {
return 2;
} else {
return 4;
}
}
static int stringLength(ByteBuffer in, int terminatorWidth) {
if (in.hasArray()) {
byte[] array = in.array();
int end = in.arrayOffset() + in.limit();
int tcount = 0;
for (int idx = in.arrayOffset() + in.position(); idx < end; ) {
if (array[idx++] == 0) {
tcount++;
} else {
tcount = 0;
}
if (tcount == terminatorWidth) {
return idx - terminatorWidth;
}
}
} else {
int begin = in.position();
int end = in.limit();
int tcount = 0;
for (int idx = begin; idx < end; ) {
if (in.get(idx++) == 0) {
tcount++;
} else {
tcount = 0;
}
if (tcount == terminatorWidth) {
return idx - terminatorWidth;
}
}
}
return -1;
}
}