1 /* 2 * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.jimage; 27 28 import java.io.UTFDataFormatException; 29 import java.nio.ByteBuffer; 30 import java.util.Objects; 31 32 /** 33 * @implNote This class needs to maintain JDK 8 source compatibility. 34 * 35 * It is used internally in the JDK to implement jimage/jrtfs access, 36 * but also compiled and delivered as part of the jrtfs.jar to support access 37 * to the jimage file provided by the shipped JDK by tools running on JDK 8. 38 */ 39 public class ImageStringsReader implements ImageStrings { 40 public static final int HASH_MULTIPLIER = 0x01000193; 41 private final BasicImageReader reader; 42 43 ImageStringsReader(BasicImageReader reader) { 44 this.reader = Objects.requireNonNull(reader); 45 } 46 47 @Override 48 public String get(int offset) { 49 return reader.getString(offset); 50 } 51 52 @Override 53 public int add(final String string) { 54 throw new InternalError("Can not add strings at runtime"); 55 } 56 57 private static int hashCode(byte[] bytes, int offset, int count, int seed) { 58 Objects.requireNonNull(bytes); 59 60 if (offset < 0 || count < 0 || offset > bytes.length - count) { 61 throw new IndexOutOfBoundsException("offset=" + offset + ", count=" + count); 62 } 63 64 int limit = offset + count; 65 66 if (limit < 0 || limit > bytes.length) { 67 throw new IndexOutOfBoundsException("limit=" + limit); 68 } 69 70 for (int i = offset; i < limit; i++) { 71 seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF); 72 } 73 74 return seed & 0x7FFFFFFF; 75 } 76 77 public static int hashCode(byte[] bytes, int seed) { 78 return hashCode(bytes, 0, bytes.length, seed); 79 } 80 81 public static int hashCode(byte[] bytes) { 82 return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER); 83 } 84 85 public static int hashCode(String string) { 86 return hashCode(string, HASH_MULTIPLIER); 87 } 88 89 public static int hashCode(String string, int seed) { 90 91 int slen = string.length(); 92 byte[] buffer = null; 93 94 for (int i = 0; i < slen; i++) { 95 char ch = string.charAt(i); 96 int uch = ch & 0xFFFF; 97 98 if ((uch & ~0x7F) != 0) { 99 if (buffer == null) { 100 buffer = new byte[8]; 101 } 102 int mask = ~0x3F; 103 int n = 0; 104 105 do { 106 buffer[n++] = (byte)(0x80 | (uch & 0x3F)); 107 uch >>= 6; 108 mask >>= 1; 109 } while ((uch & mask) != 0); 110 111 buffer[n] = (byte)((mask << 1) | uch); 112 113 do { 114 seed = (seed * HASH_MULTIPLIER) ^ (buffer[n--] & 0xFF); 115 } while (0 <= n); 116 } else if (uch == 0) { 117 seed = (seed * HASH_MULTIPLIER) ^ (0xC0); 118 seed = (seed * HASH_MULTIPLIER) ^ (0x80); 119 } else { 120 seed = (seed * HASH_MULTIPLIER) ^ (uch); 121 } 122 } 123 124 return seed & 0x7FFFFFFF; 125 } 126 127 static int charsFromMUTF8Length(byte[] bytes, int offset, int count) { 128 int length = 0; 129 130 for (int i = offset; i < offset + count; i++) { 131 byte ch = bytes[i]; 132 133 if (ch == 0) { 134 break; 135 } 136 137 if ((ch & 0xC0) != 0x80) { 138 length++; 139 } 140 } 141 142 return length; 143 } 144 145 static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException { 146 int j = 0; 147 148 for (int i = offset; i < offset + count; i++) { 149 byte ch = bytes[i]; 150 151 if (ch == 0) { 152 break; 153 } 154 155 boolean is_unicode = (ch & 0x80) != 0; 156 int uch = ch & 0x7F; 157 158 if (is_unicode) { 159 int mask = 0x40; 160 161 while ((uch & mask) != 0) { 162 ch = bytes[++i]; 163 164 if ((ch & 0xC0) != 0x80) { 165 throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch)); 166 } 167 168 uch = ((uch & ~mask) << 6) | (ch & 0x3F); 169 mask <<= 6 - 1; 170 } 171 172 if ((uch & 0xFFFF) != uch) { 173 throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch)); 174 } 175 } 176 177 chars[j++] = (char)uch; 178 } 179 } 180 181 public static String stringFromMUTF8(byte[] bytes, int offset, int count) { 182 int length = charsFromMUTF8Length(bytes, offset, count); 183 char[] chars = new char[length]; 184 185 try { 186 charsFromMUTF8(chars, bytes, offset, count); 187 } catch (UTFDataFormatException ex) { 188 throw new InternalError("Attempt to convert non modified UTF-8 byte sequence", ex); 189 } 190 191 return new String(chars); 192 } 193 194 public static String stringFromMUTF8(byte[] bytes) { 195 return stringFromMUTF8(bytes, 0, bytes.length); 196 } 197 198 static int charsFromByteBufferLength(ByteBuffer buffer) { 199 int length = 0; 200 201 while(buffer.hasRemaining()) { 202 byte ch = buffer.get(); 203 204 if (ch == 0) { 205 return length; 206 } 207 208 if ((ch & 0xC0) != 0x80) { 209 length++; 210 } 211 } 212 213 throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); 214 } 215 216 static void charsFromByteBuffer(char[] chars, ByteBuffer buffer) { 217 int j = 0; 218 219 while(buffer.hasRemaining()) { 220 byte ch = buffer.get(); 221 222 if (ch == 0) { 223 return; 224 } 225 226 boolean is_unicode = (ch & 0x80) != 0; 227 int uch = ch & 0x7F; 228 229 if (is_unicode) { 230 int mask = 0x40; 231 232 while ((uch & mask) != 0) { 233 ch = buffer.get(); 234 235 if ((ch & 0xC0) != 0x80) { 236 throw new InternalError("Bad continuation in " + 237 "modified UTF-8 byte sequence: " + ch); 238 } 239 240 uch = ((uch & ~mask) << 6) | (ch & 0x3F); 241 mask <<= 6 - 1; 242 } 243 } 244 245 if ((uch & 0xFFFF) != uch) { 246 throw new InternalError("UTF-32 char in modified UTF-8 " + 247 "byte sequence: " + uch); 248 } 249 250 chars[j++] = (char)uch; 251 } 252 253 throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); 254 } 255 256 public static String stringFromByteBuffer(ByteBuffer buffer) { 257 int length = charsFromByteBufferLength(buffer); 258 buffer.rewind(); 259 char[] chars = new char[length]; 260 charsFromByteBuffer(chars, buffer); 261 262 return new String(chars); 263 } 264 265 static int mutf8FromStringLength(String s) { 266 int length = 0; 267 int slen = s.length(); 268 for (int i = 0; i < slen; i++) { 269 char ch = s.charAt(i); 270 int uch = ch & 0xFFFF; 271 272 if ((uch & ~0x7F) != 0) { 273 int mask = ~0x3F; 274 int n = 0; 275 276 do { 277 n++; 278 uch >>= 6; 279 mask >>= 1; 280 } while ((uch & mask) != 0); 281 282 length += n + 1; 283 } else if (uch == 0) { 284 length += 2; 285 } else { 286 length++; 287 } 288 } 289 290 return length; 291 } 292 293 static void mutf8FromString(byte[] bytes, int offset, String s) { 294 int j = offset; 295 byte[] buffer = null; 296 int slen = s.length(); 297 298 for (int i = 0; i < slen; i++) { 299 char ch = s.charAt(i); 300 int uch = ch & 0xFFFF; 301 302 if ((uch & ~0x7F) != 0) { 303 if (buffer == null) { 304 buffer = new byte[8]; 305 } 306 int mask = ~0x3F; 307 int n = 0; 308 309 do { 310 buffer[n++] = (byte)(0x80 | (uch & 0x3F)); 311 uch >>= 6; 312 mask >>= 1; 313 } while ((uch & mask) != 0); 314 315 buffer[n] = (byte)((mask << 1) | uch); 316 317 do { 318 bytes[j++] = buffer[n--]; 319 } while (0 <= n); 320 } else if (uch == 0) { 321 bytes[j++] = (byte)0xC0; 322 bytes[j++] = (byte)0x80; 323 } else { 324 bytes[j++] = (byte)uch; 325 } 326 } 327 } 328 329 public static byte[] mutf8FromString(String string) { 330 int length = mutf8FromStringLength(string); 331 byte[] bytes = new byte[length]; 332 mutf8FromString(bytes, 0, string); 333 334 return bytes; 335 } 336 }