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 31 /** 32 * @implNote This class needs to maintain JDK 8 source compatibility. 33 * 34 * It is used internally in the JDK to implement jimage/jrtfs access, 35 * but also compiled and delivered as part of the jrtfs.jar to support access 36 * to the jimage file provided by the shipped JDK by tools running on JDK 8. 37 */ 38 public class ImageStringsReader implements ImageStrings { 39 public static final int HASH_MULTIPLIER = 0x01000193; 40 private final BasicImageReader reader; 41 42 ImageStringsReader(BasicImageReader reader) { 43 this.reader = reader; 44 } 45 46 @Override 47 public String get(int offset) { 48 return reader.getString(offset); 49 } 50 51 @Override 52 public int add(final String string) { 53 throw new InternalError("Can not add strings at runtime"); 54 } 55 56 private static int hashCode(byte[] bytes, int offset, int count, int seed) { 57 for (int i = offset, limit = offset + count; i < limit; i++) { 58 seed = (seed * HASH_MULTIPLIER) ^ (bytes[i] & 0xFF); 59 } 60 61 return seed & 0x7FFFFFFF; 62 } 63 64 public static int hashCode(byte[] bytes, int seed) { 65 return hashCode(bytes, 0, bytes.length, seed); 66 } 67 68 public static int hashCode(byte[] bytes) { 69 return hashCode(bytes, 0, bytes.length, HASH_MULTIPLIER); 70 } 71 72 public static int hashCode(String string, int seed) { 73 return hashCode(mutf8FromString(string), seed); 74 } 75 76 public static int hashCode(String string) { 77 return hashCode(mutf8FromString(string), HASH_MULTIPLIER); 78 } 79 80 static int charsFromMUTF8Length(byte[] bytes, int offset, int count) { 81 int length = 0; 82 83 for (int i = offset; i < offset + count; i++) { 84 byte ch = bytes[i]; 85 86 if (ch == 0) { 87 break; 88 } 89 90 if ((ch & 0xC0) != 0x80) { 91 length++; 92 } 93 } 94 95 return length; 96 } 97 98 static void charsFromMUTF8(char[] chars, byte[] bytes, int offset, int count) throws UTFDataFormatException { 99 int j = 0; 100 101 for (int i = offset; i < offset + count; i++) { 102 byte ch = bytes[i]; 103 104 if (ch == 0) { 105 break; 106 } 107 108 boolean is_unicode = (ch & 0x80) != 0; 109 int uch = ch & 0x7F; 110 111 if (is_unicode) { 112 int mask = 0x40; 113 114 while ((uch & mask) != 0) { 115 ch = bytes[++i]; 116 117 if ((ch & 0xC0) != 0x80) { 118 throw new UTFDataFormatException("bad continuation 0x" + Integer.toHexString(ch)); 119 } 120 121 uch = ((uch & ~mask) << 6) | (ch & 0x3F); 122 mask <<= 6 - 1; 123 } 124 125 if ((uch & 0xFFFF) != uch) { 126 throw new UTFDataFormatException("character out of range \\u" + Integer.toHexString(uch)); 127 } 128 } 129 130 chars[j++] = (char)uch; 131 } 132 } 133 134 public static String stringFromMUTF8(byte[] bytes, int offset, int count) { 135 int length = charsFromMUTF8Length(bytes, offset, count); 136 char[] chars = new char[length]; 137 138 try { 139 charsFromMUTF8(chars, bytes, offset, count); 140 } catch (UTFDataFormatException ex) { 141 throw new InternalError("Attempt to convert non modified UTF-8 byte sequence"); 142 } 143 144 return new String(chars); 145 } 146 147 public static String stringFromMUTF8(byte[] bytes) { 148 return stringFromMUTF8(bytes, 0, bytes.length); 149 } 150 151 static int charsFromByteBufferLength(ByteBuffer buffer) { 152 int length = 0; 153 154 while(buffer.hasRemaining()) { 155 byte ch = buffer.get(); 156 157 if (ch == 0) { 158 return length; 159 } 160 161 if ((ch & 0xC0) != 0x80) { 162 length++; 163 } 164 } 165 166 throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); 167 } 168 169 static void charsFromByteBuffer(char chars[], ByteBuffer buffer) { 170 int j = 0; 171 172 while(buffer.hasRemaining()) { 173 byte ch = buffer.get(); 174 175 if (ch == 0) { 176 return; 177 } 178 179 boolean is_unicode = (ch & 0x80) != 0; 180 int uch = ch & 0x7F; 181 182 if (is_unicode) { 183 int mask = 0x40; 184 185 while ((uch & mask) != 0) { 186 ch = buffer.get(); 187 188 if ((ch & 0xC0) != 0x80) { 189 throw new InternalError("Bad continuation in modified UTF-8 byte sequence"); 190 } 191 192 uch = ((uch & ~mask) << 6) | (ch & 0x3F); 193 mask <<= 6 - 1; 194 } 195 } 196 197 if ((uch & 0xFFFF) != uch) { 198 throw new InternalError("UTF-32 char in modified UTF-8 byte sequence"); 199 } 200 201 chars[j++] = (char)uch; 202 } 203 204 throw new InternalError("No terminating zero byte for modified UTF-8 byte sequence"); 205 } 206 207 public static String stringFromByteBuffer(ByteBuffer buffer) { 208 int length = charsFromByteBufferLength(buffer); 209 buffer.rewind(); 210 char[] chars = new char[length]; 211 charsFromByteBuffer(chars, buffer); 212 213 return new String(chars); 214 } 215 216 static int mutf8FromCharsLength(char chars[]) { 217 int length = 0; 218 219 for (char ch : chars) { 220 int uch = ch & 0xFFFF; 221 222 if ((uch & ~0x7F) != 0) { 223 int mask = ~0x3F; 224 int n = 0; 225 226 do { 227 n++; 228 uch >>= 6; 229 mask >>= 1; 230 } while ((uch & mask) != 0); 231 232 length += n + 1; 233 } else if (uch == 0) { 234 length += 2; 235 } else { 236 length++; 237 } 238 } 239 240 return length; 241 } 242 243 static void mutf8FromChars(byte[] bytes, int offset, char chars[]) { 244 int j = offset; 245 byte[] buffer = new byte[8]; 246 247 for (char ch : chars) { 248 int uch = ch & 0xFFFF; 249 250 if ((uch & ~0x7F) != 0) { 251 int mask = ~0x3F; 252 int n = 0; 253 254 do { 255 buffer[n++] = (byte)(0x80 | (uch & 0x3F)); 256 uch >>= 6; 257 mask >>= 1; 258 } while ((uch & mask) != 0); 259 260 buffer[n] = (byte)((mask << 1) | uch); 261 262 do { 263 bytes[j++] = buffer[n--]; 264 } while (0 <= n); 265 } else if (uch == 0) { 266 bytes[j++] = (byte)0xC0; 267 bytes[j++] = (byte)0x80; 268 } else { 269 bytes[j++] = (byte)uch; 270 } 271 } 272 } 273 274 public static byte[] mutf8FromString(String string) { 275 char[] chars = string.toCharArray(); 276 int length = mutf8FromCharsLength(chars); 277 byte[] bytes = new byte[length]; 278 mutf8FromChars(bytes, 0, chars); 279 280 return bytes; 281 } 282 }