Source code: com/pepperview/romzinger/ROMZinger.java
1 /*
2 * ROMZinger.java -
3 * Copyright (C) 2000 Fabrice Armisen
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20 package com.pepperview.romzinger;
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.util.Date;
25 import java.util.Vector;
26 import java.util.Enumeration;
27 import java.util.StringTokenizer;
28 import java.util.Hashtable;
29 import java.util.zip.ZipException;
30
31 import com.pepperview.util.Util;
32
33 /**
34 * Description of the Class
35 *
36 * @author Default
37 * @created May 13, 2001
38 */
39
40 public class ROMZinger
41 {
42
43 private final static int DO_NOTHING = 0;
44 private final static int MOVE = 1;
45 private final static int DELETE = 2;
46 private final static int RENAME = 4;
47
48 private final static int REPAIR = 1;
49 private final static int IDENTIFY = 2;
50 private final static int LIST = 3;
51
52 private static int mode = DO_NOTHING;
53 private static boolean recurseFolders = true;
54 private static String badZipFolder = null;
55 private static String dupRomFolder = null;
56 private static String unmatchedFolder = null;
57 private static String romPath = null;
58 private static String backupFolder = null;
59 private static String datFiles = null;
60 private static String processedFolder = null;
61
62 private static int badZipAction = DO_NOTHING;
63 private static int unmatchedFileAction = DO_NOTHING;
64 private static int badNamedFileAction = DO_NOTHING;
65 private static int badRomAction = DO_NOTHING;
66 private static int duplicateAction = DO_NOTHING;
67
68
69
70 /**
71 * Description of the Method
72 *
73 * @param gameList Description of Parameter
74 * @param collection Description of Parameter
75 * @since
76 */
77 private static void doRepair( Vector gameList, GameSetCollection collection )
78 {
79 long t = 0;
80 long delta = 0;
81 File moveFolder = null;
82
83 // check duplicates
84
85 System.out.print( "Check duplicates " );
86 System.out.flush();
87 t = ( new Date() ).getTime();
88 moveFolder = null == dupRomFolder ? null : new File( dupRomFolder );
89 checkForDuplicates( gameList, collection, duplicateAction, moveFolder );
90 delta = ( new Date() ).getTime() - t;
91 System.out.println( " (" + delta + " ms)" );
92
93 // check files name
94
95 System.out.print( "Renaming files " );
96 System.out.flush();
97 t = ( new Date() ).getTime();
98 renameFiles( gameList, collection, badNamedFileAction, null );
99 delta = ( new Date() ).getTime() - t;
100 System.out.println( " (" + delta + " ms)" );
101
102 // check ROMs
103
104 System.out.print( "Checking ROMs " );
105 System.out.flush();
106 t = ( new Date() ).getTime();
107 checkROMs( gameList, collection, badRomAction, null );
108 delta = ( new Date() ).getTime() - t;
109 System.out.println( " (" + delta + " ms)" );
110
111 // Commit changes
112
113 System.out.print( "Commiting changes " );
114 System.out.flush();
115 t = ( new Date() ).getTime();
116 commit( gameList );
117 delta = ( new Date() ).getTime() - t;
118 System.out.println( " (" + delta + " ms)" );
119
120 // Move processed files
121
122 if ( null != processedFolder )
123 {
124 System.out.print( "Moving files " );
125 System.out.flush();
126 t = ( new Date() ).getTime();
127 moveProcessed( gameList );
128 delta = ( new Date() ).getTime() - t;
129 System.out.println( " (" + delta + " ms)" );
130 }
131 }
132
133
134 /**
135 * The main program for the ROMZinger class
136 *
137 * @param argv The command line arguments
138 * @since
139 */
140 public static void main( String[] argv )
141 {
142
143 parseArguments( argv );
144
145 long t = 0;
146 long delta = 0;
147
148 // load the game description data
149
150 GameSetCollection collection = new GameSetCollection();
151 StringTokenizer st = new StringTokenizer( datFiles, File.pathSeparator );
152 while ( st.hasMoreTokens() )
153 {
154 String datFile = st.nextToken();
155 System.out.print( "Loading GameSet desc " + datFile );
156 System.out.flush();
157 t = ( new Date() ).getTime();
158 GameSet set = new GameSet();
159 try
160 {
161 set.importData( datFile );
162 }
163 catch ( Exception e )
164 {
165 e.printStackTrace();
166 System.exit( 1 );
167 }
168 delta = ( new Date() ).getTime() - t;
169 System.out.println( " (" + delta + " ms)" );
170
171 collection.addGameSet( set );
172
173 }
174
175
176 // parse the games folders
177
178 Vector romPathList = new Vector();
179 st = new StringTokenizer( romPath, File.pathSeparator );
180 while ( st.hasMoreTokens() )
181 {
182 romPathList.add( st.nextToken() );
183 }
184
185 File moveFolder = null == badZipFolder ? null : new File( badZipFolder );
186 System.out.println( "Parsing ROM folders " );
187 t = ( new Date() ).getTime();
188 Vector gameList = new Vector();
189 for ( int p = 0; p < romPathList.size(); p++ )
190 {
191 String path = ( String ) romPathList.elementAt( p );
192
193 File folder = new File( path );
194 if ( !folder.isDirectory() )
195 {
196 System.out.println( path + " is not a folder !" );
197 continue;
198 }
199
200 processFolder( folder, gameList, recurseFolders, badZipAction, moveFolder );
201 }
202 delta = ( new Date() ).getTime() - t;
203 System.out.println( " (" + delta + " ms)" );
204
205 // sanitization
206
207 System.out.print( "Sanitizing files list" );
208 System.out.flush();
209 t = ( new Date() ).getTime();
210 sanitizeFilesList( gameList );
211 delta = ( new Date() ).getTime() - t;
212 System.out.println( " (" + delta + " ms)" );
213
214 // identify files
215
216 System.out.print( "Identifying files" );
217 System.out.flush();
218 t = ( new Date() ).getTime();
219 moveFolder = null == unmatchedFolder ? null : new File( unmatchedFolder );
220 identifyFiles( gameList, collection, unmatchedFileAction, moveFolder );
221 delta = ( new Date() ).getTime() - t;
222 System.out.println( " (" + delta + " ms)" );
223
224 switch ( mode )
225 {
226 case REPAIR:
227 doRepair( gameList, collection );
228 break;
229 }
230
231
232 }
233
234
235 /**
236 * Description of the Method
237 *
238 * @param folder Description of Parameter
239 * @param gameList Description of Parameter
240 * @param recurse Description of Parameter
241 * @param action Description of Parameter
242 * @param moveFolder Description of Parameter
243 * @since
244 */
245 private static void processFolder( File folder, Vector gameList, boolean recurse, int action, File moveFolder )
246 {
247 System.out.println( "\t" + folder );
248 File[] gameFiles = folder.listFiles();
249 for ( int f = 0; f < gameFiles.length; f++ )
250 {
251
252 try
253 {
254 try
255 {
256
257 if ( recurse && gameFiles[f].isDirectory() )
258 {
259 processFolder( gameFiles[f], gameList, recurse, action, moveFolder );
260 }
261
262 Game game = GameLoader.loadGameFile( gameFiles[f].getAbsolutePath() );
263 gameList.add( game );
264 }
265 catch ( ZipException ze )
266 {
267 System.out.println( gameFiles[f].getName() + " has a bad zip structure" );
268 if ( MOVE == action )
269 {
270 Util.moveFile( gameFiles[f], moveFolder );
271 }
272 else if ( DELETE == action )
273 {
274 gameFiles[f].delete();
275 }
276 }
277 }
278 catch ( IOException ioe )
279 {
280 System.out.println( ioe );
281 }
282 }
283 }
284
285
286 /**
287 * Description of the Method
288 *
289 * @param gameList Description of Parameter
290 * @param collection Description of Parameter
291 * @param action Description of Parameter
292 * @param moveFolder Description of Parameter
293 * @since
294 */
295 private static void identifyFiles( Vector gameList, GameSetCollection collection, int action, File moveFolder )
296 {
297 int matchedCnt = 0;
298 int unmatched = 0;
299 try
300 {
301 for ( int g = 0; g < gameList.size(); g++ )
302 {
303 Game game = ( Game ) gameList.elementAt( g );
304 GameDesc matched = collection.matchGame( game );
305
306 if ( null == matched )
307 {
308 unmatched++;
309 if ( MOVE == action )
310 {
311 Util.moveFile( game.getFile(), moveFolder );
312 gameList.remove( g-- );
313 }
314 else if ( DELETE == action )
315 {
316 game.getFile().delete();
317 gameList.remove( g-- );
318 }
319 }
320 else
321 {
322 matchedCnt++;
323 }
324 }
325 }
326 catch ( IOException ioe )
327 {
328 System.out.println( ioe );
329 }
330
331 int total = matchedCnt + unmatched;
332 System.out.print( " total=" + total + " matched=" + matchedCnt + " unmatched=" + unmatched );
333 System.out.flush();
334 }
335
336
337 /**
338 * Description of the Method
339 *
340 * @param gameList Description of Parameter
341 * @param collection Description of Parameter
342 * @param action Description of Parameter
343 * @param moveFolder Description of Parameter
344 * @since
345 */
346 private static void renameFiles( Vector gameList, GameSetCollection collection, int action, File moveFolder )
347 {
348 int badNamed = 0;
349 int renamed = 0;
350 for ( int g = 0; g < gameList.size(); g++ )
351 {
352 Game game = ( Game ) gameList.elementAt( g );
353 GameDesc matched = collection.matchGame( game );
354
355 if ( null == matched )
356 {
357 // unmatched file not removed previous step
358
359 continue;
360 }
361
362 if ( !matched.getName().equals( game.getName() ) )
363 {
364 badNamed++;
365 if ( RENAME == action )
366 {
367 game.renameTo( matched.getName() );
368 renamed++;
369 }
370 }
371 }
372 System.out.print( " badNamed=" + badNamed + " renamed=" + renamed );
373 System.out.flush();
374 }
375
376
377 /**
378 * Description of the Method
379 *
380 * @param gameList Description of Parameter
381 * @param collection Description of Parameter
382 * @param action Description of Parameter
383 * @param moveFolder Description of Parameter
384 * @since
385 */
386 private static void checkForDuplicates( Vector gameList, GameSetCollection collection, int action, File moveFolder )
387 {
388 int duplicates = 0;
389 int moved = 0;
390 int erased = 0;
391
392 Hashtable matchedGamesTable = new Hashtable();
393
394 for ( int g = 0; g < gameList.size(); g++ )
395 {
396 Game game = ( Game ) gameList.elementAt( g );
397
398 GameDesc matched = collection.matchGame( game );
399
400 if ( null == matched )
401 {
402 // unmatched file not removed previous step
403
404 continue;
405 }
406
407 GameDesc duplicate = ( GameDesc ) matchedGamesTable.get( matched );
408 if ( null == duplicate )
409 {
410 matchedGamesTable.put( matched, game );
411 }
412 else
413 {
414 duplicates++;
415 if ( MOVE == action )
416 {
417 try
418 {
419 Util.moveFile( game.getFile(), moveFolder );
420 moved++;
421 gameList.remove( g-- );
422 }
423 catch ( IOException ioe )
424 {
425 System.out.println( ioe );
426 }
427 }
428 else if ( DELETE == action )
429 {
430 erased++;
431 game.getFile().delete();
432 gameList.remove( g-- );
433 }
434 }
435 }
436 System.out.print( " Duplicates=" + duplicates + " moved=" + moved + " erased=" + erased );
437 System.out.flush();
438 }
439
440
441 /**
442 * Description of the Method
443 *
444 * @param gameList Description of Parameter
445 * @since
446 */
447 private static void sanitizeFilesList( Vector gameList )
448 {
449 for ( int g = gameList.size() - 1; g >= 0; g-- )
450 {
451 Game game = ( Game ) gameList.elementAt( g );
452
453 if ( null == game )
454 {
455 System.out.println( "[ISSUE] null game entry : " + g );
456 gameList.remove( g );
457 }
458 }
459 }
460
461
462 /**
463 * Description of the Method
464 *
465 * @param gameList Description of Parameter
466 * @param collection Description of Parameter
467 * @param action Description of Parameter
468 * @param moveFolder Description of Parameter
469 * @since
470 */
471 private static void checkROMs( Vector gameList, GameSetCollection collection, int action, File moveFolder )
472 {
473 int badNamed = 0;
474 int renamed = 0;
475 int useless = 0;
476 int erased = 0;
477
478 for ( int g = 0; g < gameList.size(); g++ )
479 {
480 Game game = ( Game ) gameList.elementAt( g );
481
482 GameDesc matchedGame = collection.matchGame( game );
483
484 if ( null == matchedGame )
485 {
486 // unmatched file not removed previous step
487
488 continue;
489 }
490
491 for ( Enumeration e = game.getROMs(); e.hasMoreElements(); )
492 {
493 ROM rom = ( ROM ) e.nextElement();
494 ROMDesc matchedRom = matchedGame.getROM( rom.getCrc() );
495
496 if ( null == matchedRom )
497 {
498 // not a rom (nfo file ?)
499
500 useless++;
501 if ( 0 != ( DELETE & action ) )
502 {
503 erased++;
504 rom.setUseless( true );
505 game.setModified( true );
506 }
507 continue;
508 }
509
510 if ( !matchedRom.getName().equals( rom.getName() ) )
511 {
512
513 badNamed++;
514 if ( 0 != ( RENAME & action ) )
515 {
516 renamed++;
517 rom.setName( matchedRom.getName() );
518 game.setModified( true );
519 }
520 }
521 }
522 }
523 System.out.print( "Bas named=" + badNamed + " renamed=" + renamed + " useless=" + useless + " erased=" + erased );
524 System.out.flush();
525 }
526
527
528 /**
529 * Description of the Method
530 *
531 * @param gameList Description of Parameter
532 * @since
533 */
534 private static void commit( Vector gameList )
535 {
536 for ( int g = 0; g < gameList.size(); g++ )
537 {
538 Game game = ( Game ) gameList.elementAt( g );
539 if ( game.isModified() )
540 {
541 try
542 {
543 game.saveModifications();
544 }
545 catch ( IOException ioe )
546 {
547 System.out.println( ioe );
548 }
549 }
550 }
551 }
552
553
554 /**
555 * Description of the Method
556 *
557 * @param gameList Description of Parameter
558 * @since
559 */
560 private static void moveProcessed( Vector gameList )
561 {
562 File dest = new File( processedFolder );
563
564 for ( int g = 0; g < gameList.size(); g++ )
565 {
566 Game game = ( Game ) gameList.elementAt( g );
567 if ( game.getToMove() )
568 {
569 try
570 {
571 Util.moveFile( game.getFile(), dest );
572 }
573 catch ( IOException ioe )
574 {
575 System.out.println( ioe );
576 }
577 }
578 }
579 }
580
581
582 /**
583 * Description of the Method
584 *
585 * @param argv Description of Parameter
586 * @since
587 */
588 private static void parseArguments( String argv[] )
589 {
590
591 if ( argv.length < 3 )
592 {
593 usage( null );
594 }
595
596 String modeStr = argv[0].toLowerCase();
597
598 if ( "-repair".equals( modeStr ) )
599 {
600 mode = REPAIR;
601 }
602 else
603 {
604 usage( null );
605 }
606
607 datFiles = argv[argv.length - 2];
608 romPath = argv[argv.length - 1];
609
610 String[] args = new String[argv.length - 3];
611 System.arraycopy( argv, 1, args, 0, argv.length - 3 );
612
613 int c = 0;
614 while ( c < args.length )
615 {
616 String arg = args[c++];
617
618 if ( arg.startsWith( "-" ) )
619 {
620 arg = arg.substring( 1 ).toLowerCase();
621 }
622 else
623 {
624 usage( null );
625 }
626
627 try
628 {
629 if ( "bzf".equals( arg ) )
630 {
631 badZipFolder = args[c++];
632 badZipAction |= MOVE;
633 continue;
634 }
635
636 if ( "dbz".equals( arg ) )
637 {
638 badZipAction |= DELETE;
639 continue;
640 }
641
642 if ( "drf".equals( arg ) )
643 {
644 duplicateAction |= MOVE;
645 dupRomFolder = args[c++];
646 continue;
647 }
648
649 if ( "ddr".equals( arg ) )
650 {
651 duplicateAction |= DELETE;
652 continue;
653 }
654
655 if ( "rf".equals( arg ) )
656 {
657 badNamedFileAction |= RENAME;
658 continue;
659 }
660
661 if ( "uff".equals( arg ) )
662 {
663 unmatchedFileAction |= MOVE;
664 unmatchedFolder = args[c++];
665 continue;
666 }
667
668 if ( "duf".equals( arg ) )
669 {
670 unmatchedFileAction |= DELETE;
671 continue;
672 }
673
674 if ( "bf".equals( arg ) )
675 {
676 backupFolder = args[c++];
677 continue;
678 }
679
680 if ( "pr".equals( arg ) )
681 {
682 processedFolder = args[c++];
683 continue;
684 }
685
686 if ( "rr".equals( arg ) )
687 {
688 badRomAction |= RENAME;
689 continue;
690 }
691
692 if ( "du".equals( arg ) )
693 {
694 badRomAction |= DELETE;
695 continue;
696 }
697
698
699 usage( "Bad parameter : " + arg );
700 }
701 catch ( Exception e )
702 {
703 usage( null );
704 }
705 }
706 }
707
708
709 /**
710 * Description of the Method
711 *
712 * @param str Description of Parameter
713 * @since
714 */
715 private static void usage( String str )
716 {
717 System.out.println( "java -jar romzinger.jar -repair [options] datfiles rompath" );
718 System.out.println( "where possible options are" );
719 System.out.println( "\t-bzf <folder> : move the bad zip files to that folder" );
720 System.out.println( "\t-dbz : delete the bad zip files" );
721 System.out.println( "\t-drf <folder> : move the duplicated games to that folder" );
722 System.out.println( "\t-ddr : delete the duplicated games" );
723 System.out.println( "\t-uff <folder> : move the unmatched files to that folder" );
724 System.out.println( "\t-duf : delete the unmatched files" );
725 System.out.println( "\t-bf <folder> : make backup copy in that folder before modification" );
726 System.out.println( "\t-pr <folder> : move the repaired games in that folder" );
727 System.out.println( "\t-rf : rename bad named games" );
728 System.out.println( "\t-rr : rename bad named ROMs" );
729 System.out.println( "\t-du : delete useless files in zipped games" );
730
731 System.exit( 1 );
732 }
733 }
734