Kasse
This commit is contained in:
parent
5481ca8841
commit
25ef6542bc
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="src"/>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
|
||||
<classpathentry combineaccessrules="false" exported="true" kind="src" path="/SQLHelper"/>
|
||||
<classpathentry kind="lib" path="mysql-connector-java-5.1.37-bin.jar"/>
|
||||
<classpathentry kind="lib" path="miglayout15-swing.jar" sourcepath="miglayout-src.zip"/>
|
||||
<classpathentry combineaccessrules="false" kind="src" path="/jBCrypt"/>
|
||||
<classpathentry kind="output" path="bin"/>
|
||||
</classpath>
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>Sven Kasse Aktuell</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,11 @@
|
|||
eclipse.preferences.version=1
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
|
||||
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
|
||||
org.eclipse.jdt.core.compiler.debug.localVariable=generate
|
||||
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
|
||||
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||
org.eclipse.jdt.core.compiler.source=1.8
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,11 @@
|
|||
public class BorderInformation {
|
||||
// Randstärke in Pixeln
|
||||
public float BorderWidth;
|
||||
// Erstes schwarzes Pixel in der linken oberen Ecke
|
||||
public Pair firstBlackPixel;
|
||||
|
||||
public BorderInformation(float width, Pair firstBlack) {
|
||||
BorderWidth = width;
|
||||
firstBlackPixel = firstBlack;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
import java.sql.*;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
|
||||
public class Helper {
|
||||
|
||||
Connection con;
|
||||
Statement stmt;
|
||||
ResultSet rs;
|
||||
ResultSetMetaData rsmd;
|
||||
|
||||
//baut verbindung auf
|
||||
public void connect() {
|
||||
try {
|
||||
con = DriverManager.getConnection("jdbc:mysql://102-012/", "intabi19", "hallo");
|
||||
System.out.println("connected");
|
||||
} catch (SQLException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
//baut verbindung auf zur Auswahl
|
||||
public void connect(String databaseName) {
|
||||
try {
|
||||
con = DriverManager.getConnection("jdbc:mysql://102-012/"+ databaseName, "intabi19", "hallo");
|
||||
System.out.println("connected");
|
||||
} catch (SQLException e) {
|
||||
System.out.println(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void listTables()
|
||||
{
|
||||
try {
|
||||
rs = con.getMetaData().getTables(null, null, null, null);
|
||||
while (rs.next())
|
||||
{
|
||||
System.out.println(rs.getString(3));
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
public void passSQL(String sql)
|
||||
{
|
||||
try {
|
||||
stmt = con.createStatement();
|
||||
stmt.execute(sql);
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public DefaultTableModel getTableModel(String sqlString) {
|
||||
DefaultTableModel model = new DefaultTableModel();
|
||||
|
||||
try {
|
||||
// wichtig nicht vergessen ohne diese Aussage gibts nen Fehler(Nullpointer)
|
||||
stmt = con.createStatement();
|
||||
// schickt SQL Abfrage ab und speichert im Objekt rs
|
||||
rs = stmt.executeQuery(sqlString);
|
||||
// liest MetaDaten aus und speichert im Objekt rsmd
|
||||
rsmd = rs.getMetaData();
|
||||
// Breite der Tabelle
|
||||
int colCount = rsmd.getColumnCount();
|
||||
|
||||
// Ein String Array hat die Länge der Breite der Tabelle
|
||||
String colData[] = new String[colCount];
|
||||
// Läuft einmal die Breite ab und fügt die Spaltennamen zum Array hinzu
|
||||
for (int i = 1; i <= colCount; i++) {
|
||||
colData[i - 1] = rsmd.getColumnLabel(i);
|
||||
}
|
||||
// setzt die Spaltennamen im DefaultTableModel
|
||||
model.setColumnIdentifiers(colData);
|
||||
|
||||
// Ein String Array hat die Länge der Breite der Tabelle
|
||||
String rowData[] = new String[colCount];
|
||||
//Läuft solange es noch weitere Zeilen im rs gibt
|
||||
while (rs.next()) {
|
||||
// Läuft jede Spalte ab
|
||||
for (int i = 0; i < colCount; i++) {
|
||||
//trägt Werte der spalte in den Array ein überschreibt vorherige Werte
|
||||
rowData[i] = rs.getString(i+1);
|
||||
}
|
||||
// fügt komplette Zeile dem DefaultTableModel hinzu
|
||||
model.addRow(rowData);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
//gibt fertiges DefaultTableModel zurück
|
||||
return model;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,918 @@
|
|||
import java.awt.BorderLayout;
|
||||
import java.awt.EventQueue;
|
||||
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.border.EmptyBorder;
|
||||
import javax.swing.JMenuBar;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.DefaultListSelectionModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JComboBox;
|
||||
import javax.swing.JFileChooser;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JTextField;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.JLabel;
|
||||
import java.awt.Font;
|
||||
import java.awt.Label;
|
||||
|
||||
import javax.swing.JTextArea;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
|
||||
import javax.swing.JProgressBar;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JTabbedPane;
|
||||
import javax.swing.JTable;
|
||||
import javax.swing.border.LineBorder;
|
||||
import javax.swing.event.ListSelectionEvent;
|
||||
import javax.swing.event.ListSelectionListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import lib.SQLConnection;
|
||||
|
||||
import javax.swing.JPasswordField;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.awt.event.ComponentEvent;
|
||||
import java.awt.event.ComponentListener;
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.SwingConstants;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.sql.SQLException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.IsoFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.swing.event.CaretListener;
|
||||
import javax.swing.event.CaretEvent;
|
||||
import java.awt.GridBagLayout;
|
||||
import java.awt.GridBagConstraints;
|
||||
import net.miginfocom.swing.MigLayout;
|
||||
import javax.swing.JTextPane;
|
||||
|
||||
public class MainFrame extends JFrame {
|
||||
|
||||
private JPanel contentPane;
|
||||
private JTextField textField;
|
||||
private JTextField textField_1;
|
||||
private JTable table;
|
||||
private JTextField textField_2;
|
||||
private JTextField textField_3;
|
||||
private JPasswordField textField_4;
|
||||
private JTable table_2;
|
||||
private float Preis = 0.0F;
|
||||
DefaultTableModel model;
|
||||
JScrollPane scrollPane_1 = new JScrollPane();
|
||||
private JTextField txtProduktID;
|
||||
private JTextField txtProduktName;
|
||||
private JTextField txtPreis;
|
||||
JScrollPane scrollPane = new JScrollPane();
|
||||
|
||||
JTextArea textArea_AX = new JTextArea();
|
||||
JTextArea textArea_BX = new JTextArea();
|
||||
JTextArea textArea_CX = new JTextArea();
|
||||
JTextArea textArea_AY = new JTextArea();
|
||||
JTextArea textArea_BY = new JTextArea();
|
||||
JTextArea textArea_CY = new JTextArea();
|
||||
JTextArea textArea_AZ = new JTextArea();
|
||||
JTextArea textArea_BZ = new JTextArea();
|
||||
JTextArea textArea_CZ = new JTextArea();
|
||||
|
||||
JFrame _this = this;
|
||||
|
||||
/**
|
||||
* Launch the application.
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
EventQueue.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
MainFrame frame = new MainFrame();
|
||||
frame.setVisible(true);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the frame.
|
||||
*/
|
||||
public MainFrame() {
|
||||
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
setBounds(100, 100, 882, 623);
|
||||
contentPane = new JPanel();
|
||||
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
|
||||
setContentPane(contentPane);
|
||||
contentPane.setLayout(null);
|
||||
|
||||
SQLConnection db = new SQLConnection();
|
||||
|
||||
JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
|
||||
tabbedPane.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent arg0) {
|
||||
textArea_AX.setText("");
|
||||
textArea_BX.setText("");
|
||||
textArea_CX.setText("");
|
||||
textArea_AY.setText("");
|
||||
textArea_BY.setText("");
|
||||
textArea_CY.setText("");
|
||||
textArea_AZ.setText("");
|
||||
textArea_BZ.setText("");
|
||||
textArea_CZ.setText("");
|
||||
|
||||
if (tabbedPane.getSelectedIndex() != 2)
|
||||
return;
|
||||
|
||||
// ABC-Analyse ausführen
|
||||
SQLConnection db = new SQLConnection("102-012/sven");
|
||||
|
||||
|
||||
HashMap<Integer, Float> abcxyz = new HashMap<>();
|
||||
|
||||
ArrayList<HashMap<String, String>> produkte = db.queryToMap("SELECT ID FROM t_artikel");
|
||||
for (HashMap<String, String> produkt : produkte) {
|
||||
int produktID = Integer.parseInt(produkt.get("ID"));
|
||||
|
||||
Float verkauf = 0f;
|
||||
|
||||
ArrayList<HashMap<String, String>> verkaufswerte = db.queryToMap(
|
||||
"SELECT Menge, Verkaufspreis, Woche FROM t_statistik WHERE f_Artikel_ID = " + produktID);
|
||||
|
||||
for (HashMap<String, String> wert : verkaufswerte) {
|
||||
float summe = Integer.parseInt(wert.get("Menge")) * Float.parseFloat(wert.get("Verkaufspreis"));
|
||||
verkauf += summe;
|
||||
}
|
||||
|
||||
abcxyz.put(produktID, verkauf);
|
||||
}
|
||||
|
||||
//
|
||||
// Funtkion implementieren ids durch namern ersetzen
|
||||
//
|
||||
|
||||
ArrayList<Integer> sortiert = new ArrayList<>(abcxyz.keySet());
|
||||
sortiert.sort((a, b) -> Float.compare(abcxyz.get(b), abcxyz.get(a)));
|
||||
|
||||
// Gesamtumsatz errechnen
|
||||
float gesamtUmsatz = 0;
|
||||
|
||||
for (int i = 0; i < abcxyz.keySet().size(); i++) {
|
||||
gesamtUmsatz += abcxyz.get(abcxyz.keySet().toArray()[i]);
|
||||
}
|
||||
|
||||
System.out.println(gesamtUmsatz);
|
||||
|
||||
// Prozentualen Anteil für jedes Produkt ausrechnen
|
||||
HashMap<Integer, Float> prozentualerAnteil = new HashMap<>();
|
||||
|
||||
for (int i = 0; i < abcxyz.keySet().size(); i++) {
|
||||
Float ant = abcxyz.get(abcxyz.keySet().toArray()[i]).floatValue() / gesamtUmsatz;
|
||||
prozentualerAnteil.put((Integer) abcxyz.keySet().toArray()[i], ant);
|
||||
}
|
||||
|
||||
/*int AlleProdukte = 50;
|
||||
int[] VerkaufteMenge = new int[AlleProdukte];
|
||||
ArrayList<HashMap<String, String>> Verkaufte_Artikel;
|
||||
|
||||
/*for(int i = 0; i < Verkaufte_Artikel.size(); i++)
|
||||
{
|
||||
//VerkaufteMenge += Integer.parseInt(Verkaufte_Artikel.get(i).get("Menge"));
|
||||
}//
|
||||
|
||||
|
||||
int ProduktMenge = 0;
|
||||
float[] Verkauft_Durchschnitt = new float[AlleProdukte];
|
||||
|
||||
for(int i = 1; i < AlleProdukte; i++)
|
||||
{
|
||||
ArrayList<HashMap<String, String>> Artikel_sortiert = db.queryToMap("SELECT * FROM `t_statistik` WHERE `f_Artikel_ID` = " + i);
|
||||
if(Artikel_sortiert.size() > 0)
|
||||
{
|
||||
ProduktMenge++;
|
||||
}
|
||||
}
|
||||
|
||||
VerkaufteMenge / ProduktMenge;
|
||||
|
||||
*/
|
||||
|
||||
int wochen = 48;
|
||||
|
||||
HashMap<Integer, Double> Varianzkoeffizienten = new HashMap<>();
|
||||
|
||||
for (HashMap<String, String> produkt : produkte) {
|
||||
int produktID = Integer.parseInt(produkt.get("ID"));
|
||||
|
||||
ArrayList<HashMap<String, String>> verkauf = db.queryToMap("SELECT * FROM t_statistik WHERE f_Artikel_ID = " + produktID + " AND Woche <= 48");
|
||||
|
||||
double summeVerkaufteMenge = 0;
|
||||
|
||||
for (HashMap<String, String> elem : verkauf) {
|
||||
summeVerkaufteMenge += Double.parseDouble(elem.get("Menge"));
|
||||
}
|
||||
|
||||
double Erwartungswert = summeVerkaufteMenge / wochen;
|
||||
|
||||
double summeStichproben = 0;
|
||||
|
||||
for (HashMap<String, String> elem : verkauf) {
|
||||
double menge = Double.parseDouble(elem.get("Menge"));
|
||||
summeStichproben += Math.pow(menge - Erwartungswert, 2);
|
||||
}
|
||||
|
||||
double Standardabweichung = Math.sqrt(summeStichproben / wochen);
|
||||
|
||||
Varianzkoeffizienten.put(produktID, Standardabweichung / Erwartungswert);
|
||||
}
|
||||
|
||||
// Auswerten
|
||||
double valABC = 0;
|
||||
double valXYZ = 0;
|
||||
for (Integer produktID : prozentualerAnteil.keySet()) {
|
||||
|
||||
valABC += prozentualerAnteil.get(produktID);
|
||||
valXYZ = Varianzkoeffizienten.get(produktID);
|
||||
|
||||
String name = db.queryToMap("SELECT Name FROM t_artikel WHERE ID = " + produktID).get(0).get("Name");
|
||||
|
||||
if (valABC <= 0.8f) {
|
||||
if (valXYZ <= 0.5) {
|
||||
textArea_AX.append(name + "\n");
|
||||
} else if (valXYZ <= 1.1) {
|
||||
textArea_AY.append(name + "\n");
|
||||
} else {
|
||||
textArea_AZ.append(name + "\n");
|
||||
}
|
||||
} else if (valABC > 0.8f && valABC <= 0.9) {
|
||||
if (valXYZ <= 0.5) {
|
||||
textArea_BX.append(name + "\n");
|
||||
} else if (valXYZ <= 1.1) {
|
||||
textArea_BY.append(name + "\n");
|
||||
} else {
|
||||
textArea_BZ.append(name + "\n");
|
||||
}
|
||||
} else {
|
||||
if (valXYZ <= 0.5) {
|
||||
textArea_CX.append(name + "\n");
|
||||
} else if (valXYZ <= 1.1) {
|
||||
textArea_CY.append(name + "\n");
|
||||
} else {
|
||||
textArea_CZ.append(name + "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
tabbedPane.setBounds(10, 11, 846, 563);
|
||||
contentPane.add(tabbedPane);
|
||||
|
||||
String comboBoxWoche[] = { "Woche", "1", "2", "3", "4", };
|
||||
|
||||
String a = "Januar";
|
||||
String b = "Februar";
|
||||
String c = "März";
|
||||
String d = "April";
|
||||
String e = "Mai";
|
||||
String f = "Juni";
|
||||
String g = "Juli";
|
||||
String o = "August";
|
||||
String i = "September";
|
||||
String j = "Oktober";
|
||||
String k = "November";
|
||||
String l = "Dezember";
|
||||
|
||||
String comboBoxMonate[] = { "Monat", a, b, c, d, e, f, g, o, i, j, k, l, };
|
||||
Helper h = new Helper();
|
||||
h.connect("sven");
|
||||
|
||||
JPanel panel_1 = new JPanel();
|
||||
tabbedPane.addTab(" Anmelden / Abmelden ", null, panel_1, null);
|
||||
panel_1.setLayout(null);
|
||||
|
||||
JLabel lblBenutzername = new JLabel("Benutzername:");
|
||||
lblBenutzername.setBounds(123, 134, 93, 14);
|
||||
panel_1.add(lblBenutzername);
|
||||
|
||||
textField_1 = new JTextField();
|
||||
textField_1.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
|
||||
Helper g = new Helper();
|
||||
g.connect("sven");
|
||||
|
||||
String SQL = "SELECT Name FROM `t_benutzer` WHERE Name = '" + textField_1.getText() + "'";
|
||||
|
||||
DefaultTableModel model = g.getTableModel(SQL);
|
||||
if (model.getRowCount() == 1) {
|
||||
textField_4.setEnabled(true);
|
||||
}
|
||||
}
|
||||
});
|
||||
textField_1.setBounds(226, 131, 110, 20);
|
||||
panel_1.add(textField_1);
|
||||
textField_1.setColumns(10);
|
||||
|
||||
JLabel lblPasswort = new JLabel("Passwort:");
|
||||
lblPasswort.setBounds(149, 159, 67, 14);
|
||||
panel_1.add(lblPasswort);
|
||||
|
||||
JButton btnBesttigen = new JButton("Best\u00E4tigen");
|
||||
btnBesttigen.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
|
||||
Helper g = new Helper();
|
||||
g.connect("sven");
|
||||
String SQL = "SELECT Passwort FROM `t_benutzer` WHERE Name = '" + textField_1.getText() + "'";
|
||||
|
||||
DefaultTableModel model = g.getTableModel(SQL);
|
||||
if(model.getRowCount() == 1) {
|
||||
String hash = model.getValueAt(0, 0).toString();
|
||||
|
||||
// BCrypt Format Backport. Versionen Prefix Änderung
|
||||
if(hash.toCharArray()[2] == 'y') {
|
||||
char[] hashArray = hash.toCharArray();
|
||||
hashArray[2] = 'a';
|
||||
hash = String.valueOf(hashArray);
|
||||
}
|
||||
|
||||
// wenn der gehashte Wert in der Datenbank mit dem textArea_BX.append(prozentualerAnteil.get(prozentualerAnteil.keySet().toArray()[i]).toString() + "\n");
|
||||
|
||||
if(org.mindrot.BCrypt.checkpw(String.valueOf(textField_4.getPassword()), hash)) {
|
||||
tabbedPane.setVisible(true);
|
||||
|
||||
tabbedPane.setEnabledAt(1, true);
|
||||
tabbedPane.setEnabledAt(2, true);
|
||||
tabbedPane.setSelectedIndex(1);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
btnBesttigen.setBounds(123, 193, 213, 47);
|
||||
panel_1.add(btnBesttigen);
|
||||
|
||||
textField_4 = new JPasswordField();
|
||||
textField_4.setEnabled(false);
|
||||
textField_4.setColumns(10);
|
||||
textField_4.setBounds(226, 162, 110, 20);
|
||||
panel_1.add(textField_4);
|
||||
model = new DefaultTableModel();
|
||||
model.setColumnIdentifiers(new String[] { "ID", "Menge", "Preis", "SVEN Bon" });
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
tabbedPane.addTab(" Kasse ", null, panel, null);
|
||||
tabbedPane.setEnabledAt(1, false);
|
||||
|
||||
JLabel label = new JLabel("0,00\u20AC");
|
||||
label.setBounds(571, 38, 142, 14);
|
||||
panel.add(label);
|
||||
|
||||
JButton btnTotal = new JButton("Bezahlen");
|
||||
btnTotal.setBounds(525, 424, 188, 82);
|
||||
btnTotal.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
int rowCount = model.getRowCount();
|
||||
|
||||
String Woche = textField_3.getText();
|
||||
|
||||
if (Woche.isEmpty() == false) {
|
||||
|
||||
for (int r = 0; r < rowCount; r++) {
|
||||
String ProduktID = (String) model.getValueAt(r, 0);
|
||||
String Menge = (String) model.getValueAt(r, 1);
|
||||
String Einzelpreis = (String) model.getValueAt(r, 2);
|
||||
|
||||
db.execute("INSERT INTO t_statistik (`ID`, `f_Artikel_ID`, `Woche`, `Menge`, `Verkaufspreis`) VALUES (NULL, '" + ProduktID + "', '" + Woche + "', '" + Menge + "', '" + Einzelpreis + "')");
|
||||
}
|
||||
|
||||
textField_2.setText("");
|
||||
txtPreis.setText("");
|
||||
txtProduktID.setText("");
|
||||
txtProduktName.setText("");
|
||||
|
||||
model = new DefaultTableModel();
|
||||
model.setColumnIdentifiers(new String[] { "ID", "Menge", "Preis", "SVEN Bon" });
|
||||
table_2.setModel(model);
|
||||
label.setText("0,00 €");
|
||||
Preis = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
panel.setLayout(null);
|
||||
btnTotal.setFont(new Font("Tahoma", Font.PLAIN, 12));
|
||||
panel.add(btnTotal);
|
||||
|
||||
JButton button_1 = new JButton("3");
|
||||
button_1.setBounds(607, 372, 41, 41);
|
||||
button_1.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "3");
|
||||
}
|
||||
});
|
||||
|
||||
JButton button_2 = new JButton("6");
|
||||
button_2.setBounds(607, 332, 41, 41);
|
||||
button_2.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "6");
|
||||
}
|
||||
});
|
||||
panel.add(button_2);
|
||||
|
||||
JButton btnDel = new JButton("DEL");
|
||||
btnDel.setBounds(648, 291, 65, 41);
|
||||
btnDel.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
String text = textField_2.getText();
|
||||
textField_2.setText(text.substring(0, text.length() - 1));
|
||||
}
|
||||
});
|
||||
btnDel.setFont(new Font("Tahoma", Font.PLAIN, 12));
|
||||
btnDel.setForeground(Color.RED);
|
||||
panel.add(btnDel);
|
||||
|
||||
JButton button_3 = new JButton("9");
|
||||
button_3.setBounds(607, 292, 41, 41);
|
||||
button_3.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "9");
|
||||
}
|
||||
});
|
||||
panel.add(button_3);
|
||||
|
||||
JButton button_5 = new JButton("2");
|
||||
button_5.setBounds(566, 372, 41, 41);
|
||||
button_5.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "2");
|
||||
}
|
||||
});
|
||||
panel.add(button_5);
|
||||
|
||||
JButton button_6 = new JButton("5");
|
||||
button_6.setBounds(566, 332, 41, 41);
|
||||
button_6.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "5");
|
||||
}
|
||||
});
|
||||
panel.add(button_6);
|
||||
|
||||
JButton button_7 = new JButton("8");
|
||||
button_7.setBounds(566, 292, 41, 41);
|
||||
button_7.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "8");
|
||||
}
|
||||
});
|
||||
panel.add(button_7);
|
||||
|
||||
JButton button_8 = new JButton("0");
|
||||
button_8.setBounds(648, 372, 65, 41);
|
||||
button_8.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
textField_2.setText(textField_2.getText() + "0");
|
||||
}
|
||||
});
|
||||
panel.add(button_8);
|
||||
|
||||
JButton button_9 = new JButton("1");
|
||||
button_9.setBounds(525, 372, 41, 41);
|
||||
button_9.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "1");
|
||||
}
|
||||
});
|
||||
panel.add(button_9);
|
||||
|
||||
JButton button_10 = new JButton("4");
|
||||
button_10.setBounds(525, 332, 41, 41);
|
||||
button_10.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "4");
|
||||
}
|
||||
});
|
||||
panel.add(button_10);
|
||||
|
||||
JButton button_11 = new JButton("7");
|
||||
button_11.setBounds(525, 292, 41, 41);
|
||||
button_11.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText(textField_2.getText() + "7");
|
||||
}
|
||||
});
|
||||
panel.add(button_11);
|
||||
|
||||
JButton btnAbbruch = new JButton("Abbruch");
|
||||
btnAbbruch.setBounds(443, 291, 82, 41);
|
||||
btnAbbruch.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
textField_2.setText("");
|
||||
txtPreis.setText("");
|
||||
txtProduktID.setText("");
|
||||
txtProduktName.setText("");
|
||||
|
||||
model = new DefaultTableModel();
|
||||
model.setColumnIdentifiers(new String[] { "ID", "Menge", "Preis", "SVEN Bon" });
|
||||
table_2.setModel(model);
|
||||
label.setText("0,00 €");
|
||||
Preis = 0;
|
||||
}
|
||||
});
|
||||
btnAbbruch.setFont(new Font("Tahoma", Font.PLAIN, 12));
|
||||
panel.add(btnAbbruch);
|
||||
|
||||
textField = new JTextField();
|
||||
textField.addCaretListener(new CaretListener() {
|
||||
public void caretUpdate(CaretEvent arg0) {
|
||||
String Suchen = textField.getText();
|
||||
|
||||
if (Suchen.equals("")) {
|
||||
table = new JTable();
|
||||
Helper h = new Helper();
|
||||
h.connect("sven");
|
||||
table.setModel(h.getTableModel("SELECT ID, Name, Marke, Verkaufspreis FROM t_artikel"));
|
||||
scrollPane.setViewportView(table);
|
||||
|
||||
} else {
|
||||
table = new JTable();
|
||||
Helper g = new Helper();
|
||||
g.connect("sven");
|
||||
|
||||
String SQL = "SELECT ID, Name, Marke, Verkaufspreis FROM `t_artikel` WHERE Name LIKE '" + Suchen
|
||||
+ "%' ";
|
||||
|
||||
table.setModel(g.getTableModel(SQL));
|
||||
scrollPane.setViewportView(table);
|
||||
}
|
||||
|
||||
table.getColumnModel().getColumn(0).setPreferredWidth(25);
|
||||
|
||||
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
|
||||
@Override
|
||||
public void valueChanged(ListSelectionEvent e) {
|
||||
|
||||
if (e.getValueIsAdjusting() == false) {
|
||||
|
||||
txtProduktID.setText((String) table.getModel().getValueAt(table.getSelectedRow(), 0));
|
||||
|
||||
txtProduktName.setText((String) table.getModel().getValueAt(table.getSelectedRow(), 1));
|
||||
|
||||
float preis = Float.parseFloat((String) table.getModel().getValueAt(table.getSelectedRow(), 3));
|
||||
|
||||
txtPreis.setText(String.format("%.2f €", preis));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
textField.setBounds(10, 11, 423, 20);
|
||||
panel.add(textField);
|
||||
textField.setColumns(10);
|
||||
|
||||
JLabel lblBetrag = new JLabel("Betrag:");
|
||||
lblBetrag.setBounds(525, 38, 60, 14);
|
||||
panel.add(lblBetrag);
|
||||
|
||||
JComboBox Woche = new JComboBox(comboBoxWoche);
|
||||
Woche.setBounds(505, 11, 80, 20);
|
||||
panel.add(Woche);
|
||||
|
||||
JComboBox Monate = new JComboBox(comboBoxMonate);
|
||||
Monate.setBounds(583, 11, 133, 20);
|
||||
panel.add(Monate);
|
||||
|
||||
JButton btnKw = new JButton("KW");
|
||||
btnKw.setBounds(716, 11, 55, 20);
|
||||
btnKw.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
int p;
|
||||
String w = (String) Woche.getSelectedItem();
|
||||
p = Integer.valueOf(w);
|
||||
String m = (String) Monate.getSelectedItem();
|
||||
int n = 0;
|
||||
if (m.equals(a)) {
|
||||
n = 1;
|
||||
}
|
||||
if (m.equals(b)) {
|
||||
n = 2;
|
||||
}
|
||||
if (m.equals(c)) {
|
||||
n = 3;
|
||||
}
|
||||
if (m.equals(d)) {
|
||||
n = 4;
|
||||
}
|
||||
if (m.equals(e)) {
|
||||
n = 5;
|
||||
}
|
||||
if (m.equals(f)) {
|
||||
n = 6;
|
||||
}
|
||||
if (m.equals(g)) {
|
||||
n = 7;
|
||||
}
|
||||
if (m.equals(o)) {
|
||||
n = 8;
|
||||
}
|
||||
if (m.equals(i)) {
|
||||
n = 9;
|
||||
}
|
||||
if (m.equals(j)) {
|
||||
n = 10;
|
||||
}
|
||||
if (m.equals(k)) {
|
||||
n = 11;
|
||||
}
|
||||
if (m.equals(l)) {
|
||||
n = 12;
|
||||
}
|
||||
int k;
|
||||
k = (p + ((n - 1) * 4));
|
||||
String q;
|
||||
q = String.valueOf(k);
|
||||
textField_3.setText(q);
|
||||
}
|
||||
});
|
||||
panel.add(btnKw);
|
||||
|
||||
scrollPane.setBounds(10, 36, 423, 375);
|
||||
panel.add(scrollPane);
|
||||
|
||||
panel.add(button_1);
|
||||
|
||||
JButton btnEnter = new JButton("Enter");
|
||||
btnEnter.setBounds(648, 331, 65, 41);
|
||||
btnEnter.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
||||
int Menge = Integer.parseInt(textField_2.getText());
|
||||
|
||||
float Einzelpreis = Float.valueOf(txtPreis.getText().replace("€", "").replace(",", "."));
|
||||
|
||||
float Summe = Menge * Einzelpreis;
|
||||
|
||||
Preis += Summe;
|
||||
label.setText(String.format("%.2f €", Preis));
|
||||
|
||||
model.addRow(new String[] { txtProduktID.getText(), Menge + "", Einzelpreis + "", Summe + " €" });
|
||||
|
||||
textField_2.setText("");
|
||||
txtPreis.setText("");
|
||||
txtProduktID.setText("");
|
||||
txtProduktName.setText("");
|
||||
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
btnEnter.setFont(new Font("Tahoma", Font.PLAIN, 12));
|
||||
btnEnter.setForeground(Color.GREEN);
|
||||
panel.add(btnEnter);
|
||||
|
||||
scrollPane_1.setBounds(505, 51, 208, 193);
|
||||
panel.add(scrollPane_1);
|
||||
|
||||
table_2 = new JTable();
|
||||
table_2.setModel(model);
|
||||
table_2.getColumnModel().getColumn(0).setPreferredWidth(20);
|
||||
scrollPane_1.setViewportView(table_2);
|
||||
|
||||
JButton btnQrcodeScannen = new JButton("QR-Code");
|
||||
btnQrcodeScannen.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent arg0) {
|
||||
// JFileChooser erstellen
|
||||
JFileChooser fc = new JFileChooser();
|
||||
fc.setCurrentDirectory(new File("T:/INTABI19/Projekt/ELMO Interactive Toolbox/rec"));
|
||||
|
||||
// Wenn im Dialog nicht OK gedrückt wurde, Methode verlassen
|
||||
if (fc.showOpenDialog(_this) != JFileChooser.APPROVE_OPTION)
|
||||
return;
|
||||
|
||||
// Ausgewählte Datei auslesen
|
||||
File f = fc.getSelectedFile();
|
||||
|
||||
// Ausgelesener Wert
|
||||
int value = -1;
|
||||
|
||||
// Versuche, den QR-Code einzulesen
|
||||
// Wenn das nicht geht, wird eine Fehlermeldung ausgegeben
|
||||
try {
|
||||
value = SvenQR.ReadQR(f.getAbsolutePath());
|
||||
} catch (IOException e1) {
|
||||
JOptionPane.showMessageDialog(_this, "QR-Code konnte nicht eingelesen werden: " + e1.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
int Menge = 1;
|
||||
|
||||
Helper g = new Helper();
|
||||
g.connect("sven");
|
||||
String SQL = "SELECT Verkaufspreis FROM `t_artikel` WHERE QR = " + value;
|
||||
|
||||
DefaultTableModel _model = g.getTableModel(SQL);
|
||||
|
||||
if (_model.getRowCount() != 1) {
|
||||
JOptionPane.showMessageDialog(_this, "QR-Code konnte nicht zugeordnet werden.");
|
||||
return;
|
||||
}
|
||||
|
||||
float Einzelpreis = Float.valueOf(_model.getValueAt(0, 0).toString());
|
||||
float Summe = Menge * Einzelpreis;
|
||||
|
||||
Preis += Summe;
|
||||
label.setText(String.format("%.2f €", Preis));
|
||||
|
||||
model.addRow(new String[] { GetProductIDFromQRCode(value), Menge + "", Einzelpreis + "", Summe + " €" });
|
||||
}
|
||||
});
|
||||
btnQrcodeScannen.setBounds(443, 331, 82, 82);
|
||||
btnQrcodeScannen.setFont(new Font("Trebuchet MS", Font.PLAIN, 12));
|
||||
panel.add(btnQrcodeScannen);
|
||||
|
||||
textField_2 = new JTextField();
|
||||
textField_2.setBounds(505, 271, 103, 20);
|
||||
textField_2.setColumns(10);
|
||||
panel.add(textField_2);
|
||||
|
||||
textField_3 = new JTextField();
|
||||
textField_3.setBounds(771, 11, 60, 20);
|
||||
panel.add(textField_3);
|
||||
textField_3.setColumns(10);
|
||||
|
||||
txtProduktID = new JTextField();
|
||||
txtProduktID.setEditable(false);
|
||||
txtProduktID.setBounds(505, 248, 61, 20);
|
||||
panel.add(txtProduktID);
|
||||
txtProduktID.setColumns(10);
|
||||
|
||||
txtProduktName = new JTextField();
|
||||
txtProduktName.setEditable(false);
|
||||
txtProduktName.setBounds(566, 248, 147, 20);
|
||||
panel.add(txtProduktName);
|
||||
txtProduktName.setColumns(10);
|
||||
|
||||
txtPreis = new JTextField();
|
||||
txtPreis.setEditable(false);
|
||||
txtPreis.setBounds(607, 271, 106, 20);
|
||||
panel.add(txtPreis);
|
||||
txtPreis.setColumns(10);
|
||||
|
||||
textField.setText("4");
|
||||
textField.setText("");
|
||||
|
||||
JPanel panel_2 = new JPanel();
|
||||
tabbedPane.addTab(" ABC- / XYZ-Analyse ", null, panel_2, null);
|
||||
tabbedPane.setEnabledAt(2, false);
|
||||
panel_2.setLayout(new MigLayout("", "[][grow][grow][grow]", "[][grow][grow][grow]"));
|
||||
|
||||
JPanel panel_3 = new JPanel();
|
||||
panel_2.add(panel_3, "cell 1 0,grow");
|
||||
panel_3.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JLabel lblA = new JLabel("A");
|
||||
lblA.setFont(new Font("Tahoma", Font.BOLD, 18));
|
||||
lblA.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
panel_3.add(lblA, BorderLayout.CENTER);
|
||||
|
||||
JPanel panel_4 = new JPanel();
|
||||
panel_2.add(panel_4, "cell 2 0,grow");
|
||||
panel_4.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JLabel lblB = new JLabel("B");
|
||||
lblB.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
lblB.setFont(new Font("Tahoma", Font.BOLD, 18));
|
||||
panel_4.add(lblB, BorderLayout.CENTER);
|
||||
|
||||
JPanel panel_5 = new JPanel();
|
||||
panel_2.add(panel_5, "cell 3 0,grow");
|
||||
panel_5.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JLabel lblNewLabel = new JLabel("C");
|
||||
lblNewLabel.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
lblNewLabel.setFont(new Font("Tahoma", Font.BOLD, 18));
|
||||
panel_5.add(lblNewLabel, BorderLayout.CENTER);
|
||||
|
||||
JPanel panel_6 = new JPanel();
|
||||
panel_2.add(panel_6, "cell 0 1,grow");
|
||||
panel_6.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JLabel lblX = new JLabel("X");
|
||||
lblX.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
lblX.setFont(new Font("Tahoma", Font.BOLD, 18));
|
||||
panel_6.add(lblX, BorderLayout.CENTER);
|
||||
|
||||
JScrollPane scrollPane_2 = new JScrollPane();
|
||||
panel_2.add(scrollPane_2, "cell 1 1,grow");
|
||||
textArea_AX.setEditable(false);
|
||||
textArea_AX.setWrapStyleWord(true);
|
||||
scrollPane_2.setViewportView(textArea_AX);
|
||||
|
||||
JScrollPane scrollPane_3 = new JScrollPane();
|
||||
panel_2.add(scrollPane_3, "cell 2 1,grow");
|
||||
|
||||
|
||||
textArea_BX.setWrapStyleWord(true);
|
||||
textArea_BX.setEditable(false);
|
||||
scrollPane_3.setViewportView(textArea_BX);
|
||||
|
||||
JScrollPane scrollPane_4 = new JScrollPane();
|
||||
panel_2.add(scrollPane_4, "cell 3 1,grow");
|
||||
|
||||
|
||||
textArea_CX.setWrapStyleWord(true);
|
||||
textArea_CX.setEditable(false);
|
||||
scrollPane_4.setViewportView(textArea_CX);
|
||||
|
||||
JPanel panel_7 = new JPanel();
|
||||
panel_2.add(panel_7, "cell 0 2,grow");
|
||||
panel_7.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JLabel lblY = new JLabel("Y");
|
||||
lblY.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
lblY.setFont(new Font("Tahoma", Font.BOLD, 18));
|
||||
panel_7.add(lblY, BorderLayout.CENTER);
|
||||
|
||||
JScrollPane scrollPane_5 = new JScrollPane();
|
||||
panel_2.add(scrollPane_5, "cell 1 2,grow");
|
||||
|
||||
textArea_AY.setWrapStyleWord(true);
|
||||
textArea_AY.setEditable(false);
|
||||
scrollPane_5.setViewportView(textArea_AY);
|
||||
|
||||
JScrollPane scrollPane_6 = new JScrollPane();
|
||||
panel_2.add(scrollPane_6, "cell 2 2,grow");
|
||||
|
||||
textArea_BY.setWrapStyleWord(true);
|
||||
textArea_BY.setEditable(false);
|
||||
scrollPane_6.setViewportView(textArea_BY);
|
||||
|
||||
JScrollPane scrollPane_7 = new JScrollPane();
|
||||
panel_2.add(scrollPane_7, "cell 3 2,grow");
|
||||
|
||||
textArea_CY.setWrapStyleWord(true);
|
||||
textArea_CY.setEditable(false);
|
||||
scrollPane_7.setViewportView(textArea_CY);
|
||||
|
||||
JPanel panel_8 = new JPanel();
|
||||
panel_2.add(panel_8, "cell 0 3,grow");
|
||||
panel_8.setLayout(new BorderLayout(0, 0));
|
||||
|
||||
JLabel lblZ = new JLabel("Z");
|
||||
lblZ.setHorizontalAlignment(SwingConstants.CENTER);
|
||||
lblZ.setFont(new Font("Tahoma", Font.BOLD, 18));
|
||||
panel_8.add(lblZ, BorderLayout.CENTER);
|
||||
|
||||
JScrollPane scrollPane_8 = new JScrollPane();
|
||||
panel_2.add(scrollPane_8, "cell 1 3,grow");
|
||||
|
||||
textArea_AZ.setWrapStyleWord(true);
|
||||
textArea_AZ.setEditable(false);
|
||||
scrollPane_8.setViewportView(textArea_AZ);
|
||||
|
||||
JScrollPane scrollPane_9 = new JScrollPane();
|
||||
panel_2.add(scrollPane_9, "cell 2 3,grow");
|
||||
|
||||
textArea_BZ.setWrapStyleWord(true);
|
||||
textArea_BZ.setEditable(false);
|
||||
scrollPane_9.setViewportView(textArea_BZ);
|
||||
|
||||
JScrollPane scrollPane_10 = new JScrollPane();
|
||||
panel_2.add(scrollPane_10, "cell 3 3,grow");
|
||||
|
||||
textArea_CZ.setWrapStyleWord(true);
|
||||
textArea_CZ.setEditable(false);
|
||||
scrollPane_10.setViewportView(textArea_CZ);
|
||||
|
||||
}
|
||||
|
||||
private String GetProductIDFromQRCode(int value) {
|
||||
Helper g = new Helper();
|
||||
g.connect("sven");
|
||||
String SQL = "SELECT ID FROM `t_artikel` WHERE QR = " + value;
|
||||
|
||||
DefaultTableModel model = g.getTableModel(SQL);
|
||||
|
||||
if (model.getRowCount() != 1) {
|
||||
JOptionPane.showMessageDialog(_this, "QR-Code konnte nicht zugeordnet werden.");
|
||||
return "";
|
||||
}
|
||||
|
||||
return String.valueOf(model.getValueAt(0, 0));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
public class Pair {
|
||||
public int x, y;
|
||||
|
||||
public Pair(int _x, int _y) {
|
||||
x = _x;
|
||||
y = _y;
|
||||
}
|
||||
|
||||
// Kopierkonstruktor, da eine Zuweisung nicht die Werte kopiert,
|
||||
// sondern beide Variablen auf den gleichen Speicher zeigen lässt.
|
||||
public Pair(Pair copy) {
|
||||
x = copy.x;
|
||||
y = copy.y;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
import java.awt.Graphics;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.print.PageFormat;
|
||||
import java.awt.print.Printable;
|
||||
import java.awt.print.PrinterException;
|
||||
import java.awt.print.PrinterJob;
|
||||
|
||||
// Quelle: https://stackoverflow.com/questions/18404553/proper-way-of-printing-a-bufferedimage-in-java
|
||||
|
||||
public class PrintActionListener implements Runnable {
|
||||
|
||||
private BufferedImage image;
|
||||
|
||||
public PrintActionListener(BufferedImage image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
PrinterJob printJob = PrinterJob.getPrinterJob();
|
||||
printJob.setPrintable(new ImagePrintable(printJob, image));
|
||||
|
||||
if (printJob.printDialog()) {
|
||||
try {
|
||||
printJob.print();
|
||||
} catch (PrinterException prt) {
|
||||
prt.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ImagePrintable implements Printable {
|
||||
|
||||
private double x, y, width;
|
||||
|
||||
private int orientation;
|
||||
|
||||
private BufferedImage image;
|
||||
|
||||
public ImagePrintable(PrinterJob printJob, BufferedImage image) {
|
||||
PageFormat pageFormat = printJob.defaultPage();
|
||||
this.x = pageFormat.getImageableX();
|
||||
this.y = pageFormat.getImageableY();
|
||||
this.width = pageFormat.getImageableWidth();
|
||||
this.orientation = pageFormat.getOrientation();
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int print(Graphics g, PageFormat pageFormat, int pageIndex)
|
||||
throws PrinterException {
|
||||
if (pageIndex == 0) {
|
||||
int pWidth = 0;
|
||||
int pHeight = 0;
|
||||
if (orientation == PageFormat.PORTRAIT) {
|
||||
pWidth = (int) Math.min(width, (double) image.getWidth());
|
||||
pHeight = pWidth * image.getHeight() / image.getWidth();
|
||||
} else {
|
||||
pHeight = (int) Math.min(width, (double) image.getHeight());
|
||||
pWidth = pHeight * image.getWidth() / image.getHeight();
|
||||
}
|
||||
g.drawImage(image, (int) x, (int) y, pWidth, pHeight, null);
|
||||
return PAGE_EXISTS;
|
||||
} else {
|
||||
return NO_SUCH_PAGE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,484 @@
|
|||
import java.awt.*;
|
||||
import java.awt.image.*;
|
||||
import java.awt.print.PageFormat;
|
||||
import java.awt.print.Printable;
|
||||
import java.awt.print.PrinterException;
|
||||
import java.awt.print.PrinterJob;
|
||||
import java.io.*;
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
public class SvenQR {
|
||||
// Anzahl der Rechtecke horizontal
|
||||
public static final int AMNT_RECT_X = 4;
|
||||
// Anzahl der Rechtecke vertikal
|
||||
public static final int AMNT_RECT_Y = 3;
|
||||
// Rahmendicke in Pixeln
|
||||
public static final int BORDER_WIDTH = 8;
|
||||
// Rechteckgröße in Pixeln
|
||||
public static final int RECT_WIDTH = 40;
|
||||
|
||||
// Liest das angegebene Bild ein und wertet den QR-Code aus.
|
||||
public static int ReadQR(String fileName) throws IOException {
|
||||
// Quellbild
|
||||
BufferedImage img = ImageIO.read(new File(fileName));
|
||||
// Informationen über den Rand und die Ausmaße
|
||||
BorderInformation info;
|
||||
// Gemessene Größe des QR-Codes
|
||||
Pair measuredSize;
|
||||
// Wert des QR-Codes
|
||||
int value;
|
||||
|
||||
img = _IN_PrepareImage(img);
|
||||
|
||||
info = _IN_GetBorderWidth(img);
|
||||
|
||||
Pair imageSize = new Pair((int) img.getWidth(), (int) img.getHeight());
|
||||
measuredSize = _IN_GetMeasuredSize(img, info, imageSize);
|
||||
|
||||
// Durchschnittsgröße der Rechtecke
|
||||
int avgSquareWidth = (int) ((measuredSize.x - 4f * info.BorderWidth) / AMNT_RECT_X);
|
||||
int avgSquareHeight = (int) ((measuredSize.y - 4f * info.BorderWidth) / AMNT_RECT_Y);
|
||||
Pair avgSquareSize = new Pair(avgSquareWidth, avgSquareHeight);
|
||||
|
||||
value = _IN_HeuristicDetermination(img, info, avgSquareSize);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
public static BufferedImage GenerateQR(int value) {
|
||||
boolean[][] bits;
|
||||
BufferedImage img;
|
||||
|
||||
// Konvertiere die Zahl in eine Bit-Tabelle, die der QR-Code-Darstellung
|
||||
// entspricht
|
||||
bits = _OUT_GetBits(value);
|
||||
|
||||
// Generiere Bild
|
||||
img = _OUT_DrawImage(bits);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
public static BufferedImage _IN_PrepareImage(BufferedImage img) {
|
||||
// Bildgröße auslesen
|
||||
int width = img.getWidth();
|
||||
int height = img.getHeight();
|
||||
|
||||
//
|
||||
// = BILD ENTSÄTTIGEN UND KONTRAST SPREIZEN =
|
||||
//
|
||||
// Jedes Pixel durchgehen und in Graustufen umwandeln,
|
||||
// danach den Kontrast spreizen, sodass nur noch schwarze
|
||||
// und weiße Pixel im Bild sind, anders kann der Algorithmus
|
||||
// nicht arbeiten.
|
||||
//
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
|
||||
// Aktuelles Pixel auslesen
|
||||
int value = img.getRGB(x, y);
|
||||
Color c1 = new Color(value);
|
||||
|
||||
// Graustufe berechnen
|
||||
int grau = (c1.getBlue() + c1.getRed() + c1.getGreen()) / 3;
|
||||
|
||||
// Kontrast spreizen
|
||||
if (grau >= 127) {
|
||||
grau = 255;
|
||||
} else {
|
||||
grau = 0;
|
||||
}
|
||||
|
||||
// Pixel ersetzen
|
||||
Color c = new Color(grau, grau, grau);
|
||||
img.setRGB(x, y, c.getRGB());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File fx = new File("X:/ents.png"); // Speicherort
|
||||
ImageIO.write(img, "png", fx); // Bildformat
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error: " + e);
|
||||
}
|
||||
|
||||
//
|
||||
// = ALLEINSTEHENDE PIXEL IM BILD ENTFERNEN =
|
||||
//
|
||||
// Wenn das Bild fleckig ist, entstehen einzelne Pixel, die
|
||||
// den Algorithmus zum auslesen stören können, also werden
|
||||
// diese entfernt.
|
||||
//
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
for (int y = 0; y < height; y++) {
|
||||
boolean weissAussendrum = true;
|
||||
|
||||
// Rechts
|
||||
if (!(x < width - 1 && img.getRGB(x + 1, y) == -1))
|
||||
weissAussendrum = false;
|
||||
// Links
|
||||
if (!(x > 0 && img.getRGB(x - 1, y) == -1))
|
||||
weissAussendrum = false;
|
||||
// Drunter
|
||||
if (!(y < height - 1 && img.getRGB(x, y + 1) == -1))
|
||||
weissAussendrum = false;
|
||||
// Drüber
|
||||
if (!(y > 0 && img.getRGB(x, y - 1) == -1))
|
||||
weissAussendrum = false;
|
||||
|
||||
// Links oben
|
||||
if (!(x > 0 && y > 0 && img.getRGB(x - 1, y - 1) == - 1))
|
||||
weissAussendrum = false;
|
||||
// Links unten
|
||||
if (!(x > 0 && y < height - 1 && img.getRGB(x - 1, y + 1) == -1))
|
||||
weissAussendrum = false;
|
||||
// Rechts oben
|
||||
if (!(x < width - 1 && y > 0 && img.getRGB(x + 1, y - 1) == -1))
|
||||
weissAussendrum = false;
|
||||
// Rechts unten
|
||||
if (!(x < width - 1 && y < height - 1 && img.getRGB(x + 1, y + 1) == -1))
|
||||
weissAussendrum = false;
|
||||
|
||||
if (weissAussendrum)
|
||||
img.setRGB(x, y, -1 );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
File fx = new File("X:/prep2.png"); // Speicherort
|
||||
ImageIO.write(img, "png", fx); // Bildformat
|
||||
} catch (IOException e) {
|
||||
System.out.println("Error: " + e);
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
private static BorderInformation _IN_GetBorderWidth(BufferedImage img) {
|
||||
Color pixel;
|
||||
|
||||
// Informationen über den Rahmen des QR-Codes
|
||||
BorderInformation info = null;
|
||||
|
||||
// Breite des schwarzen Rahmens und Orientierungspunkte
|
||||
float borderWidth = -1f;
|
||||
Pair firstBlackPixel = new Pair(-1, -1);
|
||||
Pair firstWhitePixel;
|
||||
|
||||
//
|
||||
// = SUCHE DAS ERSTE SCHWARZE PIXEL IN DER LINKEN OBEREN ECKE =
|
||||
//
|
||||
|
||||
// Gehe diagonal durch das Bild auf der Suche nach schwarzen Pixeln
|
||||
while (!_IN_CompareColors(img.getRGB(firstBlackPixel.x + 1, firstBlackPixel.y + 1), Color.BLACK)) {
|
||||
firstBlackPixel.x++;
|
||||
firstBlackPixel.y++;
|
||||
}
|
||||
|
||||
firstBlackPixel.x++;
|
||||
firstBlackPixel.y++;
|
||||
|
||||
// Aufgrund von Ungenauigkeiten beim Drucken, gehen wir drei Pixel in den Rand rein
|
||||
firstBlackPixel.x += 2;
|
||||
|
||||
System.out.println("Suche schwarzes Pixel.");
|
||||
System.out.println("X: " + firstBlackPixel.x + " Y: " + firstBlackPixel.y + "\n");
|
||||
|
||||
|
||||
// Gehe so weit wie möglich nach oben
|
||||
while (firstBlackPixel.y > 0
|
||||
&& _IN_CompareColors(img.getRGB(firstBlackPixel.x, firstBlackPixel.y - 1), Color.BLACK))
|
||||
firstBlackPixel.y--;
|
||||
|
||||
System.out.println("Gehe so weit wie möglich nach oben");
|
||||
System.out.println("X: " + firstBlackPixel.x + " Y: " + firstBlackPixel.y + "\n");
|
||||
|
||||
// Gehe so weit wie möglich nach links
|
||||
while (firstBlackPixel.x > 0
|
||||
&& _IN_CompareColors(img.getRGB(firstBlackPixel.x - 1, firstBlackPixel.y), Color.BLACK))
|
||||
firstBlackPixel.x--;
|
||||
|
||||
System.out.println("Gehe so weit wie möglich nach links");
|
||||
System.out.println("X: " + firstBlackPixel.x + " Y: " + firstBlackPixel.y + "\n");
|
||||
|
||||
//
|
||||
// = SUCHE DAS ERSTE WEISSE PIXEL VOM INNEREN RAHMEN =
|
||||
//
|
||||
|
||||
firstWhitePixel = new Pair(firstBlackPixel);
|
||||
|
||||
// Gehe diagonal vom ersten schwarzen Pixel durch das Bild
|
||||
while (!_IN_CompareColors(img.getRGB(firstWhitePixel.x + 1, firstWhitePixel.y + 1), Color.WHITE)) {
|
||||
firstWhitePixel.x++;
|
||||
firstWhitePixel.y++;
|
||||
}
|
||||
|
||||
firstWhitePixel.x++;
|
||||
firstWhitePixel.y++;
|
||||
|
||||
System.out.println("Suche weißes Pixel");
|
||||
System.out.println("X: " + firstWhitePixel.x + " Y: " + firstWhitePixel.y + "\n");
|
||||
|
||||
// Gehe so weit wie möglich nach oben
|
||||
while (_IN_CompareColors(img.getRGB(firstWhitePixel.x, firstWhitePixel.y - 1), Color.WHITE))
|
||||
firstWhitePixel.y--;
|
||||
|
||||
System.out.println("Gehe soweit wie möglich nach oben");
|
||||
System.out.println("X: " + firstWhitePixel.x + " Y: " + firstWhitePixel.y + "\n");
|
||||
|
||||
// Gehe so weit wie möglich nach links
|
||||
while (_IN_CompareColors(img.getRGB(firstWhitePixel.x - 1, firstWhitePixel.y), Color.WHITE))
|
||||
firstWhitePixel.x--;
|
||||
|
||||
System.out.println("Gehe soweit wie möglich nach links");
|
||||
System.out.println("X: " + firstWhitePixel.x + " Y: " + firstWhitePixel.y + "\n");
|
||||
|
||||
// Differenzen, also Rahmenstärke ausrechnen
|
||||
int deltaX = firstWhitePixel.x - firstBlackPixel.x;
|
||||
int deltaY = firstWhitePixel.y - firstBlackPixel.y;
|
||||
|
||||
// Durchschnitt ermitteln
|
||||
borderWidth = (deltaX + deltaY) / 2f;
|
||||
|
||||
System.out.println("Border width: " + borderWidth);
|
||||
|
||||
info = new BorderInformation(borderWidth, firstBlackPixel);
|
||||
return info;
|
||||
}
|
||||
|
||||
private static Pair _IN_GetMeasuredSize(BufferedImage img, BorderInformation borderInfo, Pair imageSize) {
|
||||
Pair measuredSize;
|
||||
Pair upperRightBlackPixel, lowerLeftBlackPixel;
|
||||
Color pixel;
|
||||
|
||||
//
|
||||
// = MESSE DIE BREITE DES QR-CODES =
|
||||
//
|
||||
|
||||
upperRightBlackPixel = new Pair(borderInfo.firstBlackPixel);
|
||||
// Weil das Bild nicht immer gerade ist, messen wir in der Mitte des
|
||||
// schwarzen Rahmens
|
||||
upperRightBlackPixel.y += borderInfo.BorderWidth / 2f;
|
||||
|
||||
while (upperRightBlackPixel.x < imageSize.x - 1
|
||||
&& !_IN_CompareColors(img.getRGB(upperRightBlackPixel.x + 1, upperRightBlackPixel.y), Color.WHITE))
|
||||
upperRightBlackPixel.x++;
|
||||
|
||||
//
|
||||
// = MESSE DIE HÖHE DES QR-CODES =
|
||||
//
|
||||
|
||||
lowerLeftBlackPixel = new Pair(borderInfo.firstBlackPixel);
|
||||
// Immer mittig messen, kann bei arg schiefen Bildern jedoch auch wieder
|
||||
// zu fehlerhaften Ergebnissen führen
|
||||
// In solch einem Fall können wir nichts tun :/
|
||||
lowerLeftBlackPixel.x += borderInfo.BorderWidth / 2f;
|
||||
|
||||
while (lowerLeftBlackPixel.y < imageSize.y - 1
|
||||
&& !_IN_CompareColors(img.getRGB(upperRightBlackPixel.x, upperRightBlackPixel.y + 1), Color.WHITE))
|
||||
lowerLeftBlackPixel.y++;
|
||||
|
||||
// Errechne die Größe des QR-Codes aus den Differenzen der Punkte
|
||||
measuredSize = new Pair(upperRightBlackPixel.x - borderInfo.firstBlackPixel.x,
|
||||
lowerLeftBlackPixel.y - borderInfo.firstBlackPixel.y);
|
||||
measuredSize.x++;
|
||||
measuredSize.y++;
|
||||
|
||||
System.out.println("Gemessene Größe: " + measuredSize.x + " x " + measuredSize.y);
|
||||
|
||||
return measuredSize;
|
||||
}
|
||||
|
||||
private static int _IN_HeuristicDetermination(BufferedImage img, BorderInformation borderInfo, Pair avgSquareSize) {
|
||||
boolean[][] bits = new boolean[AMNT_RECT_X][AMNT_RECT_Y];
|
||||
float halfWidth = avgSquareSize.x / 2f, halfHeight = avgSquareSize.y / 2f;
|
||||
int c_value;
|
||||
|
||||
for (int x = 0; x < AMNT_RECT_X; x++) {
|
||||
for (int y = 0; y < AMNT_RECT_Y; y++) {
|
||||
|
||||
int _x = (int) (2 * borderInfo.BorderWidth);
|
||||
_x += (int) (x * avgSquareSize.x);
|
||||
_x += (int) halfWidth;
|
||||
_x += borderInfo.firstBlackPixel.x;
|
||||
|
||||
int _y = (int) (2 * borderInfo.BorderWidth);
|
||||
_y += (int) (y * avgSquareSize.y);
|
||||
_y += (int) halfHeight;
|
||||
_y += borderInfo.firstBlackPixel.y;
|
||||
|
||||
c_value = img.getRGB(_x, _y);
|
||||
System.out.println("X: " + _x + " Y: " + _y + " V: " + (_IN_CompareColors(c_value, Color.WHITE) ? false : true));
|
||||
|
||||
if (_IN_CompareColors(c_value, Color.WHITE))
|
||||
bits[x][y] = false;
|
||||
else if (_IN_CompareColors(c_value, Color.BLACK))
|
||||
bits[x][y] = true;
|
||||
}
|
||||
}
|
||||
|
||||
int value = 0;
|
||||
|
||||
if (bits[0][0])
|
||||
value += 1;
|
||||
if (bits[1][0])
|
||||
value += 2;
|
||||
if (bits[2][0])
|
||||
value += 4;
|
||||
if (bits[3][0])
|
||||
value += 8;
|
||||
|
||||
if (bits[0][1])
|
||||
value += 16;
|
||||
if (bits[1][1])
|
||||
value += 32;
|
||||
if (bits[2][1])
|
||||
value += 64;
|
||||
if (bits[3][1])
|
||||
value += 128;
|
||||
|
||||
if (bits[0][2])
|
||||
value += 256;
|
||||
if (bits[1][2])
|
||||
value += 512;
|
||||
if (bits[2][2])
|
||||
value += 1024;
|
||||
if (bits[3][2])
|
||||
value += 2048;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private static boolean _IN_CompareColors(int rgb, Color template) {
|
||||
Color c = new Color(rgb);
|
||||
if (c.getRed() != template.getRed())
|
||||
return false;
|
||||
if (c.getGreen() != template.getGreen())
|
||||
return false;
|
||||
if (c.getBlue() != template.getBlue())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean[][] _OUT_GetBits(int value) {
|
||||
// Die Bits in QR-Code-Darstellung
|
||||
boolean[][] bits = new boolean[AMNT_RECT_X][AMNT_RECT_Y];
|
||||
// Die Bits als Binärstring
|
||||
String bitsAsString = Integer.toBinaryString(value);
|
||||
// Anzahl an führenden Nullen für 12-Bit:
|
||||
int amntLeadingZeros = 12 - bitsAsString.length();
|
||||
|
||||
// Stelle führende Nullen voran
|
||||
for (int i = 0; i < amntLeadingZeros; i++)
|
||||
bitsAsString = "0" + bitsAsString;
|
||||
|
||||
bits[0][0] = bitsAsString.charAt(11) == '0' ? false : true;
|
||||
bits[1][0] = bitsAsString.charAt(10) == '0' ? false : true;
|
||||
bits[2][0] = bitsAsString.charAt(9) == '0' ? false : true;
|
||||
bits[3][0] = bitsAsString.charAt(8) == '0' ? false : true;
|
||||
bits[0][1] = bitsAsString.charAt(7) == '0' ? false : true;
|
||||
bits[1][1] = bitsAsString.charAt(6) == '0' ? false : true;
|
||||
bits[2][1] = bitsAsString.charAt(5) == '0' ? false : true;
|
||||
bits[3][1] = bitsAsString.charAt(4) == '0' ? false : true;
|
||||
bits[0][2] = bitsAsString.charAt(3) == '0' ? false : true;
|
||||
bits[1][2] = bitsAsString.charAt(2) == '0' ? false : true;
|
||||
bits[2][2] = bitsAsString.charAt(1) == '0' ? false : true;
|
||||
bits[3][2] = bitsAsString.charAt(0) == '0' ? false : true;
|
||||
|
||||
return bits;
|
||||
}
|
||||
|
||||
private static BufferedImage _OUT_DrawImage(boolean[][] bits) {
|
||||
// Bildgröße
|
||||
Pair imageSize;
|
||||
// Bild
|
||||
BufferedImage img;
|
||||
// Grafikobjekt zum zeichnen
|
||||
Graphics2D g;
|
||||
|
||||
// Bildbreite und -höhe berechnen
|
||||
// Bei 72 dpi entspricht 1mm 3px, wir nehmen 2px
|
||||
imageSize = new Pair(BORDER_WIDTH * 4 + AMNT_RECT_X * RECT_WIDTH, BORDER_WIDTH * 4 + AMNT_RECT_Y * RECT_WIDTH);
|
||||
|
||||
// Bild erstellen und Grafikobjekt erstellen
|
||||
img = new BufferedImage(imageSize.x, imageSize.y, BufferedImage.TYPE_INT_ARGB);
|
||||
g = img.createGraphics();
|
||||
|
||||
//
|
||||
// = QR-CODE-ZEICHEN =
|
||||
//
|
||||
|
||||
// Äußeren Rahmen zeichnen
|
||||
g.setColor(Color.BLACK);
|
||||
g.fillRect(0, 0, imageSize.x, imageSize.y);
|
||||
|
||||
// Inneren Rahmen zeichnen
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(BORDER_WIDTH, BORDER_WIDTH, imageSize.x - 2 * BORDER_WIDTH, imageSize.y - 2 * BORDER_WIDTH);
|
||||
|
||||
g.setColor(Color.BLACK);
|
||||
|
||||
// Rechtecke zeichnen
|
||||
for (int x = 0; x < AMNT_RECT_X; x++) {
|
||||
for (int y = 0; y < AMNT_RECT_Y; y++) {
|
||||
int _x = BORDER_WIDTH * 2 + x * RECT_WIDTH;
|
||||
int _y = BORDER_WIDTH * 2 + y * RECT_WIDTH;
|
||||
|
||||
if (!bits[x][y])
|
||||
continue;
|
||||
|
||||
g.fillRect(_x, _y, RECT_WIDTH, RECT_WIDTH);
|
||||
}
|
||||
}
|
||||
|
||||
// Rechte untere Ecke als Orientierungspunkt entfernen
|
||||
g.setColor(Color.WHITE);
|
||||
g.fillRect(imageSize.x - BORDER_WIDTH, imageSize.y - BORDER_WIDTH, BORDER_WIDTH, BORDER_WIDTH);
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
package lib;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* SQL helper to interact with the database
|
||||
*
|
||||
* @author Manuel
|
||||
*/
|
||||
public class SQLConnection {
|
||||
|
||||
Connection con;
|
||||
|
||||
public SQLConnection() {
|
||||
this("102-012/sven");
|
||||
}
|
||||
|
||||
public SQLConnection(String url) {
|
||||
this(url, "intabi19", "hallo");
|
||||
}
|
||||
|
||||
public SQLConnection(String url, String username, String password) {
|
||||
try {
|
||||
this.con = DriverManager.getConnection("jdbc:mysql://" + url, username, password);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a query without storing the return values
|
||||
*
|
||||
* @param sqlQuery SQL command to be executed
|
||||
*/
|
||||
public void execute(String sqlQuery) {
|
||||
try {
|
||||
System.out.println("SQL: " + sqlQuery);
|
||||
this.con.createStatement().execute(sqlQuery);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns table headers in a list from an existing meta data object
|
||||
*/
|
||||
private ArrayList<String> getColumnNames(ResultSetMetaData metaData) throws SQLException {
|
||||
int columns = metaData.getColumnCount();
|
||||
|
||||
ArrayList<String> columnTitles = new ArrayList<>();
|
||||
for (int i = 0; i < columns; i++) {
|
||||
columnTitles.add(metaData.getColumnLabel(i + 1));
|
||||
}
|
||||
|
||||
return columnTitles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the database return values into a usable format
|
||||
*
|
||||
* @param sqlQuery SQL command to be executed
|
||||
* @return a list of rows that are keyed by their column name
|
||||
*/
|
||||
public ArrayList<HashMap<String, String>> queryToMap(String sqlQuery) {
|
||||
ArrayList<HashMap<String, String>> data = new ArrayList<>();
|
||||
|
||||
//System.out.println("SQLq: " + sqlQuery);
|
||||
|
||||
try {
|
||||
ResultSet result = this.con.createStatement().executeQuery(sqlQuery);
|
||||
ResultSetMetaData metaData = result.getMetaData();
|
||||
|
||||
int columns = metaData.getColumnCount();
|
||||
|
||||
ArrayList<String> columnTitles = getColumnNames(metaData);
|
||||
|
||||
// iterate over all rows
|
||||
while (result.next()) {
|
||||
HashMap<String, String> row = new HashMap<>();
|
||||
for (int i = 0; i < columns; i++) {
|
||||
// copy items from table to row
|
||||
row.put(columnTitles.get(i), result.getString(i + 1));
|
||||
}
|
||||
data.add(row);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public ArrayList<ArrayList<String>> queryToArray(String sqlQuery) {
|
||||
ArrayList<ArrayList<String>> data = new ArrayList<>();
|
||||
|
||||
try {
|
||||
ResultSet result = this.con.createStatement().executeQuery(sqlQuery);
|
||||
ResultSetMetaData metaData = result.getMetaData();
|
||||
|
||||
int columns = metaData.getColumnCount();
|
||||
|
||||
// iterate over all rows
|
||||
while (result.next()) {
|
||||
ArrayList<String> row = new ArrayList<>();
|
||||
for (int i = 0; i < columns; i++) {
|
||||
// copy items from table to row
|
||||
row.add(result.getString(i + 1));
|
||||
}
|
||||
data.add(row);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the connection with the database
|
||||
*/
|
||||
public void close() {
|
||||
try {
|
||||
this.con.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,778 @@
|
|||
package org.mindrot;
|
||||
|
||||
// Copyright (c) 2006 Damien Miller <djm@mindrot.org>
|
||||
//
|
||||
// Permission to use, copy, modify, and distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import java.security.SecureRandom;
|
||||
|
||||
/**
|
||||
* BCrypt implements OpenBSD-style Blowfish password hashing using
|
||||
* the scheme described in "A Future-Adaptable Password Scheme" by
|
||||
* Niels Provos and David Mazieres.
|
||||
* <p>
|
||||
* This password hashing system tries to thwart off-line password
|
||||
* cracking using a computationally-intensive hashing algorithm,
|
||||
* based on Bruce Schneier's Blowfish cipher. The work factor of
|
||||
* the algorithm is parameterised, so it can be increased as
|
||||
* computers get faster.
|
||||
* <p>
|
||||
* Usage is really simple. To hash a password for the first time,
|
||||
* call the hashpw method with a random salt, like this:
|
||||
* <p>
|
||||
* <code>
|
||||
* String pw_hash = BCrypt.hashpw(plain_password, BCrypt.gensalt()); <br />
|
||||
* </code>
|
||||
* <p>
|
||||
* To check whether a plaintext password matches one that has been
|
||||
* hashed previously, use the checkpw method:
|
||||
* <p>
|
||||
* <code>
|
||||
* if (BCrypt.checkpw(candidate_password, stored_hash))<br />
|
||||
* System.out.println("It matches");<br />
|
||||
* else<br />
|
||||
* System.out.println("It does not match");<br />
|
||||
* </code>
|
||||
* <p>
|
||||
* The gensalt() method takes an optional parameter (log_rounds)
|
||||
* that determines the computational complexity of the hashing:
|
||||
* <p>
|
||||
* <code>
|
||||
* String strong_salt = BCrypt.gensalt(10)<br />
|
||||
* String stronger_salt = BCrypt.gensalt(12)<br />
|
||||
* </code>
|
||||
* <p>
|
||||
* The amount of work increases exponentially (2**log_rounds), so
|
||||
* each increment is twice as much work. The default log_rounds is
|
||||
* 10, and the valid range is 4 to 30.
|
||||
*
|
||||
* @author Damien Miller
|
||||
* @version 0.4
|
||||
*/
|
||||
public class BCrypt {
|
||||
// BCrypt parameters
|
||||
private static final int GENSALT_DEFAULT_LOG2_ROUNDS = 10;
|
||||
private static final int BCRYPT_SALT_LEN = 16;
|
||||
|
||||
// Blowfish parameters
|
||||
private static final int BLOWFISH_NUM_ROUNDS = 16;
|
||||
|
||||
// Initial contents of key schedule
|
||||
private static final int P_orig[] = {
|
||||
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344,
|
||||
0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
|
||||
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
|
||||
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
|
||||
0x9216d5d9, 0x8979fb1b
|
||||
};
|
||||
private static final int S_orig[] = {
|
||||
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7,
|
||||
0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
|
||||
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
|
||||
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
|
||||
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee,
|
||||
0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
|
||||
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef,
|
||||
0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
|
||||
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
|
||||
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
|
||||
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce,
|
||||
0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
|
||||
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e,
|
||||
0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
|
||||
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
|
||||
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
|
||||
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88,
|
||||
0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
|
||||
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e,
|
||||
0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
|
||||
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
|
||||
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
|
||||
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88,
|
||||
0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
|
||||
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6,
|
||||
0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
|
||||
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
|
||||
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
|
||||
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba,
|
||||
0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
|
||||
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f,
|
||||
0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
|
||||
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
|
||||
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
|
||||
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279,
|
||||
0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
|
||||
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab,
|
||||
0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
|
||||
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
|
||||
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
|
||||
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0,
|
||||
0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
|
||||
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790,
|
||||
0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
|
||||
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
|
||||
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
|
||||
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7,
|
||||
0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
|
||||
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad,
|
||||
0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
|
||||
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
|
||||
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
|
||||
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477,
|
||||
0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
|
||||
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49,
|
||||
0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
|
||||
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
|
||||
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
|
||||
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41,
|
||||
0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
|
||||
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400,
|
||||
0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
|
||||
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
|
||||
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
|
||||
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623,
|
||||
0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
|
||||
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
|
||||
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
|
||||
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6,
|
||||
0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
|
||||
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e,
|
||||
0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
|
||||
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
|
||||
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
|
||||
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff,
|
||||
0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
|
||||
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701,
|
||||
0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
|
||||
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
|
||||
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
|
||||
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf,
|
||||
0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
|
||||
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e,
|
||||
0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
|
||||
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
|
||||
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
|
||||
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16,
|
||||
0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
|
||||
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b,
|
||||
0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
|
||||
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
|
||||
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
|
||||
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f,
|
||||
0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
|
||||
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4,
|
||||
0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
|
||||
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
|
||||
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
|
||||
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802,
|
||||
0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
|
||||
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510,
|
||||
0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
|
||||
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
|
||||
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
|
||||
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50,
|
||||
0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
|
||||
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8,
|
||||
0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
|
||||
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
|
||||
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
|
||||
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128,
|
||||
0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
|
||||
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0,
|
||||
0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
|
||||
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
|
||||
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
|
||||
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3,
|
||||
0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
|
||||
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00,
|
||||
0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
|
||||
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
|
||||
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
|
||||
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735,
|
||||
0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
|
||||
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9,
|
||||
0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
|
||||
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
|
||||
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
|
||||
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934,
|
||||
0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
|
||||
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
|
||||
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
|
||||
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45,
|
||||
0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
|
||||
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a,
|
||||
0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
|
||||
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
|
||||
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
|
||||
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42,
|
||||
0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
|
||||
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2,
|
||||
0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
|
||||
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
|
||||
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
|
||||
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33,
|
||||
0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
|
||||
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3,
|
||||
0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
|
||||
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
|
||||
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
|
||||
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b,
|
||||
0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
|
||||
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922,
|
||||
0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
|
||||
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
|
||||
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
|
||||
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37,
|
||||
0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
|
||||
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804,
|
||||
0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
|
||||
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
|
||||
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
|
||||
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d,
|
||||
0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
|
||||
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350,
|
||||
0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
|
||||
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
|
||||
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
|
||||
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d,
|
||||
0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
|
||||
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f,
|
||||
0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
|
||||
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
|
||||
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
|
||||
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2,
|
||||
0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
|
||||
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e,
|
||||
0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
|
||||
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
|
||||
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
|
||||
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52,
|
||||
0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
|
||||
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5,
|
||||
0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
|
||||
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
|
||||
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
|
||||
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24,
|
||||
0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
|
||||
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4,
|
||||
0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
|
||||
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
|
||||
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
|
||||
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b,
|
||||
0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
|
||||
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
|
||||
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
|
||||
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8,
|
||||
0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
|
||||
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304,
|
||||
0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
|
||||
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
|
||||
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
|
||||
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9,
|
||||
0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
|
||||
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593,
|
||||
0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
|
||||
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
|
||||
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
|
||||
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b,
|
||||
0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
|
||||
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c,
|
||||
0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
|
||||
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
|
||||
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
|
||||
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb,
|
||||
0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
|
||||
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991,
|
||||
0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
|
||||
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
|
||||
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
|
||||
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae,
|
||||
0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
|
||||
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5,
|
||||
0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
|
||||
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
|
||||
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
|
||||
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84,
|
||||
0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
|
||||
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8,
|
||||
0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
|
||||
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
|
||||
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
|
||||
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38,
|
||||
0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
|
||||
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c,
|
||||
0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
|
||||
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
|
||||
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
|
||||
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964,
|
||||
0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
|
||||
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8,
|
||||
0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
|
||||
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
|
||||
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
|
||||
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02,
|
||||
0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
|
||||
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614,
|
||||
0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
|
||||
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
|
||||
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
|
||||
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0,
|
||||
0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
|
||||
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e,
|
||||
0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
|
||||
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
|
||||
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
|
||||
};
|
||||
|
||||
// bcrypt IV: "OrpheanBeholderScryDoubt". The C implementation calls
|
||||
// this "ciphertext", but it is really plaintext or an IV. We keep
|
||||
// the name to make code comparison easier.
|
||||
static private final int bf_crypt_ciphertext[] = {
|
||||
0x4f727068, 0x65616e42, 0x65686f6c,
|
||||
0x64657253, 0x63727944, 0x6f756274
|
||||
};
|
||||
|
||||
// Table for Base64 encoding
|
||||
static private final char base64_code[] = {
|
||||
'.', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
|
||||
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
|
||||
'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
|
||||
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
|
||||
'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
|
||||
'6', '7', '8', '9'
|
||||
};
|
||||
|
||||
// Table for Base64 decoding
|
||||
static private final byte index_64[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, 0, 1, 54, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63, -1, -1,
|
||||
-1, -1, -1, -1, -1, 2, 3, 4, 5, 6,
|
||||
7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
|
||||
-1, -1, -1, -1, -1, -1, 28, 29, 30,
|
||||
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
|
||||
41, 42, 43, 44, 45, 46, 47, 48, 49, 50,
|
||||
51, 52, 53, -1, -1, -1, -1, -1
|
||||
};
|
||||
|
||||
// Expanded Blowfish key
|
||||
private int P[];
|
||||
private int S[];
|
||||
|
||||
/**
|
||||
* Encode a byte array using bcrypt's slightly-modified base64
|
||||
* encoding scheme. Note that this is *not* compatible with
|
||||
* the standard MIME-base64 encoding.
|
||||
*
|
||||
* @param d the byte array to encode
|
||||
* @param len the number of bytes to encode
|
||||
* @return base64-encoded string
|
||||
* @exception IllegalArgumentException if the length is invalid
|
||||
*/
|
||||
private static String encode_base64(byte d[], int len)
|
||||
throws IllegalArgumentException {
|
||||
int off = 0;
|
||||
StringBuffer rs = new StringBuffer();
|
||||
int c1, c2;
|
||||
|
||||
if (len <= 0 || len > d.length)
|
||||
throw new IllegalArgumentException ("Invalid len");
|
||||
|
||||
while (off < len) {
|
||||
c1 = d[off++] & 0xff;
|
||||
rs.append(base64_code[(c1 >> 2) & 0x3f]);
|
||||
c1 = (c1 & 0x03) << 4;
|
||||
if (off >= len) {
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
break;
|
||||
}
|
||||
c2 = d[off++] & 0xff;
|
||||
c1 |= (c2 >> 4) & 0x0f;
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
c1 = (c2 & 0x0f) << 2;
|
||||
if (off >= len) {
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
break;
|
||||
}
|
||||
c2 = d[off++] & 0xff;
|
||||
c1 |= (c2 >> 6) & 0x03;
|
||||
rs.append(base64_code[c1 & 0x3f]);
|
||||
rs.append(base64_code[c2 & 0x3f]);
|
||||
}
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Look up the 3 bits base64-encoded by the specified character,
|
||||
* range-checking againt conversion table
|
||||
* @param x the base64-encoded value
|
||||
* @return the decoded value of x
|
||||
*/
|
||||
private static byte char64(char x) {
|
||||
if ((int)x < 0 || (int)x > index_64.length)
|
||||
return -1;
|
||||
return index_64[(int)x];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a string encoded using bcrypt's base64 scheme to a
|
||||
* byte array. Note that this is *not* compatible with
|
||||
* the standard MIME-base64 encoding.
|
||||
* @param s the string to decode
|
||||
* @param maxolen the maximum number of bytes to decode
|
||||
* @return an array containing the decoded bytes
|
||||
* @throws IllegalArgumentException if maxolen is invalid
|
||||
*/
|
||||
private static byte[] decode_base64(String s, int maxolen)
|
||||
throws IllegalArgumentException {
|
||||
StringBuffer rs = new StringBuffer();
|
||||
int off = 0, slen = s.length(), olen = 0;
|
||||
byte ret[];
|
||||
byte c1, c2, c3, c4, o;
|
||||
|
||||
if (maxolen <= 0)
|
||||
throw new IllegalArgumentException ("Invalid maxolen");
|
||||
|
||||
while (off < slen - 1 && olen < maxolen) {
|
||||
c1 = char64(s.charAt(off++));
|
||||
c2 = char64(s.charAt(off++));
|
||||
if (c1 == -1 || c2 == -1)
|
||||
break;
|
||||
o = (byte)(c1 << 2);
|
||||
o |= (c2 & 0x30) >> 4;
|
||||
rs.append((char)o);
|
||||
if (++olen >= maxolen || off >= slen)
|
||||
break;
|
||||
c3 = char64(s.charAt(off++));
|
||||
if (c3 == -1)
|
||||
break;
|
||||
o = (byte)((c2 & 0x0f) << 4);
|
||||
o |= (c3 & 0x3c) >> 2;
|
||||
rs.append((char)o);
|
||||
if (++olen >= maxolen || off >= slen)
|
||||
break;
|
||||
c4 = char64(s.charAt(off++));
|
||||
o = (byte)((c3 & 0x03) << 6);
|
||||
o |= c4;
|
||||
rs.append((char)o);
|
||||
++olen;
|
||||
}
|
||||
|
||||
ret = new byte[olen];
|
||||
for (off = 0; off < olen; off++)
|
||||
ret[off] = (byte)rs.charAt(off);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Blowfish encipher a single 64-bit block encoded as
|
||||
* two 32-bit halves
|
||||
* @param lr an array containing the two 32-bit half blocks
|
||||
* @param off the position in the array of the blocks
|
||||
*/
|
||||
private final void encipher(int lr[], int off) {
|
||||
int i, n, l = lr[off], r = lr[off + 1];
|
||||
|
||||
l ^= P[0];
|
||||
for (i = 0; i <= BLOWFISH_NUM_ROUNDS - 2;) {
|
||||
// Feistel substitution on left word
|
||||
n = S[(l >> 24) & 0xff];
|
||||
n += S[0x100 | ((l >> 16) & 0xff)];
|
||||
n ^= S[0x200 | ((l >> 8) & 0xff)];
|
||||
n += S[0x300 | (l & 0xff)];
|
||||
r ^= n ^ P[++i];
|
||||
|
||||
// Feistel substitution on right word
|
||||
n = S[(r >> 24) & 0xff];
|
||||
n += S[0x100 | ((r >> 16) & 0xff)];
|
||||
n ^= S[0x200 | ((r >> 8) & 0xff)];
|
||||
n += S[0x300 | (r & 0xff)];
|
||||
l ^= n ^ P[++i];
|
||||
}
|
||||
lr[off] = r ^ P[BLOWFISH_NUM_ROUNDS + 1];
|
||||
lr[off + 1] = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cycically extract a word of key material
|
||||
* @param data the string to extract the data from
|
||||
* @param offp a "pointer" (as a one-entry array) to the
|
||||
* current offset into data
|
||||
* @return the next word of material from data
|
||||
*/
|
||||
private static int streamtoword(byte data[], int offp[]) {
|
||||
int i;
|
||||
int word = 0;
|
||||
int off = offp[0];
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
word = (word << 8) | (data[off] & 0xff);
|
||||
off = (off + 1) % data.length;
|
||||
}
|
||||
|
||||
offp[0] = off;
|
||||
return word;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the Blowfish key schedule
|
||||
*/
|
||||
private void init_key() {
|
||||
P = (int[])P_orig.clone();
|
||||
S = (int[])S_orig.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Key the Blowfish cipher
|
||||
* @param key an array containing the key
|
||||
*/
|
||||
private void key(byte key[]) {
|
||||
int i;
|
||||
int koffp[] = { 0 };
|
||||
int lr[] = { 0, 0 };
|
||||
int plen = P.length, slen = S.length;
|
||||
|
||||
for (i = 0; i < plen; i++)
|
||||
P[i] = P[i] ^ streamtoword(key, koffp);
|
||||
|
||||
for (i = 0; i < plen; i += 2) {
|
||||
encipher(lr, 0);
|
||||
P[i] = lr[0];
|
||||
P[i + 1] = lr[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < slen; i += 2) {
|
||||
encipher(lr, 0);
|
||||
S[i] = lr[0];
|
||||
S[i + 1] = lr[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the "enhanced key schedule" step described by
|
||||
* Provos and Mazieres in "A Future-Adaptable Password Scheme"
|
||||
* http://www.openbsd.org/papers/bcrypt-paper.ps
|
||||
* @param data salt information
|
||||
* @param key password information
|
||||
*/
|
||||
private void ekskey(byte data[], byte key[]) {
|
||||
int i;
|
||||
int koffp[] = { 0 }, doffp[] = { 0 };
|
||||
int lr[] = { 0, 0 };
|
||||
int plen = P.length, slen = S.length;
|
||||
|
||||
for (i = 0; i < plen; i++)
|
||||
P[i] = P[i] ^ streamtoword(key, koffp);
|
||||
|
||||
for (i = 0; i < plen; i += 2) {
|
||||
lr[0] ^= streamtoword(data, doffp);
|
||||
lr[1] ^= streamtoword(data, doffp);
|
||||
encipher(lr, 0);
|
||||
P[i] = lr[0];
|
||||
P[i + 1] = lr[1];
|
||||
}
|
||||
|
||||
for (i = 0; i < slen; i += 2) {
|
||||
lr[0] ^= streamtoword(data, doffp);
|
||||
lr[1] ^= streamtoword(data, doffp);
|
||||
encipher(lr, 0);
|
||||
S[i] = lr[0];
|
||||
S[i + 1] = lr[1];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the central password hashing step in the
|
||||
* bcrypt scheme
|
||||
* @param password the password to hash
|
||||
* @param salt the binary salt to hash with the password
|
||||
* @param log_rounds the binary logarithm of the number
|
||||
* of rounds of hashing to apply
|
||||
* @param cdata the plaintext to encrypt
|
||||
* @return an array containing the binary hashed password
|
||||
*/
|
||||
public byte[] crypt_raw(byte password[], byte salt[], int log_rounds,
|
||||
int cdata[]) {
|
||||
int rounds, i, j;
|
||||
int clen = cdata.length;
|
||||
byte ret[];
|
||||
|
||||
if (log_rounds < 4 || log_rounds > 30)
|
||||
throw new IllegalArgumentException ("Bad number of rounds");
|
||||
rounds = 1 << log_rounds;
|
||||
if (salt.length != BCRYPT_SALT_LEN)
|
||||
throw new IllegalArgumentException ("Bad salt length");
|
||||
|
||||
init_key();
|
||||
ekskey(salt, password);
|
||||
for (i = 0; i != rounds; i++) {
|
||||
key(password);
|
||||
key(salt);
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
for (j = 0; j < (clen >> 1); j++)
|
||||
encipher(cdata, j << 1);
|
||||
}
|
||||
|
||||
ret = new byte[clen * 4];
|
||||
for (i = 0, j = 0; i < clen; i++) {
|
||||
ret[j++] = (byte)((cdata[i] >> 24) & 0xff);
|
||||
ret[j++] = (byte)((cdata[i] >> 16) & 0xff);
|
||||
ret[j++] = (byte)((cdata[i] >> 8) & 0xff);
|
||||
ret[j++] = (byte)(cdata[i] & 0xff);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash a password using the OpenBSD bcrypt scheme
|
||||
* @param password the password to hash
|
||||
* @param salt the salt to hash with (perhaps generated
|
||||
* using BCrypt.gensalt)
|
||||
* @return the hashed password
|
||||
*/
|
||||
public static String hashpw(String password, String salt) {
|
||||
BCrypt B;
|
||||
String real_salt;
|
||||
byte passwordb[], saltb[], hashed[];
|
||||
char minor = (char)0;
|
||||
int rounds, off = 0;
|
||||
StringBuffer rs = new StringBuffer();
|
||||
|
||||
if (salt.charAt(0) != '$' || salt.charAt(1) != '2')
|
||||
throw new IllegalArgumentException ("Invalid salt version");
|
||||
if (salt.charAt(2) == '$')
|
||||
off = 3;
|
||||
else {
|
||||
minor = salt.charAt(2);
|
||||
if (minor != 'a' || salt.charAt(3) != '$')
|
||||
throw new IllegalArgumentException ("Invalid salt revision");
|
||||
off = 4;
|
||||
}
|
||||
|
||||
// Extract number of rounds
|
||||
if (salt.charAt(off + 2) > '$')
|
||||
throw new IllegalArgumentException ("Missing salt rounds");
|
||||
rounds = Integer.parseInt(salt.substring(off, off + 2));
|
||||
|
||||
real_salt = salt.substring(off + 3, off + 25);
|
||||
try {
|
||||
passwordb = (password + (minor >= 'a' ? "\000" : "")).getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
throw new AssertionError("UTF-8 is not supported");
|
||||
}
|
||||
|
||||
saltb = decode_base64(real_salt, BCRYPT_SALT_LEN);
|
||||
|
||||
B = new BCrypt();
|
||||
hashed = B.crypt_raw(passwordb, saltb, rounds,
|
||||
(int[])bf_crypt_ciphertext.clone());
|
||||
|
||||
rs.append("$2");
|
||||
if (minor >= 'a')
|
||||
rs.append(minor);
|
||||
rs.append("$");
|
||||
if (rounds < 10)
|
||||
rs.append("0");
|
||||
if (rounds > 30) {
|
||||
throw new IllegalArgumentException(
|
||||
"rounds exceeds maximum (30)");
|
||||
}
|
||||
rs.append(Integer.toString(rounds));
|
||||
rs.append("$");
|
||||
rs.append(encode_base64(saltb, saltb.length));
|
||||
rs.append(encode_base64(hashed,
|
||||
bf_crypt_ciphertext.length * 4 - 1));
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method
|
||||
* @param log_rounds the log2 of the number of rounds of
|
||||
* hashing to apply - the work factor therefore increases as
|
||||
* 2**log_rounds.
|
||||
* @param random an instance of SecureRandom to use
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt(int log_rounds, SecureRandom random) {
|
||||
StringBuffer rs = new StringBuffer();
|
||||
byte rnd[] = new byte[BCRYPT_SALT_LEN];
|
||||
|
||||
random.nextBytes(rnd);
|
||||
|
||||
rs.append("$2a$");
|
||||
if (log_rounds < 10)
|
||||
rs.append("0");
|
||||
if (log_rounds > 30) {
|
||||
throw new IllegalArgumentException(
|
||||
"log_rounds exceeds maximum (30)");
|
||||
}
|
||||
rs.append(Integer.toString(log_rounds));
|
||||
rs.append("$");
|
||||
rs.append(encode_base64(rnd, rnd.length));
|
||||
return rs.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method
|
||||
* @param log_rounds the log2 of the number of rounds of
|
||||
* hashing to apply - the work factor therefore increases as
|
||||
* 2**log_rounds.
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt(int log_rounds) {
|
||||
return gensalt(log_rounds, new SecureRandom());
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a salt for use with the BCrypt.hashpw() method,
|
||||
* selecting a reasonable default for the number of hashing
|
||||
* rounds to apply
|
||||
* @return an encoded salt value
|
||||
*/
|
||||
public static String gensalt() {
|
||||
return gensalt(GENSALT_DEFAULT_LOG2_ROUNDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that a plaintext password matches a previously hashed
|
||||
* one
|
||||
* @param plaintext the plaintext password to verify
|
||||
* @param hashed the previously-hashed password
|
||||
* @return true if the passwords match, false otherwise
|
||||
*/
|
||||
public static boolean checkpw(String plaintext, String hashed) {
|
||||
byte hashed_bytes[];
|
||||
byte try_bytes[];
|
||||
try {
|
||||
String try_pw = hashpw(plaintext, hashed);
|
||||
hashed_bytes = hashed.getBytes("UTF-8");
|
||||
try_bytes = try_pw.getBytes("UTF-8");
|
||||
} catch (UnsupportedEncodingException uee) {
|
||||
return false;
|
||||
}
|
||||
if (hashed_bytes.length != try_bytes.length)
|
||||
return false;
|
||||
byte ret = 0;
|
||||
for (int i = 0; i < try_bytes.length; i++)
|
||||
ret |= hashed_bytes[i] ^ try_bytes[i];
|
||||
return ret == 0;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue