xref: /openbsd/gnu/usr.bin/gcc/gcc/java/jcf-io.c (revision c87b03e5)
1*c87b03e5Sespie /* Utility routines for finding and reading Java(TM) .class files.
2*c87b03e5Sespie    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2002  Free Software Foundation, Inc.
3*c87b03e5Sespie 
4*c87b03e5Sespie This program is free software; you can redistribute it and/or modify
5*c87b03e5Sespie it under the terms of the GNU General Public License as published by
6*c87b03e5Sespie the Free Software Foundation; either version 2, or (at your option)
7*c87b03e5Sespie any later version.
8*c87b03e5Sespie 
9*c87b03e5Sespie This program is distributed in the hope that it will be useful,
10*c87b03e5Sespie but WITHOUT ANY WARRANTY; without even the implied warranty of
11*c87b03e5Sespie MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12*c87b03e5Sespie GNU General Public License for more details.
13*c87b03e5Sespie 
14*c87b03e5Sespie You should have received a copy of the GNU General Public License
15*c87b03e5Sespie along with GNU CC; see the file COPYING.  If not, write to
16*c87b03e5Sespie the Free Software Foundation, 59 Temple Place - Suite 330,
17*c87b03e5Sespie Boston, MA 02111-1307, USA.
18*c87b03e5Sespie 
19*c87b03e5Sespie Java and all Java-based marks are trademarks or registered trademarks
20*c87b03e5Sespie of Sun Microsystems, Inc. in the United States and other countries.
21*c87b03e5Sespie The Free Software Foundation is independent of Sun Microsystems, Inc.  */
22*c87b03e5Sespie 
23*c87b03e5Sespie /* Written by Per Bothner <bothner@cygnus.com>, February 1996. */
24*c87b03e5Sespie 
25*c87b03e5Sespie #include "config.h"
26*c87b03e5Sespie #include "system.h"
27*c87b03e5Sespie 
28*c87b03e5Sespie #include "jcf.h"
29*c87b03e5Sespie #include "tree.h"
30*c87b03e5Sespie #include "toplev.h"
31*c87b03e5Sespie #include "java-tree.h"
32*c87b03e5Sespie #include "hashtab.h"
33*c87b03e5Sespie #if JCF_USE_SCANDIR
34*c87b03e5Sespie #include <dirent.h>
35*c87b03e5Sespie #include <fnmatch.h>
36*c87b03e5Sespie #endif
37*c87b03e5Sespie 
38*c87b03e5Sespie #include "zlib.h"
39*c87b03e5Sespie 
40*c87b03e5Sespie /* DOS brain-damage */
41*c87b03e5Sespie #ifndef O_BINARY
42*c87b03e5Sespie #define O_BINARY 0 /* MS-DOS brain-damage */
43*c87b03e5Sespie #endif
44*c87b03e5Sespie 
45*c87b03e5Sespie int
46*c87b03e5Sespie DEFUN(jcf_unexpected_eof, (jcf, count),
47*c87b03e5Sespie       JCF *jcf AND int count ATTRIBUTE_UNUSED)
48*c87b03e5Sespie {
49*c87b03e5Sespie   if (jcf->filename)
50*c87b03e5Sespie     fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename);
51*c87b03e5Sespie   else
52*c87b03e5Sespie     fprintf (stderr, "Premature end of .class file <stdin>.\n");
53*c87b03e5Sespie   exit (-1);
54*c87b03e5Sespie }
55*c87b03e5Sespie 
56*c87b03e5Sespie void
57*c87b03e5Sespie DEFUN(jcf_trim_old_input, (jcf),
58*c87b03e5Sespie       JCF *jcf)
59*c87b03e5Sespie {
60*c87b03e5Sespie   int count = jcf->read_ptr - jcf->buffer;
61*c87b03e5Sespie   if (count > 0)
62*c87b03e5Sespie     {
63*c87b03e5Sespie       memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr);
64*c87b03e5Sespie       jcf->read_ptr -= count;
65*c87b03e5Sespie       jcf->read_end -= count;
66*c87b03e5Sespie     }
67*c87b03e5Sespie }
68*c87b03e5Sespie 
69*c87b03e5Sespie int
70*c87b03e5Sespie DEFUN(jcf_filbuf_from_stdio, (jcf, count),
71*c87b03e5Sespie       JCF *jcf AND int count)
72*c87b03e5Sespie {
73*c87b03e5Sespie   FILE *file = (FILE*) (jcf->read_state);
74*c87b03e5Sespie   if (count > jcf->buffer_end - jcf->read_ptr)
75*c87b03e5Sespie     {
76*c87b03e5Sespie       JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer;
77*c87b03e5Sespie       JCF_u4 old_read_end = jcf->read_end - jcf->buffer;
78*c87b03e5Sespie       JCF_u4 old_size = jcf->buffer_end - jcf->buffer;
79*c87b03e5Sespie       JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count;
80*c87b03e5Sespie       unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size)
81*c87b03e5Sespie 	: REALLOC (jcf->buffer, new_size);
82*c87b03e5Sespie       jcf->buffer = new_buffer;
83*c87b03e5Sespie       jcf->buffer_end = new_buffer + new_size;
84*c87b03e5Sespie       jcf->read_ptr = new_buffer + old_read_ptr;
85*c87b03e5Sespie       jcf->read_end = new_buffer + old_read_end;
86*c87b03e5Sespie     }
87*c87b03e5Sespie   count -= jcf->read_end - jcf->read_ptr;
88*c87b03e5Sespie   if (count <= 0)
89*c87b03e5Sespie     return 0;
90*c87b03e5Sespie   if ((int) fread (jcf->read_end, 1, count, file) != count)
91*c87b03e5Sespie     jcf_unexpected_eof (jcf, count);
92*c87b03e5Sespie   jcf->read_end += count;
93*c87b03e5Sespie   return 0;
94*c87b03e5Sespie }
95*c87b03e5Sespie 
96*c87b03e5Sespie #include "zipfile.h"
97*c87b03e5Sespie 
98*c87b03e5Sespie struct ZipFile *SeenZipFiles = NULL;
99*c87b03e5Sespie 
100*c87b03e5Sespie /* Open a zip file with the given name, and cache directory and file
101*c87b03e5Sespie    descriptor.  If the file is missing, treat it as an empty archive.
102*c87b03e5Sespie    Return NULL if the .zip file is malformed.
103*c87b03e5Sespie */
104*c87b03e5Sespie 
105*c87b03e5Sespie ZipFile *
106*c87b03e5Sespie DEFUN(opendir_in_zip, (zipfile, is_system),
107*c87b03e5Sespie       const char *zipfile AND int is_system)
108*c87b03e5Sespie {
109*c87b03e5Sespie   struct ZipFile* zipf;
110*c87b03e5Sespie   char magic [4];
111*c87b03e5Sespie   int fd;
112*c87b03e5Sespie   for (zipf = SeenZipFiles;  zipf != NULL;  zipf = zipf->next)
113*c87b03e5Sespie     {
114*c87b03e5Sespie       if (strcmp (zipf->name, zipfile) == 0)
115*c87b03e5Sespie 	return zipf;
116*c87b03e5Sespie     }
117*c87b03e5Sespie 
118*c87b03e5Sespie   zipf = ALLOC (sizeof (struct ZipFile) + strlen (zipfile) + 1);
119*c87b03e5Sespie   zipf->next = SeenZipFiles;
120*c87b03e5Sespie   zipf->name = (char*)(zipf+1);
121*c87b03e5Sespie   strcpy (zipf->name, zipfile);
122*c87b03e5Sespie   SeenZipFiles = zipf;
123*c87b03e5Sespie   fd = open (zipfile, O_RDONLY | O_BINARY);
124*c87b03e5Sespie   zipf->fd = fd;
125*c87b03e5Sespie   if (fd < 0)
126*c87b03e5Sespie     {
127*c87b03e5Sespie       /* A missing zip file is not considered an error.
128*c87b03e5Sespie        We may want to re-consider that.  FIXME. */
129*c87b03e5Sespie       zipf->count = 0;
130*c87b03e5Sespie       zipf->dir_size = 0;
131*c87b03e5Sespie       zipf->central_directory = NULL;
132*c87b03e5Sespie     }
133*c87b03e5Sespie   else
134*c87b03e5Sespie     {
135*c87b03e5Sespie       jcf_dependency_add_file (zipfile, is_system);
136*c87b03e5Sespie       if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC)
137*c87b03e5Sespie 	return NULL;
138*c87b03e5Sespie       lseek (fd, 0L, SEEK_SET);
139*c87b03e5Sespie       if (read_zip_archive (zipf) != 0)
140*c87b03e5Sespie 	return NULL;
141*c87b03e5Sespie     }
142*c87b03e5Sespie   return zipf;
143*c87b03e5Sespie }
144*c87b03e5Sespie 
145*c87b03e5Sespie /* Returns:
146*c87b03e5Sespie    0:  OK - zipmember found.
147*c87b03e5Sespie    -1: Not found.
148*c87b03e5Sespie    -2: Malformed archive.
149*c87b03e5Sespie */
150*c87b03e5Sespie 
151*c87b03e5Sespie int
152*c87b03e5Sespie DEFUN(open_in_zip, (jcf, zipfile, zipmember, is_system),
153*c87b03e5Sespie       JCF *jcf AND const char *zipfile AND const char *zipmember
154*c87b03e5Sespie       AND int is_system)
155*c87b03e5Sespie {
156*c87b03e5Sespie   ZipDirectory *zipd;
157*c87b03e5Sespie   int i, len;
158*c87b03e5Sespie   ZipFile *zipf = opendir_in_zip (zipfile, is_system);
159*c87b03e5Sespie 
160*c87b03e5Sespie   if (zipf == NULL)
161*c87b03e5Sespie     return -2;
162*c87b03e5Sespie 
163*c87b03e5Sespie   if (!zipmember)
164*c87b03e5Sespie     return 0;
165*c87b03e5Sespie 
166*c87b03e5Sespie   len = strlen (zipmember);
167*c87b03e5Sespie 
168*c87b03e5Sespie   zipd = (struct ZipDirectory*) zipf->central_directory;
169*c87b03e5Sespie   for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd))
170*c87b03e5Sespie     {
171*c87b03e5Sespie       if (len == zipd->filename_length &&
172*c87b03e5Sespie 	  strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0)
173*c87b03e5Sespie 	{
174*c87b03e5Sespie 	  JCF_ZERO (jcf);
175*c87b03e5Sespie 
176*c87b03e5Sespie 	  jcf->filename = xstrdup (zipfile);
177*c87b03e5Sespie 	  jcf->classname = xstrdup (zipmember);
178*c87b03e5Sespie 	  return read_zip_member(jcf, zipd, zipf);
179*c87b03e5Sespie 	}
180*c87b03e5Sespie     }
181*c87b03e5Sespie   return -1;
182*c87b03e5Sespie }
183*c87b03e5Sespie 
184*c87b03e5Sespie /* Read data from zip archive member. */
185*c87b03e5Sespie 
186*c87b03e5Sespie int
187*c87b03e5Sespie DEFUN(read_zip_member, (jcf, zipd, zipf),
188*c87b03e5Sespie       JCF *jcf AND  ZipDirectory *zipd AND ZipFile *zipf)
189*c87b03e5Sespie {
190*c87b03e5Sespie 	  jcf->filbuf = jcf_unexpected_eof;
191*c87b03e5Sespie 	  jcf->zipd = (void *)zipd;
192*c87b03e5Sespie 
193*c87b03e5Sespie 	  if (zipd->compression_method == Z_NO_COMPRESSION)
194*c87b03e5Sespie 	    {
195*c87b03e5Sespie 	      jcf->buffer = ALLOC (zipd->size);
196*c87b03e5Sespie 	      jcf->buffer_end = jcf->buffer + zipd->size;
197*c87b03e5Sespie 	      jcf->read_ptr = jcf->buffer;
198*c87b03e5Sespie 	      jcf->read_end = jcf->buffer_end;
199*c87b03e5Sespie 	      if (lseek (zipf->fd, zipd->filestart, 0) < 0
200*c87b03e5Sespie 		  || read (zipf->fd, jcf->buffer, zipd->size) != (long) zipd->size)
201*c87b03e5Sespie 	        return -2;
202*c87b03e5Sespie 	    }
203*c87b03e5Sespie 	  else
204*c87b03e5Sespie 	    {
205*c87b03e5Sespie 	      char *buffer;
206*c87b03e5Sespie 	      z_stream d_stream; /* decompression stream */
207*c87b03e5Sespie 	      d_stream.zalloc = (alloc_func) 0;
208*c87b03e5Sespie 	      d_stream.zfree = (free_func) 0;
209*c87b03e5Sespie 	      d_stream.opaque = (voidpf) 0;
210*c87b03e5Sespie 
211*c87b03e5Sespie 	      jcf->buffer = ALLOC (zipd->uncompressed_size);
212*c87b03e5Sespie 	      d_stream.next_out = jcf->buffer;
213*c87b03e5Sespie 	      d_stream.avail_out = zipd->uncompressed_size;
214*c87b03e5Sespie 	      jcf->buffer_end = jcf->buffer + zipd->uncompressed_size;
215*c87b03e5Sespie 	      jcf->read_ptr = jcf->buffer;
216*c87b03e5Sespie 	      jcf->read_end = jcf->buffer_end;
217*c87b03e5Sespie 	      buffer = ALLOC (zipd->size);
218*c87b03e5Sespie 	      d_stream.next_in = buffer;
219*c87b03e5Sespie 	      d_stream.avail_in = zipd->size;
220*c87b03e5Sespie 	      if (lseek (zipf->fd, zipd->filestart, 0) < 0
221*c87b03e5Sespie 		  || read (zipf->fd, buffer, zipd->size) != (long) zipd->size)
222*c87b03e5Sespie 		return -2;
223*c87b03e5Sespie 	      /* Handle NO_HEADER using undocumented zlib feature.
224*c87b03e5Sespie                  This is a very common hack.  */
225*c87b03e5Sespie 	      inflateInit2 (&d_stream, -MAX_WBITS);
226*c87b03e5Sespie 	      inflate (&d_stream, Z_NO_FLUSH);
227*c87b03e5Sespie 	      inflateEnd (&d_stream);
228*c87b03e5Sespie 	      FREE (buffer);
229*c87b03e5Sespie 	    }
230*c87b03e5Sespie 
231*c87b03e5Sespie 	  return 0;
232*c87b03e5Sespie }
233*c87b03e5Sespie 
234*c87b03e5Sespie const char *
235*c87b03e5Sespie DEFUN(open_class, (filename, jcf, fd, dep_name),
236*c87b03e5Sespie       const char *filename AND JCF *jcf AND int fd AND const char *dep_name)
237*c87b03e5Sespie {
238*c87b03e5Sespie   if (jcf)
239*c87b03e5Sespie     {
240*c87b03e5Sespie       struct stat stat_buf;
241*c87b03e5Sespie       if (fstat (fd, &stat_buf) != 0
242*c87b03e5Sespie 	  || ! S_ISREG (stat_buf.st_mode))
243*c87b03e5Sespie 	{
244*c87b03e5Sespie 	  perror ("Could not figure length of .class file");
245*c87b03e5Sespie 	  return NULL;
246*c87b03e5Sespie 	}
247*c87b03e5Sespie       if (dep_name != NULL)
248*c87b03e5Sespie 	jcf_dependency_add_file (dep_name, 0);
249*c87b03e5Sespie       JCF_ZERO (jcf);
250*c87b03e5Sespie       jcf->buffer = ALLOC (stat_buf.st_size);
251*c87b03e5Sespie       jcf->buffer_end = jcf->buffer + stat_buf.st_size;
252*c87b03e5Sespie       jcf->read_ptr = jcf->buffer;
253*c87b03e5Sespie       jcf->read_end = jcf->buffer_end;
254*c87b03e5Sespie       jcf->read_state = NULL;
255*c87b03e5Sespie       jcf->filename = filename;
256*c87b03e5Sespie       if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size)
257*c87b03e5Sespie 	{
258*c87b03e5Sespie 	  perror ("Failed to read .class file");
259*c87b03e5Sespie 	  return NULL;
260*c87b03e5Sespie 	}
261*c87b03e5Sespie       close (fd);
262*c87b03e5Sespie       jcf->filbuf = jcf_unexpected_eof;
263*c87b03e5Sespie     }
264*c87b03e5Sespie   else
265*c87b03e5Sespie     close (fd);
266*c87b03e5Sespie   return filename;
267*c87b03e5Sespie }
268*c87b03e5Sespie 
269*c87b03e5Sespie 
270*c87b03e5Sespie const char *
271*c87b03e5Sespie DEFUN(find_classfile, (filename, jcf, dep_name),
272*c87b03e5Sespie       char *filename AND JCF *jcf AND const char *dep_name)
273*c87b03e5Sespie {
274*c87b03e5Sespie   int fd = open (filename, O_RDONLY | O_BINARY);
275*c87b03e5Sespie   if (fd < 0)
276*c87b03e5Sespie     return NULL;
277*c87b03e5Sespie   return open_class (filename, jcf, fd, dep_name);
278*c87b03e5Sespie }
279*c87b03e5Sespie 
280*c87b03e5Sespie #if JCF_USE_SCANDIR
281*c87b03e5Sespie 
282*c87b03e5Sespie /* A comparison function (as for qsort) that compares KEY (a char *
283*c87b03e5Sespie    giving the basename of a file) with the name stored in ENTRY (a
284*c87b03e5Sespie    dirent **).  */
285*c87b03e5Sespie 
286*c87b03e5Sespie static int
287*c87b03e5Sespie DEFUN(compare_path, (key, entry),
288*c87b03e5Sespie       const void *key AND const void *entry)
289*c87b03e5Sespie {
290*c87b03e5Sespie   return strcmp ((const char *) key,
291*c87b03e5Sespie 		 (*((const struct dirent **) entry))->d_name);
292*c87b03e5Sespie }
293*c87b03e5Sespie 
294*c87b03e5Sespie /* Returns nonzero if ENTRY names a .java or .class file.  */
295*c87b03e5Sespie 
296*c87b03e5Sespie static int
297*c87b03e5Sespie DEFUN(java_or_class_file, (entry),
298*c87b03e5Sespie       const struct dirent *entry)
299*c87b03e5Sespie {
300*c87b03e5Sespie   const char *base = basename (entry->d_name);
301*c87b03e5Sespie   return (fnmatch ("*.java", base, 0) == 0 ||
302*c87b03e5Sespie 	  fnmatch ("*.class", base, 0) == 0);
303*c87b03e5Sespie }
304*c87b03e5Sespie 
305*c87b03e5Sespie /* Information about the files present in a particular directory.  */
306*c87b03e5Sespie typedef struct memoized_dirlist_entry
307*c87b03e5Sespie {
308*c87b03e5Sespie   /* The name of the directory.  */
309*c87b03e5Sespie   const char *dir;
310*c87b03e5Sespie   /* The number of .java and .class files present, or -1 if we could
311*c87b03e5Sespie      not, for some reason, obtain the list.  */
312*c87b03e5Sespie   int num_files;
313*c87b03e5Sespie   /* The .java and .class files in the directory, in alphabetical
314*c87b03e5Sespie      order.  */
315*c87b03e5Sespie   struct dirent **files;
316*c87b03e5Sespie } memoized_dirlist_entry;
317*c87b03e5Sespie 
318*c87b03e5Sespie /* Returns true if ENTRY (a memoized_dirlist_entry *) correponds to
319*c87b03e5Sespie    the directory given by KEY (a char *) giving the directory
320*c87b03e5Sespie    name.  */
321*c87b03e5Sespie 
322*c87b03e5Sespie static int
323*c87b03e5Sespie DEFUN(memoized_dirlist_lookup_eq, (entry, key),
324*c87b03e5Sespie       const void *entry AND const void *key)
325*c87b03e5Sespie {
326*c87b03e5Sespie   return strcmp ((const char *) key,
327*c87b03e5Sespie 		 ((const memoized_dirlist_entry *) entry)->dir) == 0;
328*c87b03e5Sespie }
329*c87b03e5Sespie 
330*c87b03e5Sespie /* A hash table mapping directory names to the lists of .java and
331*c87b03e5Sespie    .class files in that directory.  */
332*c87b03e5Sespie 
333*c87b03e5Sespie static htab_t memoized_dirlists;
334*c87b03e5Sespie 
335*c87b03e5Sespie #endif
336*c87b03e5Sespie 
337*c87b03e5Sespie /* Like stat, but avoids actually making the stat system call if we
338*c87b03e5Sespie    know that it cannot succeed.  FILENAME and BUF are as for stat.  */
339*c87b03e5Sespie 
340*c87b03e5Sespie static int
341*c87b03e5Sespie DEFUN(caching_stat, (filename, buf),
342*c87b03e5Sespie       char *filename AND struct stat *buf)
343*c87b03e5Sespie {
344*c87b03e5Sespie #if JCF_USE_SCANDIR
345*c87b03e5Sespie   char *sep;
346*c87b03e5Sespie   char origsep = 0;
347*c87b03e5Sespie   char *base;
348*c87b03e5Sespie   memoized_dirlist_entry *dent;
349*c87b03e5Sespie   void **slot;
350*c87b03e5Sespie 
351*c87b03e5Sespie   /* If the hashtable has not already been created, create it now.  */
352*c87b03e5Sespie   if (!memoized_dirlists)
353*c87b03e5Sespie     memoized_dirlists = htab_create (37,
354*c87b03e5Sespie 				     htab_hash_string,
355*c87b03e5Sespie 				     memoized_dirlist_lookup_eq,
356*c87b03e5Sespie 				     NULL);
357*c87b03e5Sespie 
358*c87b03e5Sespie   /* Get the name of the directory.  */
359*c87b03e5Sespie   sep = strrchr (filename, DIR_SEPARATOR);
360*c87b03e5Sespie #ifdef DIR_SEPARATOR_2
361*c87b03e5Sespie   if (! sep)
362*c87b03e5Sespie     sep = strrchr (filename, DIR_SEPARATOR_2);
363*c87b03e5Sespie #endif
364*c87b03e5Sespie   if (sep)
365*c87b03e5Sespie     {
366*c87b03e5Sespie       origsep = *sep;
367*c87b03e5Sespie       *sep = '\0';
368*c87b03e5Sespie       base = sep + 1;
369*c87b03e5Sespie     }
370*c87b03e5Sespie   else
371*c87b03e5Sespie     base = filename;
372*c87b03e5Sespie 
373*c87b03e5Sespie   /* Obtain the entry for this directory from the hash table.  */
374*c87b03e5Sespie   slot = htab_find_slot (memoized_dirlists, filename, INSERT);
375*c87b03e5Sespie   if (!*slot)
376*c87b03e5Sespie     {
377*c87b03e5Sespie       /* We have not already scanned this directory; scan it now.  */
378*c87b03e5Sespie       dent = ((memoized_dirlist_entry *)
379*c87b03e5Sespie 	      ALLOC (sizeof (memoized_dirlist_entry)));
380*c87b03e5Sespie       dent->dir = xstrdup (filename);
381*c87b03e5Sespie       /* Unfortunately, scandir is not fully standardized.  In
382*c87b03e5Sespie 	 particular, the type of the function pointer passed as the
383*c87b03e5Sespie 	 third argument sometimes takes a "const struct dirent *"
384*c87b03e5Sespie 	 parameter, and sometimes just a "struct dirent *".  We cast
385*c87b03e5Sespie 	 to (void *) so that either way it is quietly accepted.  */
386*c87b03e5Sespie       dent->num_files = scandir (filename, &dent->files,
387*c87b03e5Sespie 				 (void *) java_or_class_file,
388*c87b03e5Sespie 				 alphasort);
389*c87b03e5Sespie       *slot = dent;
390*c87b03e5Sespie     }
391*c87b03e5Sespie   else
392*c87b03e5Sespie     dent = *((memoized_dirlist_entry **) slot);
393*c87b03e5Sespie 
394*c87b03e5Sespie   /* Put the separator back.  */
395*c87b03e5Sespie   if (sep)
396*c87b03e5Sespie     *sep = origsep;
397*c87b03e5Sespie 
398*c87b03e5Sespie   /* If the file is not in the list, there is no need to stat it; it
399*c87b03e5Sespie      does not exist.  */
400*c87b03e5Sespie   if (dent->num_files != -1
401*c87b03e5Sespie       && !bsearch (base, dent->files, dent->num_files,
402*c87b03e5Sespie 		   sizeof (struct dirent *), compare_path))
403*c87b03e5Sespie     return -1;
404*c87b03e5Sespie #endif
405*c87b03e5Sespie 
406*c87b03e5Sespie   return stat (filename, buf);
407*c87b03e5Sespie }
408*c87b03e5Sespie 
409*c87b03e5Sespie /* Returns 1 if the CLASSNAME (really a char *) matches the name
410*c87b03e5Sespie    stored in TABLE_ENTRY (also a char *).  */
411*c87b03e5Sespie 
412*c87b03e5Sespie static int
413*c87b03e5Sespie DEFUN(memoized_class_lookup_eq, (table_entry, classname),
414*c87b03e5Sespie       const void *table_entry AND const void *classname)
415*c87b03e5Sespie {
416*c87b03e5Sespie   return strcmp ((const char *)classname, (const char *)table_entry) == 0;
417*c87b03e5Sespie }
418*c87b03e5Sespie 
419*c87b03e5Sespie /* A hash table keeping track of class names that were not found
420*c87b03e5Sespie    during class lookup.  (There is no need to cache the values
421*c87b03e5Sespie    associated with names that were found; they are saved in
422*c87b03e5Sespie    IDENTIFIER_CLASS_VALUE.)  */
423*c87b03e5Sespie static htab_t memoized_class_lookups;
424*c87b03e5Sespie 
425*c87b03e5Sespie /* Returns a freshly malloc'd string with the fully qualified pathname
426*c87b03e5Sespie    of the .class file for the class CLASSNAME.  CLASSNAME must be
427*c87b03e5Sespie    allocated in permanent storage; this function may retain a pointer
428*c87b03e5Sespie    to it.  Returns NULL on failure.  If JCF != NULL, it is suitably
429*c87b03e5Sespie    initialized.  SOURCE_OK is true if we should also look for .java
430*c87b03e5Sespie    file. */
431*c87b03e5Sespie 
432*c87b03e5Sespie const char *
433*c87b03e5Sespie DEFUN(find_class, (classname, classname_length, jcf, source_ok),
434*c87b03e5Sespie       const char *classname AND int classname_length AND JCF *jcf AND int source_ok)
435*c87b03e5Sespie 
436*c87b03e5Sespie {
437*c87b03e5Sespie   int fd;
438*c87b03e5Sespie   int i, k, java = -1, class = -1;
439*c87b03e5Sespie   struct stat java_buf, class_buf;
440*c87b03e5Sespie   char *dep_file;
441*c87b03e5Sespie   void *entry;
442*c87b03e5Sespie   char *java_buffer;
443*c87b03e5Sespie   int buflen;
444*c87b03e5Sespie   char *buffer;
445*c87b03e5Sespie   hashval_t hash;
446*c87b03e5Sespie 
447*c87b03e5Sespie   /* Create the hash table, if it does not already exist.  */
448*c87b03e5Sespie   if (!memoized_class_lookups)
449*c87b03e5Sespie     memoized_class_lookups = htab_create (37,
450*c87b03e5Sespie 					  htab_hash_string,
451*c87b03e5Sespie 					  memoized_class_lookup_eq,
452*c87b03e5Sespie 					  NULL);
453*c87b03e5Sespie 
454*c87b03e5Sespie   /* Loop for this class in the hashtable.  If it is present, we've
455*c87b03e5Sespie      already looked for this class and failed to find it.  */
456*c87b03e5Sespie   hash = htab_hash_string (classname);
457*c87b03e5Sespie   if (htab_find_with_hash (memoized_class_lookups, classname, hash))
458*c87b03e5Sespie     return NULL;
459*c87b03e5Sespie 
460*c87b03e5Sespie   /* Allocate and zero out the buffer, since we don't explicitly put a
461*c87b03e5Sespie      null pointer when we're copying it below.  */
462*c87b03e5Sespie   buflen = jcf_path_max_len () + classname_length + 10;
463*c87b03e5Sespie   buffer = ALLOC (buflen);
464*c87b03e5Sespie   memset (buffer, 0, buflen);
465*c87b03e5Sespie 
466*c87b03e5Sespie   java_buffer = alloca (buflen);
467*c87b03e5Sespie 
468*c87b03e5Sespie   jcf->java_source = 0;
469*c87b03e5Sespie 
470*c87b03e5Sespie   for (entry = jcf_path_start (); entry != NULL; entry = jcf_path_next (entry))
471*c87b03e5Sespie     {
472*c87b03e5Sespie       const char *path_name = jcf_path_name (entry);
473*c87b03e5Sespie       if (class != 0)
474*c87b03e5Sespie 	{
475*c87b03e5Sespie 	  int dir_len;
476*c87b03e5Sespie 
477*c87b03e5Sespie 	  strcpy (buffer, path_name);
478*c87b03e5Sespie 	  i = strlen (buffer);
479*c87b03e5Sespie 
480*c87b03e5Sespie 	  /* This is right because we know that `.zip' entries will have a
481*c87b03e5Sespie 	     trailing slash.  See jcf-path.c.  */
482*c87b03e5Sespie 	  dir_len = i - 1;
483*c87b03e5Sespie 
484*c87b03e5Sespie 	  for (k = 0; k < classname_length; k++, i++)
485*c87b03e5Sespie 	    {
486*c87b03e5Sespie 	      char ch = classname[k];
487*c87b03e5Sespie 	      buffer[i] = ch == '.' ? '/' : ch;
488*c87b03e5Sespie 	    }
489*c87b03e5Sespie 	  strcpy (buffer+i, ".class");
490*c87b03e5Sespie 
491*c87b03e5Sespie 	  if (jcf_path_is_zipfile (entry))
492*c87b03e5Sespie 	    {
493*c87b03e5Sespie 	      int err_code;
494*c87b03e5Sespie 	      JCF _jcf;
495*c87b03e5Sespie 	      buffer[dir_len] = '\0';
496*c87b03e5Sespie 	      SOURCE_FRONTEND_DEBUG
497*c87b03e5Sespie 		(("Trying [...%s]:%s",
498*c87b03e5Sespie 		  &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)],
499*c87b03e5Sespie 		  buffer+dir_len+1));
500*c87b03e5Sespie 	      if (jcf == NULL)
501*c87b03e5Sespie 		jcf = &_jcf;
502*c87b03e5Sespie 	      err_code = open_in_zip (jcf, buffer, buffer+dir_len+1,
503*c87b03e5Sespie 				      jcf_path_is_system (entry));
504*c87b03e5Sespie 	      if (err_code == 0)
505*c87b03e5Sespie 		{
506*c87b03e5Sespie 		  /* Should we check if .zip is out-of-date wrt .java? */
507*c87b03e5Sespie 		  buffer[dir_len] = '(';
508*c87b03e5Sespie 		  strcpy (buffer+i, ".class)");
509*c87b03e5Sespie 		  if (jcf == &_jcf)
510*c87b03e5Sespie 		    JCF_FINISH (jcf);
511*c87b03e5Sespie 		  return buffer;
512*c87b03e5Sespie 		}
513*c87b03e5Sespie 	      else
514*c87b03e5Sespie 		continue;
515*c87b03e5Sespie 	    }
516*c87b03e5Sespie 	  class = caching_stat(buffer, &class_buf);
517*c87b03e5Sespie 	}
518*c87b03e5Sespie 
519*c87b03e5Sespie       if (source_ok)
520*c87b03e5Sespie 	{
521*c87b03e5Sespie 	  /* Compute name of .java file.  */
522*c87b03e5Sespie 	  int l, m;
523*c87b03e5Sespie 	  strcpy (java_buffer, path_name);
524*c87b03e5Sespie 	  l = strlen (java_buffer);
525*c87b03e5Sespie 	  for (m = 0; m < classname_length; ++m)
526*c87b03e5Sespie 	    java_buffer[m + l] = (classname[m] == '.'
527*c87b03e5Sespie 				  ? DIR_SEPARATOR : classname[m]);
528*c87b03e5Sespie 	  strcpy (java_buffer + m + l, ".java");
529*c87b03e5Sespie 	  java = caching_stat (java_buffer, &java_buf);
530*c87b03e5Sespie 	  if (java == 0)
531*c87b03e5Sespie 	    break;
532*c87b03e5Sespie 	}
533*c87b03e5Sespie     }
534*c87b03e5Sespie 
535*c87b03e5Sespie   /* We preferably pick a class file if we have a chance. If the source
536*c87b03e5Sespie      file is newer than the class file, we issue a warning and parse the
537*c87b03e5Sespie      source file instead.
538*c87b03e5Sespie      There should be a flag to allow people have the class file picked
539*c87b03e5Sespie      up no matter what. FIXME. */
540*c87b03e5Sespie   if (! java && ! class && java_buf.st_mtime > class_buf.st_mtime)
541*c87b03e5Sespie     {
542*c87b03e5Sespie       if (flag_newer)
543*c87b03e5Sespie 	warning ("source file for class `%s' is newer than its matching class file.  Source file `%s' used instead", classname, java_buffer);
544*c87b03e5Sespie       class = -1;
545*c87b03e5Sespie     }
546*c87b03e5Sespie 
547*c87b03e5Sespie   if (! java)
548*c87b03e5Sespie     dep_file = java_buffer;
549*c87b03e5Sespie   else
550*c87b03e5Sespie     dep_file = buffer;
551*c87b03e5Sespie   if (!class)
552*c87b03e5Sespie     {
553*c87b03e5Sespie       SOURCE_FRONTEND_DEBUG ((stderr, "[Class selected: %s]\n",
554*c87b03e5Sespie 			      classname+classname_length-
555*c87b03e5Sespie 			      (classname_length <= 30 ?
556*c87b03e5Sespie 			       classname_length : 30)));
557*c87b03e5Sespie       fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY | O_BINARY);
558*c87b03e5Sespie       if (fd >= 0)
559*c87b03e5Sespie 	goto found;
560*c87b03e5Sespie     }
561*c87b03e5Sespie   /* Give .java a try, if necessary */
562*c87b03e5Sespie   if (!java)
563*c87b03e5Sespie     {
564*c87b03e5Sespie       strcpy (buffer, java_buffer);
565*c87b03e5Sespie       SOURCE_FRONTEND_DEBUG ((stderr, "[Source selected: %s]\n",
566*c87b03e5Sespie 			      classname+classname_length-
567*c87b03e5Sespie 			      (classname_length <= 30 ?
568*c87b03e5Sespie 			       classname_length : 30)));
569*c87b03e5Sespie       fd = JCF_OPEN_EXACT_CASE (buffer, O_RDONLY);
570*c87b03e5Sespie       if (fd >= 0)
571*c87b03e5Sespie 	{
572*c87b03e5Sespie 	  jcf->java_source = 1;
573*c87b03e5Sespie 	  goto found;
574*c87b03e5Sespie 	}
575*c87b03e5Sespie     }
576*c87b03e5Sespie 
577*c87b03e5Sespie   free (buffer);
578*c87b03e5Sespie 
579*c87b03e5Sespie   /* Remember that this class could not be found so that we do not
580*c87b03e5Sespie      have to look again.  */
581*c87b03e5Sespie   *htab_find_slot_with_hash (memoized_class_lookups, classname, hash, INSERT)
582*c87b03e5Sespie     = (void *) classname;
583*c87b03e5Sespie 
584*c87b03e5Sespie   return NULL;
585*c87b03e5Sespie  found:
586*c87b03e5Sespie   if (jcf->java_source)
587*c87b03e5Sespie     {
588*c87b03e5Sespie       JCF_ZERO (jcf);		/* JCF_FINISH relies on this */
589*c87b03e5Sespie       jcf->java_source = 1;
590*c87b03e5Sespie       jcf->filename = xstrdup (buffer);
591*c87b03e5Sespie       close (fd);		/* We use STDIO for source file */
592*c87b03e5Sespie     }
593*c87b03e5Sespie   else
594*c87b03e5Sespie     buffer = (char *) open_class (buffer, jcf, fd, dep_file);
595*c87b03e5Sespie   jcf->classname = xstrdup (classname);
596*c87b03e5Sespie   return buffer;
597*c87b03e5Sespie }
598*c87b03e5Sespie 
599*c87b03e5Sespie void
600*c87b03e5Sespie DEFUN(jcf_print_char, (stream, ch),
601*c87b03e5Sespie       FILE *stream AND int ch)
602*c87b03e5Sespie {
603*c87b03e5Sespie   switch (ch)
604*c87b03e5Sespie     {
605*c87b03e5Sespie     case '\'':
606*c87b03e5Sespie     case '\\':
607*c87b03e5Sespie     case '\"':
608*c87b03e5Sespie       fprintf (stream, "\\%c", ch);
609*c87b03e5Sespie       break;
610*c87b03e5Sespie     case '\n':
611*c87b03e5Sespie       fprintf (stream, "\\n");
612*c87b03e5Sespie       break;
613*c87b03e5Sespie     case '\t':
614*c87b03e5Sespie       fprintf (stream, "\\t");
615*c87b03e5Sespie       break;
616*c87b03e5Sespie     case '\r':
617*c87b03e5Sespie       fprintf (stream, "\\r");
618*c87b03e5Sespie       break;
619*c87b03e5Sespie     default:
620*c87b03e5Sespie       if (ch >= ' ' && ch < 127)
621*c87b03e5Sespie 	putc (ch, stream);
622*c87b03e5Sespie       else if (ch < 256)
623*c87b03e5Sespie 	fprintf (stream, "\\%03x", ch);
624*c87b03e5Sespie       else
625*c87b03e5Sespie 	fprintf (stream, "\\u%04x", ch);
626*c87b03e5Sespie     }
627*c87b03e5Sespie }
628*c87b03e5Sespie 
629*c87b03e5Sespie /* Print UTF8 string at STR of length LENGTH bytes to STREAM. */
630*c87b03e5Sespie 
631*c87b03e5Sespie void
632*c87b03e5Sespie DEFUN(jcf_print_utf8, (stream, str, length),
633*c87b03e5Sespie       FILE *stream AND register const unsigned char *str AND int length)
634*c87b03e5Sespie {
635*c87b03e5Sespie   const unsigned char * limit = str + length;
636*c87b03e5Sespie   while (str < limit)
637*c87b03e5Sespie     {
638*c87b03e5Sespie       int ch = UTF8_GET (str, limit);
639*c87b03e5Sespie       if (ch < 0)
640*c87b03e5Sespie 	{
641*c87b03e5Sespie 	  fprintf (stream, "\\<invalid>");
642*c87b03e5Sespie 	  return;
643*c87b03e5Sespie 	}
644*c87b03e5Sespie       jcf_print_char (stream, ch);
645*c87b03e5Sespie     }
646*c87b03e5Sespie }
647*c87b03e5Sespie 
648*c87b03e5Sespie /* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */
649*c87b03e5Sespie 
650*c87b03e5Sespie void
651*c87b03e5Sespie DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char),
652*c87b03e5Sespie       FILE *stream AND const unsigned char *str AND int length
653*c87b03e5Sespie       AND int in_char AND int out_char)
654*c87b03e5Sespie {
655*c87b03e5Sespie   const unsigned char *limit = str + length;
656*c87b03e5Sespie   while (str < limit)
657*c87b03e5Sespie     {
658*c87b03e5Sespie       int ch = UTF8_GET (str, limit);
659*c87b03e5Sespie       if (ch < 0)
660*c87b03e5Sespie 	{
661*c87b03e5Sespie 	  fprintf (stream, "\\<invalid>");
662*c87b03e5Sespie 	  return;
663*c87b03e5Sespie 	}
664*c87b03e5Sespie       jcf_print_char (stream, ch == in_char ? out_char : ch);
665*c87b03e5Sespie     }
666*c87b03e5Sespie }
667*c87b03e5Sespie 
668*c87b03e5Sespie /* Check that all the cross-references in the constant pool are
669*c87b03e5Sespie    valid.  Returns 0 on success.
670*c87b03e5Sespie    Otherwise, returns the index of the (first) invalid entry.
671*c87b03e5Sespie    Only checks internal consistency, but does not check that
672*c87b03e5Sespie    any classes, fields, or methods are valid.*/
673*c87b03e5Sespie 
674*c87b03e5Sespie int
675*c87b03e5Sespie DEFUN(verify_constant_pool, (jcf),
676*c87b03e5Sespie       JCF *jcf)
677*c87b03e5Sespie {
678*c87b03e5Sespie   int i, n;
679*c87b03e5Sespie   for (i = 1; i < JPOOL_SIZE (jcf); i++)
680*c87b03e5Sespie     {
681*c87b03e5Sespie       switch (JPOOL_TAG (jcf, i))
682*c87b03e5Sespie 	{
683*c87b03e5Sespie 	case CONSTANT_NameAndType:
684*c87b03e5Sespie 	  n = JPOOL_USHORT2 (jcf, i);
685*c87b03e5Sespie 	  if (n <= 0 || n >= JPOOL_SIZE(jcf)
686*c87b03e5Sespie 	      || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
687*c87b03e5Sespie 	    return i;
688*c87b03e5Sespie 	  /* ... fall through ... */
689*c87b03e5Sespie 	case CONSTANT_Class:
690*c87b03e5Sespie 	case CONSTANT_String:
691*c87b03e5Sespie 	  n = JPOOL_USHORT1 (jcf, i);
692*c87b03e5Sespie 	  if (n <= 0 || n >= JPOOL_SIZE(jcf)
693*c87b03e5Sespie 	      || JPOOL_TAG (jcf, n) != CONSTANT_Utf8)
694*c87b03e5Sespie 	    return i;
695*c87b03e5Sespie 	  break;
696*c87b03e5Sespie 	case CONSTANT_Fieldref:
697*c87b03e5Sespie 	case CONSTANT_Methodref:
698*c87b03e5Sespie 	case CONSTANT_InterfaceMethodref:
699*c87b03e5Sespie 	  n = JPOOL_USHORT1 (jcf, i);
700*c87b03e5Sespie 	  if (n <= 0 || n >= JPOOL_SIZE(jcf)
701*c87b03e5Sespie 	      || JPOOL_TAG (jcf, n) != CONSTANT_Class)
702*c87b03e5Sespie 	    return i;
703*c87b03e5Sespie 	  n = JPOOL_USHORT2 (jcf, i);
704*c87b03e5Sespie 	  if (n <= 0 || n >= JPOOL_SIZE(jcf)
705*c87b03e5Sespie 	      || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType)
706*c87b03e5Sespie 	    return i;
707*c87b03e5Sespie 	  break;
708*c87b03e5Sespie 	case CONSTANT_Long:
709*c87b03e5Sespie 	case CONSTANT_Double:
710*c87b03e5Sespie 	  i++;
711*c87b03e5Sespie 	  break;
712*c87b03e5Sespie 	case CONSTANT_Float:
713*c87b03e5Sespie 	case CONSTANT_Integer:
714*c87b03e5Sespie 	case CONSTANT_Utf8:
715*c87b03e5Sespie 	case CONSTANT_Unicode:
716*c87b03e5Sespie 	  break;
717*c87b03e5Sespie 	default:
718*c87b03e5Sespie 	  return i;
719*c87b03e5Sespie 	}
720*c87b03e5Sespie     }
721*c87b03e5Sespie   return 0;
722*c87b03e5Sespie }
723*c87b03e5Sespie 
724*c87b03e5Sespie void
725*c87b03e5Sespie DEFUN(format_uint, (buffer, value, base),
726*c87b03e5Sespie       char *buffer AND uint64 value AND int base)
727*c87b03e5Sespie {
728*c87b03e5Sespie #define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8)
729*c87b03e5Sespie   char buf[WRITE_BUF_SIZE];
730*c87b03e5Sespie   register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */
731*c87b03e5Sespie   int chars_written;
732*c87b03e5Sespie   int i;
733*c87b03e5Sespie 
734*c87b03e5Sespie   /* Now do the actual conversion, placing the result at the *end* of buf. */
735*c87b03e5Sespie   /* Note this code does not pretend to be optimized. */
736*c87b03e5Sespie   do {
737*c87b03e5Sespie     int digit = value % base;
738*c87b03e5Sespie     static const char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz";
739*c87b03e5Sespie     *--buf_ptr = digit_chars[digit];
740*c87b03e5Sespie     value /= base;
741*c87b03e5Sespie   } while (value != 0);
742*c87b03e5Sespie 
743*c87b03e5Sespie   chars_written = buf+WRITE_BUF_SIZE - buf_ptr;
744*c87b03e5Sespie   for (i = 0; i < chars_written; i++)
745*c87b03e5Sespie     buffer[i] = *buf_ptr++;
746*c87b03e5Sespie   buffer[i] = 0;
747*c87b03e5Sespie }
748*c87b03e5Sespie 
749*c87b03e5Sespie void
750*c87b03e5Sespie DEFUN(format_int, (buffer, value, base),
751*c87b03e5Sespie       char *buffer AND jlong value AND int base)
752*c87b03e5Sespie {
753*c87b03e5Sespie   uint64 abs_value;
754*c87b03e5Sespie   if (value < 0)
755*c87b03e5Sespie     {
756*c87b03e5Sespie       abs_value = -(uint64)value;
757*c87b03e5Sespie       *buffer++ = '-';
758*c87b03e5Sespie     }
759*c87b03e5Sespie   else
760*c87b03e5Sespie     abs_value = (uint64) value;
761*c87b03e5Sespie   format_uint (buffer, abs_value, base);
762*c87b03e5Sespie }
763