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 private static int attributeLength(int data) {
63 return (data & 0x7) + 1;
64 }
65
66 private static int attributeKind(int data) {
67 return data >>> 3;
68 }
69
70 static long[] decompress(ByteBuffer bytes) {
71 Objects.requireNonNull(bytes);
72 long[] attributes = new long[ATTRIBUTE_COUNT];
73
74 if (bytes != null) {
75 while (bytes.hasRemaining()) {
76 int data = bytes.get() & 0xFF;
77 int kind = attributeKind(data);
78
79 if (kind == ATTRIBUTE_END) {
80 break;
81 }
82
83 if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
84 throw new InternalError(
85 "Invalid jimage attribute kind: " + kind);
86 }
87
88 int length = attributeLength(data);
89 long value = 0;
90
91 for (int j = 0; j < length; j++) {
92 value <<= 8;
93
94 if (!bytes.hasRemaining()) {
95 throw new InternalError("Missing jimage attribute data");
96 }
97
98 value |= bytes.get() & 0xFF;
99 }
100
101 attributes[kind] = value;
102 }
103 }
104
105 return attributes;
106 }
107
108 public static byte[] compress(long[] attributes) {
111
112 for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
113 long value = attributes[kind];
114
115 if (value != 0) {
116 int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
117 stream.put((kind << 3) | n);
118
119 for (int i = n; i >= 0; i--) {
120 stream.put((int)(value >> (i << 3)));
121 }
122 }
123 }
124
125 stream.put(ATTRIBUTE_END << 3);
126
127 return stream.toArray();
128 }
129
130 public boolean verify(String name) {
131 Objects.requireNonNull(name);
132
133 return name.equals(getFullName());
134 }
135
136 long getAttribute(int kind) {
137 if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
138 throw new InternalError(
139 "Invalid jimage attribute kind: " + kind);
140 }
141
142 return attributes[kind];
143 }
144
145 String getAttributeString(int kind) {
146 if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
147 throw new InternalError(
148 "Invalid jimage attribute kind: " + kind);
149 }
150
151 return getStrings().get((int)attributes[kind]);
152 }
153
|
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) {
63 Objects.requireNonNull(bytes);
64 long[] attributes = new long[ATTRIBUTE_COUNT];
65
66 if (bytes != null) {
67 while (bytes.hasRemaining()) {
68 int data = bytes.get() & 0xFF;
69 int kind = data >>> 3;
70
71 if (kind == ATTRIBUTE_END) {
72 break;
73 }
74
75 if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
76 throw new InternalError(
77 "Invalid jimage attribute kind: " + kind);
78 }
79
80 int length = (data & 0x7) + 1;
81 long value = 0;
82
83 for (int j = 0; j < length; j++) {
84 value <<= 8;
85
86 if (!bytes.hasRemaining()) {
87 throw new InternalError("Missing jimage attribute data");
88 }
89
90 value |= bytes.get() & 0xFF;
91 }
92
93 attributes[kind] = value;
94 }
95 }
96
97 return attributes;
98 }
99
100 public static byte[] compress(long[] attributes) {
103
104 for (int kind = ATTRIBUTE_END + 1; kind < ATTRIBUTE_COUNT; kind++) {
105 long value = attributes[kind];
106
107 if (value != 0) {
108 int n = (63 - Long.numberOfLeadingZeros(value)) >> 3;
109 stream.put((kind << 3) | n);
110
111 for (int i = n; i >= 0; i--) {
112 stream.put((int)(value >> (i << 3)));
113 }
114 }
115 }
116
117 stream.put(ATTRIBUTE_END << 3);
118
119 return stream.toArray();
120 }
121
122 public boolean verify(String name) {
123 return verify(name, attributes, strings);
124 }
125
126 /**
127 * A simpler verification would be {@code name.equals(getFullName())}, but
128 * by not creating the full name and enabling early returns we allocate
129 * fewer objects. Could possibly be made allocation free by extending
130 * ImageStrings to test if strings at an offset match the name region.
131 */
132 static boolean verify(String name, final long[] attributes,
133 final ImageStrings strings) {
134 Objects.requireNonNull(name);
135 final int length = name.length();
136 int index = 0;
137 int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
138 if (moduleOffset != 0) {
139 String module = strings.get(moduleOffset);
140 final int moduleLen = module.length();
141 index = moduleLen + 1;
142 if (length <= index
143 || name.charAt(0) != '/'
144 || !name.regionMatches(1, module, 0, moduleLen)
145 || name.charAt(index++) != '/') {
146 return false;
147 }
148 }
149
150 return verifyName(name, index, length, attributes, strings);
151 }
152
153 static boolean verify(String module, String name,
154 final long[] attributes, final ImageStrings strings) {
155 Objects.requireNonNull(module);
156 Objects.requireNonNull(name);
157 int moduleOffset = (int)attributes[ATTRIBUTE_MODULE];
158 if (moduleOffset != 0) {
159 if (!module.equals(strings.get(moduleOffset))) {
160 return false;
161 }
162 }
163
164 return verifyName(name, 0, name.length(), attributes, strings);
165 }
166
167 private static boolean verifyName(String name, int index, final int length,
168 final long[] attributes, final ImageStrings strings) {
169
170 int parentOffset = (int) attributes[ATTRIBUTE_PARENT];
171 if (parentOffset != 0) {
172 String parent = strings.get(parentOffset);
173 final int parentLen = parent.length();
174 if (!name.regionMatches(index, parent, 0, parentLen)) {
175 return false;
176 }
177 index += parentLen;
178 if (length <= index || name.charAt(index++) != '/') {
179 return false;
180 }
181 }
182 String base = strings.get((int) attributes[ATTRIBUTE_BASE]);
183 final int baseLen = base.length();
184 if (!name.regionMatches(index, base, 0, baseLen)) {
185 return false;
186 }
187 index += baseLen;
188 int extOffset = (int) attributes[ATTRIBUTE_EXTENSION];
189 if (extOffset != 0) {
190 String extension = strings.get(extOffset);
191 int extLen = extension.length();
192 if (length <= index
193 || name.charAt(index++) != '.'
194 || !name.regionMatches(index, extension, 0, extLen)) {
195 return false;
196 }
197 index += extLen;
198 }
199 return length == index;
200 }
201
202 long getAttribute(int kind) {
203 if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
204 throw new InternalError(
205 "Invalid jimage attribute kind: " + kind);
206 }
207
208 return attributes[kind];
209 }
210
211 String getAttributeString(int kind) {
212 if (kind < ATTRIBUTE_END || ATTRIBUTE_COUNT <= kind) {
213 throw new InternalError(
214 "Invalid jimage attribute kind: " + kind);
215 }
216
217 return getStrings().get((int)attributes[kind]);
218 }
219
|