1 /* Copyright (C) 2004, 2005, 2006, 2007 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 package gnu.gcj.tools.gcj_dbtool;
12 import gnu.gcj.runtime.PersistentByteMap;
14 import java.nio.channels.*;
16 import java.util.jar.*;
17 import java.security.MessageDigest;
21 static private boolean verbose = false;
23 public static void main (String[] s)
25 boolean fileListFromStdin = false;
26 char filenameSeparator = ' ';
28 insist (s.length >= 1);
30 if (s[0].equals("-") ||
33 if (s[0].equals("-0"))
34 filenameSeparator = (char)0;
35 fileListFromStdin = true;
36 String[] newArgs = new String[s.length - 1];
37 System.arraycopy(s, 1, newArgs, 0, s.length - 1);
41 if (s[0].equals("-v") || s[0].equals("--version"))
43 insist (s.length == 1);
44 System.out.println("gcj-dbtool ("
45 + System.getProperty("java.vm.name")
47 + System.getProperty("java.vm.version"));
49 System.out.println("Copyright 2006 Free Software Foundation, Inc.");
50 System.out.println("This is free software; see the source for copying conditions. There is NO");
51 System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
54 if (s[0].equals("--help"))
60 if (s[0].equals("-n"))
62 // Create a new database.
63 insist (s.length >= 2 && s.length <= 3);
69 capacity = Integer.parseInt(s[2]);
81 = PersistentByteMap.emptyPersistentByteMap(new File(s[1]),
82 capacity, capacity*32);
86 System.err.println ("error: could not create "
87 + s[1] + ": " + e.toString());
93 if (s[0].equals("-a") || s[0].equals("-f"))
95 // Add a jar file to a database, creating it if necessary.
96 // Copies the database, adds the jar file to the copy, and
97 // then renames the new database over the old.
100 insist (s.length == 4);
101 File database = new File(s[1]);
102 database = database.getAbsoluteFile();
103 File jar = new File(s[2]);
104 PersistentByteMap map;
105 if (database.isFile())
106 map = new PersistentByteMap(database,
107 PersistentByteMap.AccessMode.READ_ONLY);
109 map = PersistentByteMap.emptyPersistentByteMap(database,
111 File soFile = new File(s[3]);
112 if (! s[0].equals("-f") && ! soFile.isFile())
113 throw new IllegalArgumentException(s[3] + " is not a file");
114 map = addJar(jar, map, soFile);
118 System.err.println ("error: could not update " + s[1]
119 + ": " + e.toString());
125 if (s[0].equals("-t"))
130 insist (s.length == 2);
132 = new PersistentByteMap(new File(s[1]),
133 PersistentByteMap.AccessMode.READ_ONLY);
134 Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
136 while (iterator.hasNext())
138 PersistentByteMap.MapEntry entry
139 = (PersistentByteMap.MapEntry)iterator.next();
140 byte[] key = (byte[])entry.getKey();
141 byte[] value = (byte[])b.get(key);
142 if (! Arrays.equals (value, (byte[])entry.getValue()))
145 = ("Key " + bytesToString(key) + " at bucket "
146 + entry.getBucket());
148 throw new RuntimeException(err);
160 if (s[0].equals("-m"))
163 insist (s.length >= 3
164 || fileListFromStdin && s.length == 2);
167 File database = new File(s[1]);
168 database = database.getAbsoluteFile();
169 File temp = File.createTempFile(database.getName(), "",
170 database.getParentFile());
173 int newStringTableSize = 0;
174 Fileset files = getFiles(s, 2, fileListFromStdin,
176 PersistentByteMap[] sourceMaps
177 = new PersistentByteMap[files.size()];
179 // Scan all the input files, calculating worst case string
180 // table and hash table use.
182 Iterator it = files.iterator();
187 = new PersistentByteMap((File)it.next(),
188 PersistentByteMap.AccessMode.READ_ONLY);
190 newStringTableSize += b.stringTableSize();
195 newSize *= 1.5; // Scaling the new size by 1.5 results in
197 PersistentByteMap map
198 = PersistentByteMap.emptyPersistentByteMap
199 (temp, newSize, newStringTableSize);
201 for (int i = 0; i < sourceMaps.length; i++)
204 System.err.println("adding " + sourceMaps[i].size()
206 + sourceMaps[i].getFile());
207 map.putAll(sourceMaps[i]);
210 temp.renameTo(database);
220 if (s[0].equals("-l"))
223 insist (s.length == 2);
227 = new PersistentByteMap(new File(s[1]),
228 PersistentByteMap.AccessMode.READ_ONLY);
230 System.out.println ("Capacity: " + b.capacity());
231 System.out.println ("Size: " + b.size());
232 System.out.println ();
234 System.out.println ("Elements: ");
235 Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
237 while (iterator.hasNext())
239 PersistentByteMap.MapEntry entry
240 = (PersistentByteMap.MapEntry)iterator.next();
241 byte[] digest = (byte[])entry.getKey();
242 System.out.print ("[" + entry.getBucket() + "] "
243 + bytesToString(digest)
245 System.out.println (new String((byte[])entry.getValue()));
250 System.err.println ("error: could not list "
251 + s[1] + ": " + e.toString());
257 if (s[0].equals("-d"))
259 // For testing only: fill the byte map with random data.
260 insist (s.length == 2);
263 MessageDigest md = MessageDigest.getInstance("MD5");
265 = new PersistentByteMap(new File(s[1]),
266 PersistentByteMap.AccessMode.READ_WRITE);
267 int N = b.capacity();
268 byte[] bytes = new byte[1];
269 byte digest[] = md.digest(bytes);
270 for (int i = 0; i < N; i++)
272 digest = md.digest(digest);
273 b.put(digest, digest);
284 if (s[0].equals("-p"))
286 insist (s.length == 1 || s.length == 2);
290 result = System.getProperty("gnu.gcj.precompiled.db.path", "");
293 + (s[1].endsWith(File.separator) ? "" : File.separator)
296 System.out.println (result);
304 private static native String getDbPathTail ();
306 private static void insist(boolean ok)
315 private static void usage(PrintStream out)
318 ("gcj-dbtool: Manipulate gcj map database files\n"
321 + " gcj-dbtool -n file.gcjdb [size] - Create a new gcj map database\n"
322 + " gcj-dbtool -a file.gcjdb file.jar file.so\n"
323 + " - Add the contents of file.jar to a gcj map database\n"
324 + " gcj-dbtool -f file.gcjdb file.jar file.so\n"
325 + " - Add the contents of file.jar to a gcj map database\n"
326 + " gcj-dbtool -t file.gcjdb - Test a gcj map database\n"
327 + " gcj-dbtool -l file.gcjdb - List a gcj map database\n"
328 + " gcj-dbtool [-][-0] -m dest.gcjdb [source.gcjdb]...\n"
329 + " - Merge gcj map databases into dest\n"
331 + " To add to dest, include dest in the list of sources\n"
332 + " If the first arg is -, read the list from stdin\n"
333 + " If the first arg is -0, filenames separated by nul\n"
334 + " gcj-dbtool -p [LIBDIR] - Print default database name"
338 // Add a jar to a map. This copies the map first and returns a
339 // different map that contains the data. The original map is
342 private static PersistentByteMap
343 addJar(File f, PersistentByteMap b, File soFile)
346 MessageDigest md = MessageDigest.getInstance("MD5");
348 JarFile jar = new JarFile (f);
352 Enumeration entries = jar.entries();
353 while (entries.hasMoreElements())
355 JarEntry classfile = (JarEntry)entries.nextElement();
356 if (classfile.getName().endsWith(".class"))
362 System.err.println("adding " + count + " elements from "
363 + f + " to " + b.getFile());
365 // Maybe resize the destination map. We're allowing plenty of
366 // extra space by using a loadFactor of 2.
367 b = resizeMap(b, (b.size() + count) * 2, true);
369 Enumeration entries = jar.entries();
371 byte[] soFileName = soFile.getCanonicalPath().getBytes("UTF-8");
372 while (entries.hasMoreElements())
374 JarEntry classfile = (JarEntry)entries.nextElement();
375 if (classfile.getName().endsWith(".class"))
377 InputStream str = jar.getInputStream(classfile);
378 int length = (int) classfile.getSize();
380 throw new EOFException();
382 byte[] data = new byte[length];
384 while (length - pos > 0)
386 int len = str.read(data, pos, length - pos);
388 throw new EOFException("Not enough data reading from: "
389 + classfile.getName());
392 b.put(md.digest(data), soFileName);
398 // Resize a map by creating a new one with the same data and
399 // renaming it. If close is true, close the original map.
401 static PersistentByteMap resizeMap(PersistentByteMap m, int newCapacity, boolean close)
402 throws IOException, IllegalAccessException
404 newCapacity = Math.max(m.capacity(), newCapacity);
405 File name = m.getFile();
406 File copy = File.createTempFile(name.getName(), "", name.getParentFile());
409 PersistentByteMap dest
410 = PersistentByteMap.emptyPersistentByteMap
411 (copy, newCapacity, newCapacity*32);
427 static String bytesToString(byte[] b)
429 StringBuffer hexBytes = new StringBuffer();
430 int length = b.length;
431 for (int i = 0; i < length; ++i)
435 hexBytes.append('0');
436 hexBytes.append(Integer.toHexString(v));
438 return hexBytes.toString();
442 // Return a Fileset, either from a String array or from System.in,
443 // depending on fileListFromStdin.
444 private static final Fileset getFiles(String[] s, int startPos,
445 boolean fileListFromStdin,
448 if (fileListFromStdin)
449 return new Fileset(System.in, separator);
451 return new Fileset(s, startPos, s.length);
455 // Parse a stream into tokens. The separator can be any char, and
456 // space is equivalent to any whitepace character.
460 final char separator;
462 Tokenizer(Reader r, char separator)
465 this.separator = separator;
468 boolean isSeparator(int c)
470 if (Character.isWhitespace(separator))
471 return Character.isWhitespace((char)c);
473 return c == separator;
476 // Parse a token from the input stream. Return the empty string
477 // when the stream is exhausted.
480 StringBuffer buf = new StringBuffer();
484 while ((c = r.read()) != -1)
486 if (! isSeparator(c))
492 while ((c = r.read()) != -1)
500 catch (java.io.IOException e)
503 return buf.toString();
507 // A Fileset is a container for a set of files; it can be created
508 // either from a string array or from an input stream, given a
509 // separator character.
512 LinkedHashSet files = new LinkedHashSet();
514 Fileset (String[] s, int start, int end)
516 for (int i = start; i < end; i++)
518 files.add(new File(s[i]));
522 Fileset (InputStream is, char separator)
524 Reader r = new BufferedReader(new InputStreamReader(is));
525 Tokenizer st = new Tokenizer(r, separator);
527 while (! "".equals(name = st.nextToken()))
528 files.add(new File(name));
533 return files.iterator();