1 /* 2 * Copyright 2014 Google Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.flatbuffers; 18 19 import java.nio.ByteBuffer; 20 import java.nio.CharBuffer; 21 import java.nio.charset.CharacterCodingException; 22 import java.nio.charset.CharsetDecoder; 23 import java.nio.charset.CharsetEncoder; 24 import java.nio.charset.CoderResult; 25 import java.nio.charset.StandardCharsets; 26 27 /** 28 * This class implements the Utf8 API using the Java Utf8 encoder. Use 29 * Utf8.setDefault(new Utf8Old()); to use it. 30 */ 31 public class Utf8Old extends Utf8 { 32 33 private static class Cache { 34 final CharsetEncoder encoder; 35 final CharsetDecoder decoder; 36 CharSequence lastInput = null; 37 ByteBuffer lastOutput = null; 38 Cache()39 Cache() { 40 encoder = StandardCharsets.UTF_8.newEncoder(); 41 decoder = StandardCharsets.UTF_8.newDecoder(); 42 } 43 } 44 45 private static final ThreadLocal<Cache> CACHE = 46 ThreadLocal.withInitial(() -> new Cache()); 47 48 // Play some games so that the old encoder doesn't pay twice for computing 49 // the length of the encoded string. 50 51 @Override encodedLength(CharSequence in)52 public int encodedLength(CharSequence in) { 53 final Cache cache = CACHE.get(); 54 int estimated = (int) (in.length() * cache.encoder.maxBytesPerChar()); 55 if (cache.lastOutput == null || cache.lastOutput.capacity() < estimated) { 56 cache.lastOutput = ByteBuffer.allocate(Math.max(128, estimated)); 57 } 58 cache.lastOutput.clear(); 59 cache.lastInput = in; 60 CharBuffer wrap = (in instanceof CharBuffer) ? 61 (CharBuffer) in : CharBuffer.wrap(in); 62 CoderResult result = cache.encoder.encode(wrap, cache.lastOutput, true); 63 if (result.isError()) { 64 try { 65 result.throwException(); 66 } catch (CharacterCodingException e) { 67 throw new IllegalArgumentException("bad character encoding", e); 68 } 69 } 70 return cache.lastOutput.remaining(); 71 } 72 73 @Override encodeUtf8(CharSequence in, ByteBuffer out)74 public void encodeUtf8(CharSequence in, ByteBuffer out) { 75 final Cache cache = CACHE.get(); 76 if (cache.lastInput != in) { 77 // Update the lastOutput to match our input, although flatbuffer should 78 // never take this branch. 79 encodedLength(in); 80 } 81 out.put(cache.lastOutput); 82 } 83 84 @Override decodeUtf8(ByteBuffer buffer, int offset, int length)85 public String decodeUtf8(ByteBuffer buffer, int offset, int length) { 86 CharsetDecoder decoder = CACHE.get().decoder; 87 decoder.reset(); 88 buffer = buffer.duplicate(); 89 buffer.position(offset); 90 buffer.limit(offset + length); 91 try { 92 CharBuffer result = decoder.decode(buffer); 93 result.flip(); 94 return result.toString(); 95 } catch (CharacterCodingException e) { 96 throw new IllegalArgumentException("Bad encoding", e); 97 } 98 } 99 } 100