1 // Copyright 2020 The Pigweed Authors
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
7 // https://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
16 * This is a Java Native Interface (JNI) wrapper for the Detokenizer class.
18 * <p>This classes uses the Android Base64 library instead of the standard Java Base64, which is not
19 * yet available on Android. To use this class outside of Android, replace android.util.Base64 with
22 package dev.pigweed.tokenizer;
24 import android.util.Base64;
25 import java.util.regex.Matcher;
26 import java.util.regex.Pattern;
28 /** This class provides the Java interface for the C++ Detokenizer class. */
29 public class Detokenizer {
30 // Android's Base64 library doesn't seem to check if the Base64-encoded data is valid. This
31 // regular expression checks that it is. Does not match URL-safe or unpadded Base64.
32 private static final Pattern TOKENIZED_STRING =
33 Pattern.compile("\\$([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?");
36 System.loadLibrary("detokenizer");
39 // The handle to the C++ detokenizer instance.
40 private final long handle;
42 public Detokenizer() {
46 public Detokenizer(byte[] tokenDatabase) {
47 handle = newNativeDetokenizer(tokenDatabase);
51 * Detokenizes and replaces all recognized tokenized messages ($ followed by Base64) in the
52 * provided string. Unrecognized tokenized strings are left unchanged.
54 public String detokenize(String message) {
55 Matcher matcher = TOKENIZED_STRING.matcher(message);
56 StringBuilder result = new StringBuilder();
59 while (matcher.find()) {
60 result.append(message, lastIndex, matcher.start());
63 detokenizeNative(handle, Base64.decode(matcher.group().substring(1), Base64.DEFAULT));
64 result.append(decoded != null ? decoded : matcher.group());
66 lastIndex = matcher.end();
69 result.append(message, lastIndex, message.length());
70 return result.toString();
73 /** Deletes memory allocated in C++ when this class is garbage collected. */
75 protected void finalize() {
76 deleteNativeDetokenizer(handle);
79 /** Creates a new detokenizer using the provided data as the database. */
80 private static native long newNativeDetokenizer(byte[] data);
82 /** Deletes the detokenizer object with the provided handle, which MUST be valid. */
83 private static native void deleteNativeDetokenizer(long handle);
86 * Returns the detokenized version of the provided data. This is non-static so this object has a
87 * reference held while the function is running, which prevents finalize from running before
88 * detokenizeNative finishes.
90 private native String detokenizeNative(long handle, byte[] data);