3030package org .scijava .io .handle ;
3131
3232import java .io .DataOutput ;
33- import java .io .DataOutputStream ;
3433import java .io .IOException ;
35- import java .lang .reflect .InvocationTargetException ;
36- import java .lang .reflect .Method ;
34+ import java .io .UTFDataFormatException ;
3735
3836import org .scijava .io .location .Location ;
3937import org .scijava .task .Task ;
4644 */
4745public final class DataHandles {
4846
49- private static Method utfMethod ;
50-
5147 private DataHandles () {
5248 // Prevent instantiation of utility class.
5349 }
@@ -74,40 +70,38 @@ private DataHandles() {
7470 public static int writeUTF (final String str , final DataOutput out )
7571 throws IOException
7672 {
77- // HACK: Strangely, DataOutputStream.writeUTF(String, DataOutput)
78- // has package-private access. We work around it via reflection.
79- try {
80- return (Integer ) utfMethod ().invoke (null , str , out );
81- }
82- catch (final IllegalAccessException | IllegalArgumentException
83- | InvocationTargetException exc )
84- {
85- throw new IllegalStateException (
86- "Cannot invoke DataOutputStream.writeUTF(String, DataOutput)" , exc );
73+ // Encode string as modified UTF-8 per java.io.DataOutput specification.
74+ final int strlen = str .length ();
75+ int utflen = 0 ;
76+ for (int i = 0 ; i < strlen ; i ++) {
77+ final char c = str .charAt (i );
78+ if (c >= '\u0001' && c <= '\u007F' ) utflen += 1 ;
79+ else if (c <= '\u07FF' ) utflen += 2 ;
80+ else utflen += 3 ;
8781 }
88- }
89-
90- // -- Helper methods --
91-
92- /** Gets the {@link #utfMethod} field, initializing if needed. */
93- private static Method utfMethod () {
94- if (utfMethod == null ) initUTFMethod ();
95- return utfMethod ;
96- }
97-
98- /** Initializes the {@link #utfMethod} field. */
99- private static synchronized void initUTFMethod () {
100- if (utfMethod != null ) return ;
101- try {
102- final Method m = DataOutputStream .class .getDeclaredMethod ("writeUTF" ,
103- String .class , DataOutput .class );
104- m .setAccessible (true );
105- utfMethod = m ;
106- }
107- catch (final NoSuchMethodException | SecurityException exc ) {
108- throw new IllegalStateException (
109- "No usable DataOutputStream.writeUTF(String, DataOutput)" , exc );
82+ if (utflen > 65535 ) throw new UTFDataFormatException (
83+ "encoded string too long: " + utflen + " bytes" );
84+ final byte [] bytes = new byte [utflen + 2 ];
85+ bytes [0 ] = (byte ) ((utflen >>> 8 ) & 0xFF );
86+ bytes [1 ] = (byte ) (utflen & 0xFF );
87+ int pos = 2 ;
88+ for (int i = 0 ; i < strlen ; i ++) {
89+ final char c = str .charAt (i );
90+ if (c >= '\u0001' && c <= '\u007F' ) {
91+ bytes [pos ++] = (byte ) c ;
92+ }
93+ else if (c <= '\u07FF' ) {
94+ bytes [pos ++] = (byte ) (0xC0 | ((c >> 6 ) & 0x1F ));
95+ bytes [pos ++] = (byte ) (0x80 | (c & 0x3F ));
96+ }
97+ else {
98+ bytes [pos ++] = (byte ) (0xE0 | ((c >> 12 ) & 0x0F ));
99+ bytes [pos ++] = (byte ) (0x80 | ((c >> 6 ) & 0x3F ));
100+ bytes [pos ++] = (byte ) (0x80 | (c & 0x3F ));
101+ }
110102 }
103+ out .write (bytes );
104+ return utflen + 2 ;
111105 }
112106
113107 protected static IOException readOnlyException () {
0 commit comments