< prev index next >

src/java.base/share/classes/jdk/internal/jimage/ImageLocation.java

Print this page

  1 /*
  2  * Copyright (c) 2014, 2021, 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.nio.ByteBuffer;

 29 import java.util.Objects;

 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 ImageLocation {



 39     public static final int ATTRIBUTE_END = 0;

 40     public static final int ATTRIBUTE_MODULE = 1;

 41     public static final int ATTRIBUTE_PARENT = 2;

 42     public static final int ATTRIBUTE_BASE = 3;

 43     public static final int ATTRIBUTE_EXTENSION = 4;

 44     public static final int ATTRIBUTE_OFFSET = 5;

 45     public static final int ATTRIBUTE_COMPRESSED = 6;

 46     public static final int ATTRIBUTE_UNCOMPRESSED = 7;
 47     public static final int ATTRIBUTE_COUNT = 8;
















































































































































 48 
 49     protected final long[] attributes;
 50 
 51     protected final ImageStrings strings;
 52 
 53     public ImageLocation(long[] attributes, ImageStrings strings) {
 54         this.attributes = Objects.requireNonNull(attributes);
 55         this.strings = Objects.requireNonNull(strings);
 56     }
 57 
 58     ImageStrings getStrings() {
 59         return strings;
 60     }
 61 
 62     static long[] decompress(ByteBuffer bytes, int offset) {
 63         Objects.requireNonNull(bytes);
 64         long[] attributes = new long[ATTRIBUTE_COUNT];
 65 
 66         int limit = bytes.limit();
 67         while (offset < limit) {

268     public int getBaseOffset() {
269         return (int)getAttribute(ATTRIBUTE_BASE);
270     }
271 
272     public String getParent() {
273         return getAttributeString(ATTRIBUTE_PARENT);
274     }
275 
276     public int getParentOffset() {
277         return (int)getAttribute(ATTRIBUTE_PARENT);
278     }
279 
280     public String getExtension() {
281         return getAttributeString(ATTRIBUTE_EXTENSION);
282     }
283 
284     public int getExtensionOffset() {
285         return (int)getAttribute(ATTRIBUTE_EXTENSION);
286     }
287 




288     public String getFullName() {
289         return getFullName(false);
290     }
291 
292     public String getFullName(boolean modulesPrefix) {
293         StringBuilder builder = new StringBuilder();
294 
295         if (getModuleOffset() != 0) {
296             if (modulesPrefix) {
297                 builder.append("/modules");
298             }
299 
300             builder.append('/');
301             builder.append(getModule());
302             builder.append('/');
303         }
304 
305         if (getParentOffset() != 0) {
306             builder.append(getParent());
307             builder.append('/');
308         }
309 
310         builder.append(getBase());
311 
312         if (getExtensionOffset() != 0) {
313             builder.append('.');
314             builder.append(getExtension());
315         }
316 
317         return builder.toString();
318     }
319 
320     String buildName(boolean includeModule, boolean includeParent,
321             boolean includeName) {
322         StringBuilder builder = new StringBuilder();
323 
324         if (includeModule && getModuleOffset() != 0) {
325             builder.append("/modules/");
326             builder.append(getModule());
327          }
328 
329         if (includeParent && getParentOffset() != 0) {
330             builder.append('/');
331             builder.append(getParent());
332         }
333 
334         if (includeName) {
335             if (includeModule || includeParent) {
336                 builder.append('/');
337             }
338 
339             builder.append(getBase());
340 
341             if (getExtensionOffset() != 0) {
342                 builder.append('.');
343                 builder.append(getExtension());
344             }
345         }
346 
347         return builder.toString();
348    }
349 
350     public long getContentOffset() {
351         return getAttribute(ATTRIBUTE_OFFSET);
352     }
353 
354     public long getCompressedSize() {
355         return getAttribute(ATTRIBUTE_COMPRESSED);
356     }
357 
358     public long getUncompressedSize() {
359         return getAttribute(ATTRIBUTE_UNCOMPRESSED);
360     }
361 




































362     static ImageLocation readFrom(BasicImageReader reader, int offset) {
363         Objects.requireNonNull(reader);
364         long[] attributes = reader.getAttributes(offset);
365         ImageStringsReader strings = reader.getStrings();
366 
367         return new ImageLocation(attributes, strings);
368     }
369 }

  1 /*
  2  * Copyright (c) 2014, 2025, 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.nio.ByteBuffer;
 29 import java.util.List;
 30 import java.util.Objects;
 31 import java.util.function.Predicate;
 32 
 33 /**
 34  * @implNote This class needs to maintain JDK 8 source compatibility.
 35  *
 36  * It is used internally in the JDK to implement jimage/jrtfs access,
 37  * but also compiled and delivered as part of the jrtfs.jar to support access
 38  * to the jimage file provided by the shipped JDK by tools running on JDK 8.
 39  */
 40 public class ImageLocation {
 41     // Also defined in src/java.base/share/native/libjimage/imageFile.hpp
 42 
 43     /** End of attribute stream marker. */
 44     public static final int ATTRIBUTE_END = 0;
 45     /** String table offset of module name. */
 46     public static final int ATTRIBUTE_MODULE = 1;
 47     /** String table offset of resource path parent. */
 48     public static final int ATTRIBUTE_PARENT = 2;
 49     /** String table offset of resource path base. */
 50     public static final int ATTRIBUTE_BASE = 3;
 51     /** String table offset of resource path extension. */
 52     public static final int ATTRIBUTE_EXTENSION = 4;
 53     /** Container byte offset of resource. */
 54     public static final int ATTRIBUTE_OFFSET = 5;
 55     /** In-image byte size of the compressed resource. */
 56     public static final int ATTRIBUTE_COMPRESSED = 6;
 57     /** In-memory byte size of the uncompressed resource. */
 58     public static final int ATTRIBUTE_UNCOMPRESSED = 7;
 59     /** Flags relating to preview mode resources. */
 60     public static final int ATTRIBUTE_PREVIEW_FLAGS = 8;
 61     /** Number of attribute kinds. */
 62     public static final int ATTRIBUTE_COUNT = 9;
 63 
 64     // Flag masks for the ATTRIBUTE_PREVIEW_FLAGS attribute. Defined so
 65     // that zero is the overwhelmingly common case for normal resources.
 66 
 67     /**
 68      * Indicates that a non-preview location is associated with preview
 69      * resources.
 70      *
 71      * <p>This can apply to both resources and directories in the
 72      * {@code /modules/xxx/...} namespace, as well as {@code /packages/xxx}
 73      * directories.
 74      *
 75      * <p>For {@code /packages/xxx} directories, it indicates that the package
 76      * has preview resources in one of the modules in which it exists.
 77      */
 78     private static final int FLAGS_HAS_PREVIEW_VERSION = 0x1;
 79     /**
 80      * Set on all locations in the {@code /modules/xxx/META-INF/preview/...}
 81      * namespace.
 82      *
 83      * <p>This flag is mutually exclusive with {@link #FLAGS_HAS_PREVIEW_VERSION}.
 84      */
 85     private static final int FLAGS_IS_PREVIEW_VERSION = 0x2;
 86     /**
 87      * Indicates that a location only exists due to preview resources.
 88      *
 89      * <p>This can apply to both resources and directories in the
 90      * {@code /modules/xxx/...} namespace, as well as {@code /packages/xxx}
 91      * directories.
 92      *
 93      * <p>For {@code /packages/xxx} directories it indicates that, for every
 94      * module in which the package exists, it is preview only.
 95      *
 96      * <p>This flag is mutually exclusive with {@link #FLAGS_HAS_PREVIEW_VERSION}
 97      * and need not imply that {@link #FLAGS_IS_PREVIEW_VERSION} is set (i.e.
 98      * for {@code /packages/xxx} directories).
 99      */
100     private static final int FLAGS_IS_PREVIEW_ONLY = 0x4;
101 
102     // Also used in ImageReader.
103     static final String MODULES_PREFIX = "/modules";
104     static final String PACKAGES_PREFIX = "/packages";
105     static final String PREVIEW_INFIX = "/META-INF/preview";
106 
107     /**
108      * Helper function to calculate preview flags (ATTRIBUTE_PREVIEW_FLAGS).
109      *
110      * <p>Since preview flags are calculated separately for resource nodes and
111      * directory nodes (in two quite different places) it's useful to have a
112      * common helper.
113      *
114      * <p>Based on the entry name, the flags are:
115      * <ul>
116      *     <li>{@code "[/modules]/<module>/<path>"} normal resource or directory:<br>
117      *     Zero, or {@code FLAGS_HAS_PREVIEW_VERSION} if a preview entry exists.
118      *     <li>{@code "[/modules]/<module>/META-INF/preview/<path>"} preview
119      *     resource or directory:<br>
120      *     {@code FLAGS_IS_PREVIEW_VERSION}, and additionally {@code
121      *     FLAGS_IS_PREVIEW_ONLY} if no normal version of the resource exists.
122      *     <li>In all other cases, returned flags are zero (note that {@code
123      *     "/packages/xxx"} entries may have flags, but these are calculated
124      *     elsewhere).
125      * </ul>
126      *
127      * @param name the jimage name of the resource or directory.
128      * @param hasEntry a predicate for jimage names returning whether an entry
129      *     is present.
130      * @return flags for the ATTRIBUTE_PREVIEW_FLAGS attribute.
131      */
132     public static int getFlags(String name, Predicate<String> hasEntry) {
133         if (name.startsWith(PACKAGES_PREFIX + "/")) {
134             throw new IllegalArgumentException(
135                     "Package sub-directory flags handled separately: " + name);
136         }
137         // Find suffix for either '/modules/xxx/suffix' or '/xxx/suffix' paths.
138         int idx = name.startsWith(MODULES_PREFIX + "/") ? MODULES_PREFIX.length() + 1 : 1;
139         int suffixStart = name.indexOf('/', idx);
140         if (suffixStart == -1) {
141             // No flags for '[/modules]/xxx' paths (esp. '/modules', '/packages').
142             // '/packages/xxx' entries have flags, but not calculated here.
143             return 0;
144         }
145         // Prefix is either '/modules/xxx' or '/xxx', and suffix starts with '/'.
146         String prefix = name.substring(0, suffixStart);
147         String suffix = name.substring(suffixStart);
148         if (suffix.startsWith(PREVIEW_INFIX + "/")) {
149             // Preview resources/directories.
150             String nonPreviewName = prefix + suffix.substring(PREVIEW_INFIX.length());
151             return FLAGS_IS_PREVIEW_VERSION
152                     | (hasEntry.test(nonPreviewName) ? 0 : FLAGS_IS_PREVIEW_ONLY);
153         } else if (!suffix.startsWith("/META-INF/")) {
154             // Non-preview resources/directories.
155             String previewName = prefix + PREVIEW_INFIX + suffix;
156             return hasEntry.test(previewName) ? FLAGS_HAS_PREVIEW_VERSION : 0;
157         } else {
158             // Suffix is '/META-INF/xxx' and no preview version is even possible.
159             return 0;
160         }
161     }
162 
163     /**
164      * Helper function to calculate package flags for {@code "/packages/xxx"}
165      * directory entries.
166      *
167      * <p>Based on the module references, the flags are:
168      * <ul>
169      *     <li>{@code FLAGS_HAS_PREVIEW_VERSION} if <em>any</em> referenced
170      *     package has a preview version.
171      *     <li>{@code FLAGS_IS_PREVIEW_ONLY} if <em>all</em> referenced packages
172      *     are preview only.
173      * </ul>
174      *
175      * @return package flags for {@code "/packages/xxx"} directory entries.
176      */
177     public static int getPackageFlags(List<ModuleReference> moduleReferences) {
178         boolean hasPreviewVersion =
179                 moduleReferences.stream().anyMatch(ModuleReference::hasPreviewVersion);
180         boolean isPreviewOnly =
181                 moduleReferences.stream().allMatch(ModuleReference::isPreviewOnly);
182         return (hasPreviewVersion ? ImageLocation.FLAGS_HAS_PREVIEW_VERSION : 0)
183                 | (isPreviewOnly ? ImageLocation.FLAGS_IS_PREVIEW_ONLY : 0);
184     }
185 
186     /**
187      * Tests a non-preview image location's flags to see if it has preview
188      * content associated with it.
189      */
190     public static boolean hasPreviewVersion(int flags) {
191         return (flags & FLAGS_HAS_PREVIEW_VERSION) != 0;
192     }
193 
194     /**
195      * Tests an image location's flags to see if it only exists in preview mode.
196      */
197     public static boolean isPreviewOnly(int flags) {
198         return (flags & FLAGS_IS_PREVIEW_ONLY) != 0;
199     }
200 
201     public enum LocationType {
202         RESOURCE, MODULES_ROOT, MODULES_DIR, PACKAGES_ROOT, PACKAGES_DIR;
203     }
204 
205     protected final long[] attributes;
206 
207     protected final ImageStrings strings;
208 
209     public ImageLocation(long[] attributes, ImageStrings strings) {
210         this.attributes = Objects.requireNonNull(attributes);
211         this.strings = Objects.requireNonNull(strings);
212     }
213 
214     ImageStrings getStrings() {
215         return strings;
216     }
217 
218     static long[] decompress(ByteBuffer bytes, int offset) {
219         Objects.requireNonNull(bytes);
220         long[] attributes = new long[ATTRIBUTE_COUNT];
221 
222         int limit = bytes.limit();
223         while (offset < limit) {

424     public int getBaseOffset() {
425         return (int)getAttribute(ATTRIBUTE_BASE);
426     }
427 
428     public String getParent() {
429         return getAttributeString(ATTRIBUTE_PARENT);
430     }
431 
432     public int getParentOffset() {
433         return (int)getAttribute(ATTRIBUTE_PARENT);
434     }
435 
436     public String getExtension() {
437         return getAttributeString(ATTRIBUTE_EXTENSION);
438     }
439 
440     public int getExtensionOffset() {
441         return (int)getAttribute(ATTRIBUTE_EXTENSION);
442     }
443 
444     public int getFlags() {
445         return (int) getAttribute(ATTRIBUTE_PREVIEW_FLAGS);
446     }
447 
448     public String getFullName() {
449         return getFullName(false);
450     }
451 
452     public String getFullName(boolean modulesPrefix) {
453         StringBuilder builder = new StringBuilder();
454 
455         if (getModuleOffset() != 0) {
456             if (modulesPrefix) {
457                 builder.append(MODULES_PREFIX);
458             }
459 
460             builder.append('/');
461             builder.append(getModule());
462             builder.append('/');
463         }
464 
465         if (getParentOffset() != 0) {
466             builder.append(getParent());
467             builder.append('/');
468         }
469 
470         builder.append(getBase());
471 
472         if (getExtensionOffset() != 0) {
473             builder.append('.');
474             builder.append(getExtension());
475         }
476 
477         return builder.toString();
478     }
479 






























480     public long getContentOffset() {
481         return getAttribute(ATTRIBUTE_OFFSET);
482     }
483 
484     public long getCompressedSize() {
485         return getAttribute(ATTRIBUTE_COMPRESSED);
486     }
487 
488     public long getUncompressedSize() {
489         return getAttribute(ATTRIBUTE_UNCOMPRESSED);
490     }
491 
492     // Fast (zero allocation) type determination for locations.
493     public LocationType getType() {
494         switch (getModuleOffset()) {
495             case ImageStrings.MODULES_STRING_OFFSET:
496                 // Locations in /modules/... namespace are directory entries.
497                 return LocationType.MODULES_DIR;
498             case ImageStrings.PACKAGES_STRING_OFFSET:
499                 // Locations in /packages/... namespace are always 2-level
500                 // "/packages/xxx" directories.
501                 return LocationType.PACKAGES_DIR;
502             case ImageStrings.EMPTY_STRING_OFFSET:
503                 // Only 2 choices, either the "/modules" or "/packages" root.
504                 assert isRootDir() : "Invalid root directory: " + getFullName();
505                 return getBase().charAt(1) == 'p'
506                         ? LocationType.PACKAGES_ROOT
507                         : LocationType.MODULES_ROOT;
508             default:
509                 // Anything else is /<module>/<path> and references a resource.
510                 return LocationType.RESOURCE;
511         }
512     }
513 
514     private boolean isRootDir() {
515         if (getModuleOffset() == 0 && getParentOffset() == 0) {
516             String name = getFullName();
517             return name.equals(MODULES_PREFIX) || name.equals(PACKAGES_PREFIX);
518         }
519         return false;
520     }
521 
522     @Override
523     public String toString() {
524         // Cannot use String.format() (too early in startup for locale code).
525         return "ImageLocation[name='" + getFullName() + "', type=" + getType() + ", flags=" + getFlags() + "]";
526     }
527 
528     static ImageLocation readFrom(BasicImageReader reader, int offset) {
529         Objects.requireNonNull(reader);
530         long[] attributes = reader.getAttributes(offset);
531         ImageStringsReader strings = reader.getStrings();
532 
533         return new ImageLocation(attributes, strings);
534     }
535 }
< prev index next >