]>
Commit | Line | Data |
---|---|---|
377029eb | 1 | /* Utility routines for finding and reading Java(TM) .class files. |
7e476713 | 2 | Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, |
71e45bc2 | 3 | 2006, 2007, 2008, 2009, 2010, 2012 Free Software Foundation, Inc. |
377029eb | 4 | |
7d82ed5e | 5 | This file is part of GCC. |
6 | ||
7 | GCC is free software; you can redistribute it and/or modify | |
377029eb | 8 | it under the terms of the GNU General Public License as published by |
e4b52719 | 9 | the Free Software Foundation; either version 3, or (at your option) |
377029eb | 10 | any later version. |
11 | ||
7d82ed5e | 12 | GCC is distributed in the hope that it will be useful, |
377029eb | 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
e4b52719 | 18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. | |
377029eb | 20 | |
21 | Java and all Java-based marks are trademarks or registered trademarks | |
22 | of Sun Microsystems, Inc. in the United States and other countries. | |
23 | The Free Software Foundation is independent of Sun Microsystems, Inc. */ | |
24 | ||
25 | /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */ | |
26 | ||
014e6e0c | 27 | #include "config.h" |
28 | #include "system.h" | |
805e22b2 | 29 | #include "coretypes.h" |
377029eb | 30 | |
377029eb | 31 | #include "jcf.h" |
003019ba | 32 | #include "tree.h" |
33 | #include "java-tree.h" | |
d1455aa3 | 34 | #include "hash-table.h" |
e98fb73e | 35 | #include <dirent.h> |
377029eb | 36 | |
fad14b72 | 37 | #include "zlib.h" |
38 | ||
377029eb | 39 | int |
e7bf79cf | 40 | jcf_unexpected_eof (JCF *jcf, int count ATTRIBUTE_UNUSED) |
377029eb | 41 | { |
42 | if (jcf->filename) | |
43 | fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename); | |
44 | else | |
45 | fprintf (stderr, "Premature end of .class file <stdin>.\n"); | |
46 | exit (-1); | |
47 | } | |
48 | ||
49 | void | |
e7bf79cf | 50 | jcf_trim_old_input (JCF *jcf) |
377029eb | 51 | { |
52 | int count = jcf->read_ptr - jcf->buffer; | |
53 | if (count > 0) | |
54 | { | |
55 | memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr); | |
56 | jcf->read_ptr -= count; | |
57 | jcf->read_end -= count; | |
58 | } | |
59 | } | |
60 | ||
61 | int | |
e7bf79cf | 62 | jcf_filbuf_from_stdio (JCF *jcf, int count) |
377029eb | 63 | { |
64 | FILE *file = (FILE*) (jcf->read_state); | |
65 | if (count > jcf->buffer_end - jcf->read_ptr) | |
66 | { | |
67 | JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer; | |
68 | JCF_u4 old_read_end = jcf->read_end - jcf->buffer; | |
69 | JCF_u4 old_size = jcf->buffer_end - jcf->buffer; | |
70 | JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count; | |
25a1c410 | 71 | unsigned char *new_buffer |
72 | = jcf->buffer == NULL ? XNEWVAR (unsigned char, new_size) | |
73 | : XRESIZEVAR (unsigned char, jcf->buffer, new_size); | |
377029eb | 74 | jcf->buffer = new_buffer; |
75 | jcf->buffer_end = new_buffer + new_size; | |
76 | jcf->read_ptr = new_buffer + old_read_ptr; | |
77 | jcf->read_end = new_buffer + old_read_end; | |
78 | } | |
79 | count -= jcf->read_end - jcf->read_ptr; | |
80 | if (count <= 0) | |
81 | return 0; | |
65c439eb | 82 | if ((int) fread (jcf->read_end, 1, count, file) != count) |
377029eb | 83 | jcf_unexpected_eof (jcf, count); |
84 | jcf->read_end += count; | |
85 | return 0; | |
86 | } | |
87 | ||
377029eb | 88 | #include "zipfile.h" |
89 | ||
de9c2bdc | 90 | struct ZipFile *SeenZipFiles = NULL; |
377029eb | 91 | |
087b842d | 92 | /* Open a zip file with the given name, and cache directory and file |
93 | descriptor. If the file is missing, treat it as an empty archive. | |
94 | Return NULL if the .zip file is malformed. | |
95 | */ | |
96 | ||
97 | ZipFile * | |
e7bf79cf | 98 | opendir_in_zip (const char *zipfile, int is_system) |
087b842d | 99 | { |
de9c2bdc | 100 | struct ZipFile* zipf; |
087b842d | 101 | char magic [4]; |
102 | int fd; | |
103 | for (zipf = SeenZipFiles; zipf != NULL; zipf = zipf->next) | |
104 | { | |
105 | if (strcmp (zipf->name, zipfile) == 0) | |
de9c2bdc | 106 | return zipf; |
087b842d | 107 | } |
108 | ||
25a1c410 | 109 | zipf = XNEWVAR (struct ZipFile, sizeof (struct ZipFile) + strlen (zipfile) + 1); |
087b842d | 110 | zipf->next = SeenZipFiles; |
111 | zipf->name = (char*)(zipf+1); | |
112 | strcpy (zipf->name, zipfile); | |
087b842d | 113 | fd = open (zipfile, O_RDONLY | O_BINARY); |
de9c2bdc | 114 | zipf->fd = fd; |
087b842d | 115 | if (fd < 0) |
116 | { | |
117 | /* A missing zip file is not considered an error. | |
118 | We may want to re-consider that. FIXME. */ | |
de9c2bdc | 119 | zipf->count = 0; |
120 | zipf->dir_size = 0; | |
121 | zipf->central_directory = NULL; | |
087b842d | 122 | } |
123 | else | |
124 | { | |
125 | jcf_dependency_add_file (zipfile, is_system); | |
126 | if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC) | |
c5042950 | 127 | { |
128 | free (zipf); | |
129 | close (fd); | |
130 | return NULL; | |
131 | } | |
087b842d | 132 | lseek (fd, 0L, SEEK_SET); |
de9c2bdc | 133 | if (read_zip_archive (zipf) != 0) |
c5042950 | 134 | { |
135 | free (zipf); | |
136 | close (fd); | |
137 | return NULL; | |
138 | } | |
087b842d | 139 | } |
440bcc15 | 140 | |
141 | SeenZipFiles = zipf; | |
de9c2bdc | 142 | return zipf; |
087b842d | 143 | } |
144 | ||
145 | /* Returns: | |
146 | 0: OK - zipmember found. | |
147 | -1: Not found. | |
148 | -2: Malformed archive. | |
149 | */ | |
150 | ||
377029eb | 151 | int |
e7bf79cf | 152 | open_in_zip (JCF *jcf, const char *zipfile, const char *zipmember, |
153 | int is_system) | |
377029eb | 154 | { |
377029eb | 155 | ZipDirectory *zipd; |
156 | int i, len; | |
087b842d | 157 | ZipFile *zipf = opendir_in_zip (zipfile, is_system); |
158 | ||
159 | if (zipf == NULL) | |
160 | return -2; | |
377029eb | 161 | |
162 | if (!zipmember) | |
163 | return 0; | |
164 | ||
165 | len = strlen (zipmember); | |
166 | ||
087b842d | 167 | zipd = (struct ZipDirectory*) zipf->central_directory; |
168 | for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd)) | |
377029eb | 169 | { |
170 | if (len == zipd->filename_length && | |
171 | strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0) | |
172 | { | |
173 | JCF_ZERO (jcf); | |
fad14b72 | 174 | |
1ab1061d | 175 | jcf->filename = xstrdup (zipfile); |
176 | jcf->classname = xstrdup (zipmember); | |
de9c2bdc | 177 | return read_zip_member(jcf, zipd, zipf); |
178 | } | |
179 | } | |
180 | return -1; | |
181 | } | |
182 | ||
183 | /* Read data from zip archive member. */ | |
184 | ||
185 | int | |
e7bf79cf | 186 | read_zip_member (JCF *jcf, ZipDirectory *zipd, ZipFile *zipf) |
de9c2bdc | 187 | { |
caa8fa37 | 188 | jcf->filbuf = jcf_unexpected_eof; |
4c36ffe6 | 189 | jcf->zipd = zipd; |
caa8fa37 | 190 | |
191 | if (zipd->compression_method == Z_NO_COMPRESSION) | |
192 | { | |
4c36ffe6 | 193 | jcf->buffer = XNEWVEC (unsigned char, zipd->size); |
caa8fa37 | 194 | jcf->buffer_end = jcf->buffer + zipd->size; |
195 | jcf->read_ptr = jcf->buffer; | |
196 | jcf->read_end = jcf->buffer_end; | |
197 | if (lseek (zipf->fd, zipd->filestart, 0) < 0 | |
198 | || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size) | |
199 | return -2; | |
200 | } | |
201 | else | |
202 | { | |
203 | char *buffer; | |
204 | z_stream d_stream; /* decompression stream */ | |
45e9f803 | 205 | memset (&d_stream, 0, sizeof (d_stream)); |
caa8fa37 | 206 | |
4c36ffe6 | 207 | jcf->buffer = XNEWVEC (unsigned char, zipd->uncompressed_size); |
caa8fa37 | 208 | d_stream.next_out = jcf->buffer; |
209 | d_stream.avail_out = zipd->uncompressed_size; | |
210 | jcf->buffer_end = jcf->buffer + zipd->uncompressed_size; | |
211 | jcf->read_ptr = jcf->buffer; | |
212 | jcf->read_end = jcf->buffer_end; | |
4c36ffe6 | 213 | buffer = XNEWVEC (char, zipd->size); |
8e452f9c | 214 | d_stream.next_in = (unsigned char *) buffer; |
caa8fa37 | 215 | d_stream.avail_in = zipd->size; |
216 | if (lseek (zipf->fd, zipd->filestart, 0) < 0 | |
217 | || read (zipf->fd, buffer, zipd->size) != (long) zipd->size) | |
218 | return -2; | |
219 | /* Handle NO_HEADER using undocumented zlib feature. | |
220 | This is a very common hack. */ | |
221 | inflateInit2 (&d_stream, -MAX_WBITS); | |
222 | inflate (&d_stream, Z_NO_FLUSH); | |
223 | inflateEnd (&d_stream); | |
4c36ffe6 | 224 | free (buffer); |
caa8fa37 | 225 | } |
226 | ||
227 | return 0; | |
377029eb | 228 | } |
377029eb | 229 | |
e772a198 | 230 | const char * |
e7bf79cf | 231 | open_class (const char *filename, JCF *jcf, int fd, const char *dep_name) |
377029eb | 232 | { |
233 | if (jcf) | |
234 | { | |
235 | struct stat stat_buf; | |
236 | if (fstat (fd, &stat_buf) != 0 | |
237 | || ! S_ISREG (stat_buf.st_mode)) | |
238 | { | |
239 | perror ("Could not figure length of .class file"); | |
240 | return NULL; | |
241 | } | |
b76c045f | 242 | if (dep_name != NULL) |
243 | jcf_dependency_add_file (dep_name, 0); | |
377029eb | 244 | JCF_ZERO (jcf); |
4c36ffe6 | 245 | jcf->buffer = XNEWVEC (unsigned char, stat_buf.st_size); |
377029eb | 246 | jcf->buffer_end = jcf->buffer + stat_buf.st_size; |
247 | jcf->read_ptr = jcf->buffer; | |
248 | jcf->read_end = jcf->buffer_end; | |
249 | jcf->read_state = NULL; | |
20677948 | 250 | jcf->filename = xstrdup (filename); |
377029eb | 251 | if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size) |
252 | { | |
253 | perror ("Failed to read .class file"); | |
254 | return NULL; | |
255 | } | |
256 | close (fd); | |
257 | jcf->filbuf = jcf_unexpected_eof; | |
258 | } | |
259 | else | |
260 | close (fd); | |
261 | return filename; | |
262 | } | |
377029eb | 263 | |
264 | ||
68ddcc2a | 265 | const char * |
e7bf79cf | 266 | find_classfile (char *filename, JCF *jcf, const char *dep_name) |
377029eb | 267 | { |
377029eb | 268 | int fd = open (filename, O_RDONLY | O_BINARY); |
269 | if (fd < 0) | |
270 | return NULL; | |
b76c045f | 271 | return open_class (filename, jcf, fd, dep_name); |
377029eb | 272 | } |
273 | ||
e98fb73e | 274 | |
d1455aa3 | 275 | /* Hash table helper. */ |
276 | ||
277 | struct charstar_hash : typed_noop_remove <char> | |
278 | { | |
c580da87 | 279 | typedef const char value_type; |
280 | typedef const char compare_type; | |
281 | static inline hashval_t hash (const value_type *candidate); | |
282 | static inline bool equal (const value_type *existing, | |
283 | const compare_type *candidate); | |
d1455aa3 | 284 | }; |
285 | ||
286 | inline hashval_t | |
c580da87 | 287 | charstar_hash::hash (const value_type *candidate) |
e98fb73e | 288 | { |
d1455aa3 | 289 | return htab_hash_string (candidate); |
e98fb73e | 290 | } |
291 | ||
d1455aa3 | 292 | inline bool |
c580da87 | 293 | charstar_hash::equal (const value_type *existing, const compare_type *candidate) |
d1455aa3 | 294 | { |
295 | return strcmp (existing, candidate) == 0; | |
296 | } | |
297 | ||
298 | ||
e98fb73e | 299 | /* A hash table keeping track of class names that were not found |
300 | during class lookup. (There is no need to cache the values | |
301 | associated with names that were found; they are saved in | |
302 | IDENTIFIER_CLASS_VALUE.) */ | |
d1455aa3 | 303 | static hash_table <charstar_hash> memoized_class_lookups; |
e98fb73e | 304 | |
377029eb | 305 | /* Returns a freshly malloc'd string with the fully qualified pathname |
e98fb73e | 306 | of the .class file for the class CLASSNAME. CLASSNAME must be |
307 | allocated in permanent storage; this function may retain a pointer | |
308 | to it. Returns NULL on failure. If JCF != NULL, it is suitably | |
309 | initialized. SOURCE_OK is true if we should also look for .java | |
310 | file. */ | |
377029eb | 311 | |
68ddcc2a | 312 | const char * |
7e476713 | 313 | find_class (const char *classname, int classname_length, JCF *jcf) |
377029eb | 314 | { |
377029eb | 315 | int fd; |
ead29d98 | 316 | int i, k, klass = -1; |
7e476713 | 317 | struct stat class_buf; |
b76c045f | 318 | char *dep_file; |
087b842d | 319 | void *entry; |
e98fb73e | 320 | int buflen; |
321 | char *buffer; | |
322 | hashval_t hash; | |
323 | ||
324 | /* Create the hash table, if it does not already exist. */ | |
d1455aa3 | 325 | if (!memoized_class_lookups.is_created ()) |
326 | memoized_class_lookups.create (37); | |
e98fb73e | 327 | |
328 | /* Loop for this class in the hashtable. If it is present, we've | |
329 | already looked for this class and failed to find it. */ | |
d1455aa3 | 330 | hash = charstar_hash::hash (classname); |
331 | if (memoized_class_lookups.find_with_hash (classname, hash)) | |
e98fb73e | 332 | return NULL; |
377029eb | 333 | |
334 | /* Allocate and zero out the buffer, since we don't explicitly put a | |
335 | null pointer when we're copying it below. */ | |
e98fb73e | 336 | buflen = jcf_path_max_len () + classname_length + 10; |
25a1c410 | 337 | buffer = XNEWVAR (char, buflen); |
93d3b7de | 338 | memset (buffer, 0, buflen); |
377029eb | 339 | |
bb9b756c | 340 | for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry)) |
377029eb | 341 | { |
68ddcc2a | 342 | const char *path_name = jcf_path_name (entry); |
ead29d98 | 343 | if (klass != 0) |
087b842d | 344 | { |
345 | int dir_len; | |
bb9b756c | 346 | |
087b842d | 347 | strcpy (buffer, path_name); |
348 | i = strlen (buffer); | |
bb9b756c | 349 | |
087b842d | 350 | /* This is right because we know that `.zip' entries will have a |
351 | trailing slash. See jcf-path.c. */ | |
352 | dir_len = i - 1; | |
bb9b756c | 353 | |
087b842d | 354 | for (k = 0; k < classname_length; k++, i++) |
355 | { | |
356 | char ch = classname[k]; | |
357 | buffer[i] = ch == '.' ? '/' : ch; | |
358 | } | |
359 | strcpy (buffer+i, ".class"); | |
bb9b756c | 360 | |
087b842d | 361 | if (jcf_path_is_zipfile (entry)) |
377029eb | 362 | { |
087b842d | 363 | int err_code; |
364 | JCF _jcf; | |
365 | buffer[dir_len] = '\0'; | |
366 | SOURCE_FRONTEND_DEBUG | |
367 | (("Trying [...%s]:%s", | |
368 | &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], | |
369 | buffer+dir_len+1)); | |
370 | if (jcf == NULL) | |
371 | jcf = &_jcf; | |
372 | err_code = open_in_zip (jcf, buffer, buffer+dir_len+1, | |
373 | jcf_path_is_system (entry)); | |
374 | if (err_code == 0) | |
377029eb | 375 | { |
087b842d | 376 | /* Should we check if .zip is out-of-date wrt .java? */ |
bb9b756c | 377 | buffer[dir_len] = '('; |
378 | strcpy (buffer+i, ".class)"); | |
087b842d | 379 | if (jcf == &_jcf) |
380 | JCF_FINISH (jcf); | |
381 | return buffer; | |
377029eb | 382 | } |
087b842d | 383 | else |
384 | continue; | |
377029eb | 385 | } |
93608f9d | 386 | klass = stat (buffer, &class_buf); |
bb9b756c | 387 | } |
d1016559 | 388 | } |
bb9b756c | 389 | |
7e476713 | 390 | dep_file = buffer; |
ead29d98 | 391 | if (!klass) |
d1016559 | 392 | { |
57e0b67f | 393 | SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n", |
394 | classname+classname_length- | |
395 | (classname_length <= 30 ? | |
396 | classname_length : 30))); | |
a1b2d596 | 397 | fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY | O_BINARY); |
d1016559 | 398 | if (fd >= 0) |
399 | goto found; | |
400 | } | |
d1016559 | 401 | |
377029eb | 402 | free (buffer); |
e98fb73e | 403 | |
404 | /* Remember that this class could not be found so that we do not | |
405 | have to look again. */ | |
d1455aa3 | 406 | *memoized_class_lookups.find_slot_with_hash (classname, hash, INSERT) |
407 | = classname; | |
e98fb73e | 408 | |
377029eb | 409 | return NULL; |
410 | found: | |
52d07779 | 411 | { |
412 | const char *const tmp = open_class (buffer, jcf, fd, dep_file); | |
413 | jcf->classname = xstrdup (classname); | |
414 | return tmp; | |
415 | } | |
377029eb | 416 | } |
417 | ||
418 | void | |
e7bf79cf | 419 | jcf_print_char (FILE *stream, int ch) |
377029eb | 420 | { |
421 | switch (ch) | |
422 | { | |
423 | case '\'': | |
424 | case '\\': | |
425 | case '\"': | |
426 | fprintf (stream, "\\%c", ch); | |
427 | break; | |
428 | case '\n': | |
429 | fprintf (stream, "\\n"); | |
430 | break; | |
431 | case '\t': | |
432 | fprintf (stream, "\\t"); | |
433 | break; | |
434 | case '\r': | |
435 | fprintf (stream, "\\r"); | |
436 | break; | |
437 | default: | |
438 | if (ch >= ' ' && ch < 127) | |
439 | putc (ch, stream); | |
440 | else if (ch < 256) | |
441 | fprintf (stream, "\\%03x", ch); | |
442 | else | |
443 | fprintf (stream, "\\u%04x", ch); | |
444 | } | |
445 | } | |
446 | ||
447 | /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */ | |
448 | ||
449 | void | |
fdbb243d | 450 | jcf_print_utf8 (FILE *stream, const unsigned char *str, int length) |
377029eb | 451 | { |
003019ba | 452 | const unsigned char * limit = str + length; |
377029eb | 453 | while (str < limit) |
454 | { | |
455 | int ch = UTF8_GET (str, limit); | |
456 | if (ch < 0) | |
457 | { | |
458 | fprintf (stream, "\\<invalid>"); | |
459 | return; | |
460 | } | |
461 | jcf_print_char (stream, ch); | |
462 | } | |
463 | } | |
464 | ||
465 | /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */ | |
466 | ||
467 | void | |
e7bf79cf | 468 | jcf_print_utf8_replace (FILE *stream, const unsigned char *str, int length, |
469 | int in_char, int out_char) | |
377029eb | 470 | { |
d9f14ffe | 471 | const unsigned char *limit = str + length; |
472 | while (str < limit) | |
377029eb | 473 | { |
d9f14ffe | 474 | int ch = UTF8_GET (str, limit); |
475 | if (ch < 0) | |
476 | { | |
477 | fprintf (stream, "\\<invalid>"); | |
478 | return; | |
479 | } | |
377029eb | 480 | jcf_print_char (stream, ch == in_char ? out_char : ch); |
481 | } | |
482 | } | |
483 | ||
484 | /* Check that all the cross-references in the constant pool are | |
485 | valid. Returns 0 on success. | |
9fb34998 | 486 | Otherwise, returns the index of the (first) invalid entry. |
487 | Only checks internal consistency, but does not check that | |
488 | any classes, fields, or methods are valid.*/ | |
377029eb | 489 | |
490 | int | |
e7bf79cf | 491 | verify_constant_pool (JCF *jcf) |
377029eb | 492 | { |
493 | int i, n; | |
494 | for (i = 1; i < JPOOL_SIZE (jcf); i++) | |
495 | { | |
496 | switch (JPOOL_TAG (jcf, i)) | |
497 | { | |
498 | case CONSTANT_NameAndType: | |
499 | n = JPOOL_USHORT2 (jcf, i); | |
500 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
501 | || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) | |
502 | return i; | |
503 | /* ... fall through ... */ | |
504 | case CONSTANT_Class: | |
505 | case CONSTANT_String: | |
506 | n = JPOOL_USHORT1 (jcf, i); | |
507 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
508 | || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) | |
509 | return i; | |
510 | break; | |
511 | case CONSTANT_Fieldref: | |
512 | case CONSTANT_Methodref: | |
513 | case CONSTANT_InterfaceMethodref: | |
514 | n = JPOOL_USHORT1 (jcf, i); | |
515 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
516 | || JPOOL_TAG (jcf, n) != CONSTANT_Class) | |
517 | return i; | |
518 | n = JPOOL_USHORT2 (jcf, i); | |
519 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
520 | || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) | |
521 | return i; | |
522 | break; | |
523 | case CONSTANT_Long: | |
524 | case CONSTANT_Double: | |
525 | i++; | |
526 | break; | |
527 | case CONSTANT_Float: | |
528 | case CONSTANT_Integer: | |
529 | case CONSTANT_Utf8: | |
530 | case CONSTANT_Unicode: | |
531 | break; | |
39101666 | 532 | case CONSTANT_MethodHandle: |
533 | n = JPOOL_USHORT1 (jcf, i); | |
534 | if (n < 1 || n > 9) | |
535 | return i; | |
536 | n = JPOOL_USHORT2 (jcf, i); | |
537 | if (n <= 0 || n >= JPOOL_SIZE(jcf)) | |
538 | return i; | |
539 | break; | |
540 | case CONSTANT_MethodType: | |
541 | n = JPOOL_USHORT1 (jcf, i); | |
542 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
543 | || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) | |
544 | return i; | |
545 | break; | |
546 | case CONSTANT_InvokeDynamic: | |
547 | n = JPOOL_USHORT2 (jcf, i); | |
548 | if (n <= 0 || n >= JPOOL_SIZE(jcf) | |
549 | || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) | |
550 | return i; | |
551 | break; | |
377029eb | 552 | default: |
553 | return i; | |
554 | } | |
555 | } | |
556 | return 0; | |
557 | } | |
558 | ||
559 | void | |
e7bf79cf | 560 | format_uint (char *buffer, uint64 value, int base) |
377029eb | 561 | { |
562 | #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8) | |
563 | char buf[WRITE_BUF_SIZE]; | |
fdbb243d | 564 | char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */ |
377029eb | 565 | int chars_written; |
566 | int i; | |
567 | ||
568 | /* Now do the actual conversion, placing the result at the *end* of buf. */ | |
569 | /* Note this code does not pretend to be optimized. */ | |
570 | do { | |
571 | int digit = value % base; | |
e99c3a1d | 572 | static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; |
377029eb | 573 | *--buf_ptr = digit_chars[digit]; |
574 | value /= base; | |
575 | } while (value != 0); | |
576 | ||
577 | chars_written = buf+WRITE_BUF_SIZE - buf_ptr; | |
578 | for (i = 0; i < chars_written; i++) | |
579 | buffer[i] = *buf_ptr++; | |
580 | buffer[i] = 0; | |
581 | } | |
582 | ||
583 | void | |
e7bf79cf | 584 | format_int (char *buffer, jlong value, int base) |
377029eb | 585 | { |
586 | uint64 abs_value; | |
587 | if (value < 0) | |
588 | { | |
589 | abs_value = -(uint64)value; | |
590 | *buffer++ = '-'; | |
591 | } | |
592 | else | |
593 | abs_value = (uint64) value; | |
594 | format_uint (buffer, abs_value, base); | |
595 | } |