/* PDDLC SLOT CHANGER v0.5
* Written by Suyo (ProjectDIVA.net)
*
* This program allows users to change the slots of decrypted DLC
* for Hatsune Miku: Project DIVA 2nd, Hatsune Miku: Project DIVA
* 2nd# and Hatsune Miku: Project DIVA extend.
*
* Currently supported: Songs, Modules, Wall Objects
*
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details. */
package net.projectdiva.slotchange;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.PlainDocument;
public class SlotChanger {
public static Map<Character,List<Object>> dlctypes = new HashMap<Character,List<Object>>();
public static char dlctype = '-';
public static int currentslot = 0;
public static String currentname = "";
public int chosenslot = 0;
public JFrame fenster;
public static int[] fileArray;
public static File ifile;
public JButton button1;
public JButton button2;
public JTextField text1;
public IntTextField text2;
public JTextField text3;
public JLabel label1;
public JLabel label2;
public JLabel label3;
public JLabel label4;
public JLabel label5;
public JLabel label6;
public JLabel label7;
public JLabel label8;
public SlotChanger() {
fenster = new JFrame("PD Slot Changer v0.5");
fenster.setSize(300,300);
fenster.setLocation(300,300);
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fenster.setLayout(null);
button1 = new JButton("Open DLC");
button2 = new JButton("Process!");
text1 = new JTextField();
text2 = new IntTextField(chosenslot,2);
text3 = new JTextField();
label1 = new JLabel();
label2 = new JLabel();
label3 = new JLabel();
label4 = new JLabel();
label5 = new JLabel();
label6 = new JLabel();
label7 = new JLabel();
label8 = new JLabel();
button1.setBounds(5,5,100,30);
button1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
final JFileChooser fc = new JFileChooser();
int returnVal = fc.showOpenDialog(fc);
if (returnVal == JFileChooser.APPROVE_OPTION) {
label8.setText("Loading... please wait!");
label8.setVisible(true);
fenster.paint(fenster.getGraphics());
ifile = fc.getSelectedFile();
if (readFile(ifile)) {
text1.setText(currentname);
text2.setValue(currentslot);
label4.setText("Current Slot: "+currentslot);
String printdlc = "unknown";
if (dlctypes.get(dlctype) != null) printdlc = (String) dlctypes.get(dlctype).get(0);
label5.setText("DLC Type: "+dlctype+" ("+printdlc+")");
label6.setText("DLC Size: "+ifile.length()+" bytes");
button2.setEnabled(true);
label8.setText("Done!");
} else {
button2.setEnabled(false);
label8.setText("There was an error...");
}
} else {
return;
}
}
});
button2.setBounds(187,5,100,30);
button2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
label8.setText("Processing... please wait!");
label8.setVisible(true);
fenster.paint(fenster.getGraphics());
if (changeSlot(text3.getText(),text2.getValue())) {
label8.setText("Done!");
} else {
label8.setText("There was an error...");
}
}
});
button2.setEnabled(false);
text1.setText(currentname);
text1.setBounds(105,60,182,25);
text2.setValue(currentslot);
text2.setBounds(105,110,182,25);
text2.getDocument().addDocumentListener(new DocumentListener() {
public void changedUpdate(DocumentEvent e) {
update();
}
public void removeUpdate(DocumentEvent e) {
update();
}
public void insertUpdate(DocumentEvent e) {
update();
}
public void update() {
String fileslot=text2.getText();
while (fileslot.length()<3) fileslot="0"+fileslot;
text3.setText(fileslot+".EDAT");
int slot = text2.getValue();
if (slot<1) {
label8.setText("WARNING: Slots < 1 will not work!");
label8.setVisible(true);
} else if (slot > Integer.parseInt(dlctypes.get(dlctype).get(4).toString())) {
label8.setText("WARNING: Slots > "+dlctypes.get(dlctype).get(4)+" will not work!");
label8.setVisible(true);
} else if (slot > Integer.parseInt(dlctypes.get(dlctype).get(5).toString())) {
label8.setText("WARNING: Slots > "+dlctypes.get(dlctype).get(5)+" will only work on 2nd!");
label8.setVisible(true);
} else label8.setVisible(false);
}
});
String fileslot=new Integer(currentslot).toString();
while (fileslot.length()<3) fileslot="0"+fileslot;
text3.setText(fileslot+".EDAT");
text3.setBounds(105,160,182,25);
label1.setText("Name:");
label1.setBounds(5,60,100,25);
label2.setText("(name changing coming soon)");
label2.setBounds(105,85,182,25);
label3.setText("Slot:");
label3.setBounds(5,110,100,25);
label4.setText("Current Slot: "+currentslot);
label4.setBounds(105,135,182,25);
label7.setText("Output as:");
label7.setBounds(5,160,100,25);
String printdlc = "unknown";
if (dlctypes.get(dlctype) != null) printdlc = (String) dlctypes.get(dlctype).get(0);
label5.setText("DLC Type: "+dlctype+" ("+printdlc+")");
label5.setBounds(5,222,282,25);
label6.setText("DLC Size: - bytes");
label6.setBounds(5,242,282,25);
label8.setText("WARNING:");
label8.setForeground(Color.red);
label8.setVisible(false);
label8.setBounds(5,200,282,25);
fenster.getContentPane().add(button1);
fenster.getContentPane().add(button2);
fenster.getContentPane().add(text1);
fenster.getContentPane().add(text2);
fenster.getContentPane().add(text3);
fenster.getContentPane().add(label1);
fenster.getContentPane().add(label2);
fenster.getContentPane().add(label3);
fenster.getContentPane().add(label4);
fenster.getContentPane().add(label5);
fenster.getContentPane().add(label6);
fenster.getContentPane().add(label7);
fenster.getContentPane().add(label8);
//fenster.pack();
fenster.setVisible(true);
}
/**
* @param args
*/
public static void main(String[] args) {
System.out.println("### PDDLC SLOT CHANGER v0.5");
System.out.println("Written by Suyo (ProjectDIVA.net)");
System.out.println("----------------------------------------");
System.out.println("Initializing Variables...");
// The offsets are actually not necessary, but it maybe be useful in the future.
List<Object> temp = new ArrayList<Object>();
temp.add("Song"); // DLC Type Name
temp.add(0x1800); // DLC Type Offset
temp.add(0x1803); // Slot Offset
temp.add(0x2000); // Name Offset
temp.add(25); // Max Slot 2nd
temp.add(25); // Max Slot extend
dlctypes.put('B',temp);
temp = new ArrayList<Object>();
temp.add("Module");
temp.add(0x1800);
temp.add(0x1803);
temp.add(0x2000);
temp.add(89);
temp.add(50);
dlctypes.put('C',temp);
temp = new ArrayList<Object>();
temp.add("Wall Object");
temp.add(0x1800);
temp.add(0x1803);
temp.add(0x2000);
temp.add(25);
temp.add(25);
dlctypes.put('H',temp);
System.out.println("\nInitializing GUI...");
SlotChanger s = new SlotChanger();
s.button1.getActionListeners()[0].actionPerformed(null);
}
public static boolean readFile(File ifile) {
FileInputStream fis;
if (!ifile.exists() || !ifile.isFile()) {
System.out.println(ifile.getName()+": does not exist!");
return false;
}
try {
System.out.println("Opening "+ifile.getName()+"...");
fis = new FileInputStream(ifile);
fileArray = new int[(int) ifile.length()];
int i=0;
int offs=0;
System.out.println("Reading file... this could take a while.");
while(i != -1) { /* -1 is a constant for 'EOF' : end of file. */
i=fis.read();
if (i!=-1) fileArray[offs] = i;
offs++;
}
fis.close();
} catch (Exception e) {
System.out.println(ifile.getName()+": Error while opening!");
e.printStackTrace();
return false;
}
int off;
dlctype='-';
for (Map.Entry<Character,List<Object>> entry : dlctypes.entrySet()) {
off = Integer.parseInt(entry.getValue().get(1).toString());
if ((char) fileArray[off] == entry.getKey()) {
dlctype = entry.getKey();
break;
}
}
if (dlctype=='-') {
System.out.println("Unknown DLC Type!");
return false;
}
off = Integer.parseInt(dlctypes.get(dlctype).get(2).toString());
currentslot = Integer.parseInt(""+((char) fileArray[off])+((char) fileArray[off+1])+((char) fileArray[off+2]));
currentname = "";
off = Integer.parseInt(dlctypes.get(dlctype).get(3).toString());
while (fileArray[off]!=0) {
currentname += (char) fileArray[off];
off++;
}
System.out.println("DLC Type: "+dlctype);
System.out.println("Current Slot: "+currentslot);
System.out.println("Current Name: "+currentname);
return true;
}
public static boolean changeSlot(String ofilen,int newslot) {
FileInputStream fis;
File ofile = new File(ofilen);
if (!ifile.exists() || !ifile.isFile()) {
System.out.println(ifile.getName()+": does not exist!");
return false;
}
if (ofile.exists()) {
System.out.println(ofilen+": exists already! Please rename it before running this!");
return false;
}
int[] fileArray;
try {
System.out.println("Opening "+ifile.getName()+"...");
fis = new FileInputStream(ifile);
fileArray = new int[(int) ifile.length()];
int i=0;
int offs=0;
System.out.println("Reading file... this could take a while.");
while(i != -1) { /* -1 is a constant for 'EOF' : end of file. */
i=fis.read();
if (i!=-1) fileArray[offs] = i;
offs++;
}
fis.close();
} catch (Exception e) {
System.out.println(ifile.getName()+": Error while opening!");
e.printStackTrace();
return false;
}
System.out.println("\nDLC Type: "+((char) fileArray[0x1800]));
System.out.println("Current Slot: "+((char) fileArray[0x1803])+((char) fileArray[0x1804])+((char) fileArray[0x1805]));
String newslots = ""+newslot;
while (newslots.length()<3) newslots = "0" + newslots;
fileArray[0x1803] = newslots.charAt(0);
fileArray[0x1804] = newslots.charAt(1);
fileArray[0x1805] = newslots.charAt(2);
try {
System.out.println("\nOpening "+ofilen+"...");
FileOutputStream fos = new FileOutputStream(ofile);
DataOutputStream dos = new DataOutputStream(fos);
System.out.println("Writing file... this could take a while.");
for (int i: fileArray) {
dos.writeByte(i);
}
dos.close();
} catch (Exception e) {
System.out.println(ofilen+": Error while writing!");
e.printStackTrace();
return false;
}
System.out.println("\nSuccess! We're done here.");
dlctype = (char) fileArray[0x1800];
currentslot = newslot;
return true;
}
}
class IntTextField extends JTextField {
/**
*
*/
private static final long serialVersionUID = 1L;
public IntTextField(int defval, int size) {
super("" + defval, size);
}
protected Document createDefaultModel() {
return new IntTextDocument();
}
public boolean isValid() {
try {
Integer.parseInt(getText());
return true;
} catch (Exception e) {
return false;
}
}
public int getValue() {
try {
return Integer.parseInt(getText());
} catch (NumberFormatException e) {
return 0;
}
}
public void setValue(int val) {
setText(Integer.toString(val));
}
class IntTextDocument extends PlainDocument {
/**
*
*/
private static final long serialVersionUID = 1L;
public void insertString(int offs, String str, AttributeSet a)
throws BadLocationException {
if (str == null)
return;
String oldString = getText(0, getLength());
String newString = oldString.substring(0, offs) + str
+ oldString.substring(offs);
try {
Integer.parseInt(newString + "0");
super.insertString(offs, str, a);
} catch (NumberFormatException e) {
}
}
}
}