From ea1b464ddfc3fbd5c7c9e4755ec51cb9bb9ac7e8 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Thu, 2 Mar 2023 18:23:03 +0100 Subject: [PATCH] Implement writeUTF --- .../dbengine/buffers/BufDataOutput.java | 21 ++++++++++++++-- .../stream/SafeDataOutputStream.java | 24 +++++++++++++++---- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/main/java/it/cavallium/dbengine/buffers/BufDataOutput.java b/src/main/java/it/cavallium/dbengine/buffers/BufDataOutput.java index acd1260..238e213 100644 --- a/src/main/java/it/cavallium/dbengine/buffers/BufDataOutput.java +++ b/src/main/java/it/cavallium/dbengine/buffers/BufDataOutput.java @@ -1,5 +1,8 @@ package it.cavallium.dbengine.buffers; +import static org.warp.commonutils.stream.SafeDataOutputStream.strLen; +import static org.warp.commonutils.stream.SafeDataOutputStream.utfLen; + import it.unimi.dsi.fastutil.Arrays; import java.io.DataOutput; import java.io.IOException; @@ -178,9 +181,23 @@ public class BufDataOutput implements DataOutput { dOut.writeChars(s); } + private static String tooLongMsg(String s, int bits32) { + int slen = s.length(); + String head = s.substring(0, 8); + String tail = s.substring(slen - 8, slen); + // handle int overflow with max 3x expansion + long actualLength = (long)slen + Integer.toUnsignedLong(bits32 - slen); + return "encoded string (" + head + "..." + tail + ") too long: " + + actualLength + " bytes"; + } + @Override - public void writeUTF(@NotNull String s) { - throw new UnsupportedOperationException(); + public void writeUTF(@NotNull String str) { + var strlen = strLen(str); + var utflen = utfLen(str, strlen); + var bytes = Short.BYTES + utflen; + checkOutOfBounds(bytes); + dOut.writeUTF(strlen, utflen, str); } public Buf asList() { diff --git a/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java b/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java index be6b509..5d1aa94 100644 --- a/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java +++ b/src/main/java/org/warp/commonutils/stream/SafeDataOutputStream.java @@ -310,6 +310,10 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe writeUTF(str, this); } + public final void writeUTF(int strlen, int utflen, String str) { + writeUTF(strlen, utflen, str, this); + } + /** * Writes a string to the specified DataOutput using * modified UTF-8 @@ -330,18 +334,30 @@ public class SafeDataOutputStream extends SafeFilterOutputStream implements Safe * @return The number of bytes written out. */ static int writeUTF(String str, SafeDataOutput out) { - final int strlen = str.length(); - int utflen = strlen; // optimized for ASCII + int strlen = strLen(str); + int utflen = utfLen(str, strlen); + return writeUTF(strlen, utflen, str, out); + } - for (int i = 0; i < strlen; i++) { + public static int strLen(String str) { + return str.length(); + } + + public static int utfLen(String str, int strLen) { + int utflen = strLen; // optimized for ASCII + + for (int i = 0; i < strLen; i++) { int c = str.charAt(i); if (c >= 0x80 || c == 0) utflen += (c >= 0x800) ? 2 : 1; } - if (utflen > 65535 || /* overflow */ utflen < strlen) + if (utflen > 65535 || /* overflow */ utflen < strLen) throw new IllegalArgumentException(tooLongMsg(str, utflen)); + return utflen; + } + static int writeUTF(int strlen, int utflen, String str, SafeDataOutput out) { final byte[] bytearr; if (out instanceof SafeDataOutputStream) { SafeDataOutputStream dos = (SafeDataOutputStream)out;