blob: 9793333226b3eceb6e622b73c89e91d9d3e8c1f4 [file] [log] [blame]
/*
* Copyright 2014 Google Inc. All rights reserved.
*
* 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 com.google.flatbuffers;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
import java.nio.charset.StandardCharsets;
/**
* This class implements the Utf8 API using the Java Utf8 encoder. Use
* Utf8.setDefault(new Utf8Old()); to use it.
*/
public class Utf8Old extends Utf8 {
private static class Cache {
final CharsetEncoder encoder;
final CharsetDecoder decoder;
CharSequence lastInput = null;
ByteBuffer lastOutput = null;
Cache() {
encoder = StandardCharsets.UTF_8.newEncoder();
decoder = StandardCharsets.UTF_8.newDecoder();
}
}
private static final ThreadLocal<Cache> CACHE =
ThreadLocal.withInitial(() -> new Cache());
// Play some games so that the old encoder doesn't pay twice for computing
// the length of the encoded string.
@Override
public int encodedLength(CharSequence in) {
final Cache cache = CACHE.get();
int estimated = (int) (in.length() * cache.encoder.maxBytesPerChar());
if (cache.lastOutput == null || cache.lastOutput.capacity() < estimated) {
cache.lastOutput = ByteBuffer.allocate(Math.max(128, estimated));
}
cache.lastOutput.clear();
cache.lastInput = in;
CharBuffer wrap = (in instanceof CharBuffer) ?
(CharBuffer) in : CharBuffer.wrap(in);
CoderResult result = cache.encoder.encode(wrap, cache.lastOutput, true);
if (result.isError()) {
try {
result.throwException();
} catch (CharacterCodingException e) {
throw new IllegalArgumentException("bad character encoding", e);
}
}
return cache.lastOutput.remaining();
}
@Override
public void encodeUtf8(CharSequence in, ByteBuffer out) {
final Cache cache = CACHE.get();
if (cache.lastInput != in) {
// Update the lastOutput to match our input, although flatbuffer should
// never take this branch.
encodedLength(in);
}
out.put(cache.lastOutput);
}
@Override
public String decodeUtf8(ByteBuffer buffer, int offset, int length) {
CharsetDecoder decoder = CACHE.get().decoder;
decoder.reset();
buffer = buffer.duplicate();
buffer.position(offset);
buffer.limit(offset + length);
try {
CharBuffer result = decoder.decode(buffer);
result.flip();
return result.toString();
} catch (CharacterCodingException e) {
throw new IllegalArgumentException("Bad encoding", e);
}
}
}