1 /* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010
2 Free Software Foundation
4 This file is part of libgcj.
6 This software is copyrighted work licensed under the terms of the
7 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
10 package gnu.gcj.tools.gcj_dbtool;
13 import gnu.gcj.runtime.PersistentByteMap;
15 import java.nio.channels.*;
17 import java.util.jar.*;
18 import java.security.MessageDigest;
22 static private boolean verbose = false;
24 public static void main (String[] s)
26 boolean fileListFromStdin = false;
27 char filenameSeparator = ' ';
29 insist (s.length >= 1);
31 if (s[0].equals("-") ||
34 if (s[0].equals("-0"))
35 filenameSeparator = (char)0;
36 fileListFromStdin = true;
37 String[] newArgs = new String[s.length - 1];
38 System.arraycopy(s, 1, newArgs, 0, s.length - 1);
42 if (s[0].equals("-v") || s[0].equals("--version"))
44 insist (s.length == 1);
45 System.out.println("gcj-dbtool ("
46 + System.getProperty("java.vm.name")
48 + System.getProperty("java.vm.version"));
50 System.out.println("Copyright 2010 Free Software Foundation, Inc.");
51 System.out.println("This is free software; see the source for copying conditions. There is NO");
52 System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.");
55 if (s[0].equals("--help"))
61 if (s[0].equals("-n"))
63 // Create a new database.
64 insist (s.length >= 2 && s.length <= 3);
70 capacity = Integer.parseInt(s[2]);
82 = PersistentByteMap.emptyPersistentByteMap(new File(s[1]),
83 capacity, capacity*32);
87 System.err.println ("error: could not create "
88 + s[1] + ": " + e.toString());
94 if (s[0].equals("-a") || s[0].equals("-f"))
96 // Add a jar file to a database, creating it if necessary.
97 // Copies the database, adds the jar file to the copy, and
98 // then renames the new database over the old.
101 insist (s.length == 4);
102 File database = new File(s[1]);
103 database = database.getAbsoluteFile();
104 File jar = new File(s[2]);
105 PersistentByteMap map;
106 if (database.isFile())
107 map = new PersistentByteMap(database,
108 PersistentByteMap.AccessMode.READ_ONLY);
110 map = PersistentByteMap.emptyPersistentByteMap(database,
112 File soFile = new File(s[3]);
113 if (! s[0].equals("-f") && ! soFile.isFile())
114 throw new IllegalArgumentException(s[3] + " is not a file");
115 map = addJar(jar, map, soFile);
119 System.err.println ("error: could not update " + s[1]
120 + ": " + e.toString());
126 if (s[0].equals("-t"))
131 insist (s.length == 2);
133 = new PersistentByteMap(new File(s[1]),
134 PersistentByteMap.AccessMode.READ_ONLY);
135 Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
137 while (iterator.hasNext())
139 PersistentByteMap.MapEntry entry
140 = (PersistentByteMap.MapEntry)iterator.next();
141 byte[] key = (byte[])entry.getKey();
142 byte[] value = (byte[])b.get(key);
143 if (! Arrays.equals (value, (byte[])entry.getValue()))
146 = ("Key " + bytesToString(key) + " at bucket "
147 + entry.getBucket());
149 throw new RuntimeException(err);
161 if (s[0].equals("-m"))
164 insist (s.length >= 3
165 || fileListFromStdin && s.length == 2);
168 File database = new File(s[1]);
169 database = database.getAbsoluteFile();
170 File temp = File.createTempFile(database.getName(), "",
171 database.getParentFile());
174 int newStringTableSize = 0;
175 Fileset files = getFiles(s, 2, fileListFromStdin,
177 PersistentByteMap[] sourceMaps
178 = new PersistentByteMap[files.size()];
180 // Scan all the input files, calculating worst case string
181 // table and hash table use.
183 Iterator it = files.iterator();
188 = new PersistentByteMap((File)it.next(),
189 PersistentByteMap.AccessMode.READ_ONLY);
191 newStringTableSize += b.stringTableSize();
196 newSize *= 1.5; // Scaling the new size by 1.5 results in
198 PersistentByteMap map
199 = PersistentByteMap.emptyPersistentByteMap
200 (temp, newSize, newStringTableSize);
202 for (int i = 0; i < sourceMaps.length; i++)
205 System.err.println("adding " + sourceMaps[i].size()
207 + sourceMaps[i].getFile());
208 map.putAll(sourceMaps[i]);
211 temp.renameTo(database);
221 if (s[0].equals("-l"))
224 insist (s.length == 2);
228 = new PersistentByteMap(new File(s[1]),
229 PersistentByteMap.AccessMode.READ_ONLY);
231 System.out.println ("Capacity: " + b.capacity());
232 System.out.println ("Size: " + b.size());
233 System.out.println ();
235 System.out.println ("Elements: ");
236 Iterator iterator = b.iterator(PersistentByteMap.ENTRIES);
238 while (iterator.hasNext())
240 PersistentByteMap.MapEntry entry
241 = (PersistentByteMap.MapEntry)iterator.next();
242 byte[] digest = (byte[])entry.getKey();
243 System.out.print ("[" + entry.getBucket() + "] "
244 + bytesToString(digest)
246 System.out.println (new String((byte[])entry.getValue()));
251 System.err.println ("error: could not list "
252 + s[1] + ": " + e.toString());
258 if (s[0].equals("-d"))
260 // For testing only: fill the byte map with random data.
261 insist (s.length == 2);
264 MessageDigest md = MessageDigest.getInstance("MD5");
266 = new PersistentByteMap(new File(s[1]),
267 PersistentByteMap.AccessMode.READ_WRITE);
268 int N = b.capacity();
269 byte[] bytes = new byte[1];
270 byte digest[] = md.digest(bytes);
271 for (int i = 0; i < N; i++)
273 digest = md.digest(digest);
274 b.put(digest, digest);
285 if (s[0].equals("-p"))
287 insist (s.length == 1 || s.length == 2);
291 result = System.getProperty("gnu.gcj.precompiled.db.path", "");
294 + (s[1].endsWith(File.separator) ? "" : File.separator)
297 System.out.println (result);
305 private static native String getDbPathTail ();
307 private static void insist(boolean ok)
316 private static void usage(PrintStream out)
319 ("gcj-dbtool: Manipulate gcj map database files\n"
322 + " gcj-dbtool -n file.gcjdb [size] - Create a new gcj map database\n"
323 + " gcj-dbtool -a file.gcjdb file.jar file.so\n"
324 + " - Add the contents of file.jar to a gcj map database\n"
325 + " gcj-dbtool -f file.gcjdb file.jar file.so\n"
326 + " - Add the contents of file.jar to a gcj map database\n"
327 + " gcj-dbtool -t file.gcjdb - Test a gcj map database\n"
328 + " gcj-dbtool -l file.gcjdb - List a gcj map database\n"
329 + " gcj-dbtool [-][-0] -m dest.gcjdb [source.gcjdb]...\n"
330 + " - Merge gcj map databases into dest\n"
332 + " To add to dest, include dest in the list of sources\n"
333 + " If the first arg is -, read the list from stdin\n"
334 + " If the first arg is -0, filenames separated by nul\n"
335 + " gcj-dbtool -p [LIBDIR] - Print default database name"
339 // Add a jar to a map. This copies the map first and returns a
340 // different map that contains the data. The original map is
343 private static PersistentByteMap
344 addJar(File f, PersistentByteMap b, File soFile)
347 MessageDigest md = MessageDigest.getInstance("MD5");
349 JarFile jar = new JarFile (f);
353 Enumeration entries = jar.entries();
354 while (entries.hasMoreElements())
356 JarEntry classfile = (JarEntry)entries.nextElement();
357 if (classfile.getName().endsWith(".class"))
363 System.err.println("adding " + count + " elements from "
364 + f + " to " + b.getFile());
366 // Maybe resize the destination map. We're allowing plenty of
367 // extra space by using a loadFactor of 2.
368 b = resizeMap(b, (b.size() + count) * 2, true);
370 Enumeration entries = jar.entries();
372 byte[] soFileName = soFile.getCanonicalPath().getBytes("UTF-8");
373 while (entries.hasMoreElements())
375 JarEntry classfile = (JarEntry)entries.nextElement();
376 if (classfile.getName().endsWith(".class"))
378 InputStream str = jar.getInputStream(classfile);
379 int length = (int) classfile.getSize();
381 throw new EOFException();
383 byte[] data = new byte[length];
385 while (length - pos > 0)
387 int len = str.read(data, pos, length - pos);
389 throw new EOFException("Not enough data reading from: "
390 + classfile.getName());
393 b.put(md.digest(data), soFileName);
399 // Resize a map by creating a new one with the same data and
400 // renaming it. If close is true, close the original map.
402 static PersistentByteMap resizeMap(PersistentByteMap m, int newCapacity, boolean close)
403 throws IOException, IllegalAccessException
405 newCapacity = Math.max(m.capacity(), newCapacity);
406 File name = m.getFile();
407 File copy = File.createTempFile(name.getName(), "", name.getParentFile());
410 PersistentByteMap dest
411 = PersistentByteMap.emptyPersistentByteMap
412 (copy, newCapacity, newCapacity*32);
428 static String bytesToString(byte[] b)
430 StringBuffer hexBytes = new StringBuffer();
431 int length = b.length;
432 for (int i = 0; i < length; ++i)
436 hexBytes.append('0');
437 hexBytes.append(Integer.toHexString(v));
439 return hexBytes.toString();
443 // Return a Fileset, either from a String array or from System.in,
444 // depending on fileListFromStdin.
445 private static final Fileset getFiles(String[] s, int startPos,
446 boolean fileListFromStdin,
449 if (fileListFromStdin)
450 return new Fileset(System.in, separator);
452 return new Fileset(s, startPos, s.length);
456 // Parse a stream into tokens. The separator can be any char, and
457 // space is equivalent to any whitepace character.
461 final char separator;
463 Tokenizer(Reader r, char separator)
466 this.separator = separator;
469 boolean isSeparator(int c)
471 if (Character.isWhitespace(separator))
472 return Character.isWhitespace((char)c);
474 return c == separator;
477 // Parse a token from the input stream. Return the empty string
478 // when the stream is exhausted.
481 StringBuffer buf = new StringBuffer();
485 while ((c = r.read()) != -1)
487 if (! isSeparator(c))
493 while ((c = r.read()) != -1)
501 catch (java.io.IOException e)
504 return buf.toString();
508 // A Fileset is a container for a set of files; it can be created
509 // either from a string array or from an input stream, given a
510 // separator character.
513 LinkedHashSet files = new LinkedHashSet();
515 Fileset (String[] s, int start, int end)
517 for (int i = start; i < end; i++)
519 files.add(new File(s[i]));
523 Fileset (InputStream is, char separator)
525 Reader r = new BufferedReader(new InputStreamReader(is));
526 Tokenizer st = new Tokenizer(r, separator);
528 while (! "".equals(name = st.nextToken()))
529 files.add(new File(name));
534 return files.iterator();