blob: 3dac714bb67d6b24d6935df8278173ccf04ab07b [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001/*
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
17package com.google.flatbuffers;
18
19import java.nio.ByteBuffer;
20import java.nio.CharBuffer;
21import java.nio.charset.CharacterCodingException;
22import java.nio.charset.CharsetDecoder;
23import java.nio.charset.CharsetEncoder;
24import java.nio.charset.CoderResult;
25import 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 */
31public 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
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
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 cache.lastOutput.flip();
71 return cache.lastOutput.remaining();
72 }
73
74 @Override
75 public void encodeUtf8(CharSequence in, ByteBuffer out) {
76 final Cache cache = CACHE.get();
77 if (cache.lastInput != in) {
78 // Update the lastOutput to match our input, although flatbuffer should
79 // never take this branch.
80 encodedLength(in);
81 }
82 out.put(cache.lastOutput);
83 }
84
85 @Override
86 public String decodeUtf8(ByteBuffer buffer, int offset, int length) {
87 CharsetDecoder decoder = CACHE.get().decoder;
88 decoder.reset();
89 buffer = buffer.duplicate();
90 buffer.position(offset);
91 buffer.limit(offset + length);
92 try {
93 CharBuffer result = decoder.decode(buffer);
94 return result.toString();
95 } catch (CharacterCodingException e) {
96 throw new IllegalArgumentException("Bad encoding", e);
97 }
98 }
99}