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.tools.jlink.internal;
 27 
 28 import jdk.internal.jimage.ImageLocation;
 29 import jdk.internal.jimage.ImageStream;
 30 import jdk.internal.jimage.ImageStringsReader;
 31 
 32 public final class ImageLocationWriter extends ImageLocation {
 33     private int locationOffset;
 34 
 35     private ImageLocationWriter(ImageStringsWriter strings) {
 36         super(new long[ATTRIBUTE_COUNT], strings);
 37     }
 38 
 39     void writeTo(ImageStream stream) {
 40         byte[] bytes = ImageLocation.compress(attributes);
 41         locationOffset = stream.getPosition();
 42         stream.put(bytes, 0, bytes.length);
 43     }
 44 
 45     private ImageLocationWriter addAttribute(int kind, long value) {
 46         assert ATTRIBUTE_END < kind &&
 47                kind < ATTRIBUTE_COUNT : "Invalid attribute kind";
 48         attributes[kind] = value;
 49         return this;
 50     }
 51 
 52     private ImageLocationWriter addAttribute(int kind, String value) {
 53         return addAttribute(kind, strings.add(value));
 54     }
 55 
 56     static ImageLocationWriter newLocation(
 57             String fullName,
 58             ImageStringsWriter strings,
 59             long contentOffset,
 60             long compressedSize,
 61             long uncompressedSize,
 62             int previewFlags) {
 63         String moduleName = "";
 64         String parentName = "";
 65         String baseName;
 66         String extensionName = "";
 67 
 68         if (fullName.startsWith("/modules/")) {
 69             moduleName = "modules";
 70             baseName = fullName.substring("/modules/".length());
 71         } else if ( fullName.startsWith("/packages/")) {
 72             moduleName = "packages";
 73             baseName = fullName.substring("/packages/".length());
 74         } else {
 75             int offset = fullName.indexOf('/', 1);
 76             if (fullName.length() >= 2 && fullName.charAt(0) == '/' && offset != -1) {
 77                 moduleName = fullName.substring(1, offset);
 78                 fullName = fullName.substring(offset + 1);
 79             }
 80 
 81             offset = fullName.lastIndexOf('/');
 82             if (1 < offset) {
 83                 parentName = fullName.substring(0, offset);
 84                 fullName = fullName.substring(offset + 1);
 85             }
 86 
 87             offset = fullName.lastIndexOf('.');
 88             if (offset != -1) {
 89                 baseName = fullName.substring(0, offset);
 90                 extensionName = fullName.substring(offset + 1);
 91             } else {
 92                 baseName = fullName;
 93             }
 94         }
 95 
 96         return new ImageLocationWriter(strings)
 97                 .addAttribute(ATTRIBUTE_MODULE, moduleName)
 98                 .addAttribute(ATTRIBUTE_PARENT, parentName)
 99                 .addAttribute(ATTRIBUTE_BASE, baseName)
100                 .addAttribute(ATTRIBUTE_EXTENSION, extensionName)
101                 .addAttribute(ATTRIBUTE_OFFSET, contentOffset)
102                 .addAttribute(ATTRIBUTE_COMPRESSED, compressedSize)
103                 .addAttribute(ATTRIBUTE_UNCOMPRESSED, uncompressedSize)
104                 .addAttribute(ATTRIBUTE_PREVIEW_FLAGS, previewFlags);
105     }
106 
107     @Override
108     public int hashCode() {
109         return hashCode(ImageStringsReader.HASH_MULTIPLIER);
110     }
111 
112     int hashCode(int seed) {
113         int hash = seed;
114 
115         if (getModuleOffset() != 0) {
116             hash = ImageStringsReader.unmaskedHashCode("/", hash);
117             hash = ImageStringsReader.unmaskedHashCode(getModule(), hash);
118             hash = ImageStringsReader.unmaskedHashCode("/", hash);
119         }
120 
121         if (getParentOffset() != 0) {
122             hash = ImageStringsReader.unmaskedHashCode(getParent(), hash);
123             hash = ImageStringsReader.unmaskedHashCode("/", hash);
124         }
125 
126         hash = ImageStringsReader.unmaskedHashCode(getBase(), hash);
127 
128         if (getExtensionOffset() != 0) {
129             hash = ImageStringsReader.unmaskedHashCode(".", hash);
130             hash = ImageStringsReader.unmaskedHashCode(getExtension(), hash);
131         }
132 
133         return hash & ImageStringsReader.POSITIVE_MASK;
134     }
135 
136     @Override
137     public boolean equals(Object obj) {
138         if (this == obj) {
139             return true;
140         }
141 
142         if (!(obj instanceof ImageLocationWriter)) {
143             return false;
144         }
145 
146         ImageLocationWriter other = (ImageLocationWriter) obj;
147 
148         return getModuleOffset() == other.getModuleOffset() &&
149                getParentOffset() == other.getParentOffset() &&
150                getBaseOffset() == other.getBaseOffset() &&
151                getExtensionOffset() == other.getExtensionOffset();
152     }
153 
154     int getLocationOffset() {
155         return locationOffset;
156     }
157 }