1 /* Copyright (C) 2004, 2005, 2006 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
)
432 hexBytes
.append(Integer
.toHexString(b
[i
] & 0xff));
433 return hexBytes
.toString();
437 // Return a Fileset, either from a String array or from System.in,
438 // depending on fileListFromStdin.
439 private static final Fileset
getFiles(String
[] s
, int startPos
,
440 boolean fileListFromStdin
,
443 if (fileListFromStdin
)
444 return new Fileset(System
.in
, separator
);
446 return new Fileset(s
, startPos
, s
.length
);
450 // Parse a stream into tokens. The separator can be any char, and
451 // space is equivalent to any whitepace character.
455 final char separator
;
457 Tokenizer(Reader r
, char separator
)
460 this.separator
= separator
;
463 boolean isSeparator(int c
)
465 if (Character
.isWhitespace(separator
))
466 return Character
.isWhitespace((char)c
);
468 return c
== separator
;
471 // Parse a token from the input stream. Return the empty string
472 // when the stream is exhausted.
475 StringBuffer buf
= new StringBuffer();
479 while ((c
= r
.read()) != -1)
481 if (! isSeparator(c
))
487 while ((c
= r
.read()) != -1)
495 catch (java
.io
.IOException e
)
498 return buf
.toString();
502 // A Fileset is a container for a set of files; it can be created
503 // either from a string array or from an input stream, given a
504 // separator character.
507 LinkedHashSet files
= new LinkedHashSet();
509 Fileset (String
[] s
, int start
, int end
)
511 for (int i
= start
; i
< end
; i
++)
513 files
.add(new File(s
[i
]));
517 Fileset (InputStream is
, char separator
)
519 Reader r
= new BufferedReader(new InputStreamReader(is
));
520 Tokenizer st
= new Tokenizer(r
, separator
);
522 while (! "".equals(name
= st
.nextToken()))
523 files
.add(new File(name
));
528 return files
.iterator();