Abstracted the HTTP server with TCP Network classes and added an SSDP service
This commit is contained in:
parent
b3ad292ff9
commit
45f514fc27
25 changed files with 1645 additions and 688 deletions
BIN
exemple.gif
Normal file
BIN
exemple.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 77 KiB |
|
|
@ -1,12 +1,16 @@
|
||||||
package zutil;
|
package zutil;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -19,8 +23,8 @@ public class FileFinder {
|
||||||
/**
|
/**
|
||||||
* Returns a String with a relative path from the given path
|
* Returns a String with a relative path from the given path
|
||||||
*
|
*
|
||||||
* @param file The file to get a relative path from
|
* @param file is the file to get a relative path from
|
||||||
* @param path The path
|
* @param path is the path
|
||||||
* @return A String with a relative path
|
* @return A String with a relative path
|
||||||
*/
|
*/
|
||||||
public static String relativePath(File file, String path){
|
public static String relativePath(File file, String path){
|
||||||
|
|
@ -36,11 +40,11 @@ public class FileFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the File object for the given file
|
* Returns the File object for the given file.
|
||||||
|
* Can not point to files in JAR files.
|
||||||
*
|
*
|
||||||
* @param path The path to the file (no / if not absolute path)
|
* @param path is the path to the file (no / if not absolute path)
|
||||||
* @return A File object for the file
|
* @return A File object for the file
|
||||||
* @throws URISyntaxException
|
|
||||||
*/
|
*/
|
||||||
public static File find(String path){
|
public static File find(String path){
|
||||||
try {
|
try {
|
||||||
|
|
@ -50,17 +54,46 @@ public class FileFinder {
|
||||||
}
|
}
|
||||||
return new File(findURL(path).toURI());
|
return new File(findURL(path).toURI());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
//e.printStackTrace(MultiPrintStream.out);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL to the given file
|
||||||
|
*
|
||||||
|
* @param path is the path to the file (no / if not absolute path)
|
||||||
|
* @return A URL object for the file
|
||||||
|
* @throws URISyntaxException
|
||||||
|
*/
|
||||||
|
public static URL findURL(String path){
|
||||||
|
return FileFinder.class.getClassLoader().getResource(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a InputStream from the path
|
||||||
|
*
|
||||||
|
* @param path is the path to the file (no / if not absolute path)
|
||||||
|
* @return A InputStream object for the file
|
||||||
|
*/
|
||||||
|
public static InputStream getInputStream(String path){
|
||||||
|
try {
|
||||||
|
File file = new File(path);
|
||||||
|
if(file!=null && file.exists()){
|
||||||
|
return new BufferedInputStream( new FileInputStream( file ) );
|
||||||
|
}
|
||||||
|
return FileFinder.class.getClassLoader().getResourceAsStream(path);
|
||||||
|
} catch (Exception e) {
|
||||||
|
//e.printStackTrace(MultiPrintStream.out);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads and returns the content of a file as a String.
|
* Reads and returns the content of a file as a String.
|
||||||
* Or use FileUtils.readFileToString(file);
|
* Or use FileUtils.readFileToString(file);
|
||||||
*
|
*
|
||||||
* @param file The file to read
|
* @param file is the file to read
|
||||||
* @return The file content
|
* @return The file content
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
|
|
@ -78,45 +111,35 @@ public class FileFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the URL to the given file
|
* Returns a ArrayList with all the files in a folder and sub folders
|
||||||
*
|
*
|
||||||
* @param path The path to the file (no / if not absolute path)
|
* @param dir is the directory to search in
|
||||||
* @return A URL object for the file
|
* @return The ArrayList with the files
|
||||||
* @throws URISyntaxException
|
|
||||||
*/
|
*/
|
||||||
public static URL findURL(String path){
|
public static List<File> search(File dir){
|
||||||
return FileFinder.class.getClassLoader().getResource(path);
|
return search(dir, new LinkedList<File>(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a ArrayList with all the files in a folder and sub folders
|
* Returns a ArrayList with all the files in a folder and sub folders
|
||||||
*
|
*
|
||||||
* @param dir The directory to search in
|
* @param dir is the directory to search in
|
||||||
|
* @param fileList is the ArrayList to add the files to
|
||||||
|
* @param recursice is if the method should search the sub directories to.
|
||||||
* @return The ArrayList with the files
|
* @return The ArrayList with the files
|
||||||
*/
|
*/
|
||||||
public static ArrayList<File> search(File dir){
|
public static List<File> search(File dir, List<File> fileList, boolean recursive){
|
||||||
return search(dir, new ArrayList<File>());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a ArrayList with all the files in a folder and sub folders
|
|
||||||
*
|
|
||||||
* @param dir The directory to search in
|
|
||||||
* @param fileList The ArrayList to add the files to
|
|
||||||
* @return The ArrayList with the files
|
|
||||||
*/
|
|
||||||
public static ArrayList<File> search(File dir, ArrayList<File> fileList){
|
|
||||||
String[] temp = dir.list();
|
String[] temp = dir.list();
|
||||||
File file;
|
File file;
|
||||||
|
|
||||||
if(temp != null){
|
if(temp != null){
|
||||||
for(int i=0; i<temp.length ;i++){
|
for(int i=0; i<temp.length ;i++){
|
||||||
file = new File(dir.getPath()+File.separator+temp[i]);
|
file = new File(dir.getPath()+File.separator+temp[i]);
|
||||||
if(file.isDirectory()){
|
if(recursive && file.isDirectory()){
|
||||||
search(new File(dir.getPath()+File.separator+temp[i]+File.separator),fileList);
|
search(new File(dir.getPath()+File.separator+temp[i]+File.separator), fileList, recursive);
|
||||||
}
|
}
|
||||||
else if(file.isFile()){
|
else if(file.isFile()){
|
||||||
MultiPrintStream.out.println("File Found: "+file);
|
//MultiPrintStream.out.println("File Found: "+file);
|
||||||
fileList.add(file);
|
fileList.add(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +150,8 @@ public class FileFinder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extension of the file
|
* Returns the extension of the file
|
||||||
* @param file The file
|
*
|
||||||
|
* @param file is the file
|
||||||
* @return The extension
|
* @return The extension
|
||||||
*/
|
*/
|
||||||
public static String fileExtension(File file){
|
public static String fileExtension(File file){
|
||||||
|
|
@ -136,7 +160,8 @@ public class FileFinder {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extension of the file
|
* Returns the extension of the file
|
||||||
* @param file The file
|
*
|
||||||
|
* @param file is the file
|
||||||
* @return The extension
|
* @return The extension
|
||||||
*/
|
*/
|
||||||
public static String fileExtension(String file){
|
public static String fileExtension(String file){
|
||||||
|
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
package zutil;
|
|
||||||
|
|
||||||
import java.util.LinkedList;
|
|
||||||
|
|
||||||
public class History<T> {
|
|
||||||
public int history_length = 10;
|
|
||||||
private LinkedList<T> history;
|
|
||||||
private int historyIndex = 0;
|
|
||||||
|
|
||||||
public History(int histlength){
|
|
||||||
history_length = histlength;
|
|
||||||
history = new LinkedList<T>();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addToHistory(T url){
|
|
||||||
while(historyIndex < history.size()-1){
|
|
||||||
history.removeLast();
|
|
||||||
}
|
|
||||||
history.addLast(url);
|
|
||||||
if(history_length < history.size()){
|
|
||||||
history.removeFirst();
|
|
||||||
}
|
|
||||||
|
|
||||||
historyIndex = history.size()-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getBackHistory(){
|
|
||||||
if(historyIndex > 0){
|
|
||||||
historyIndex -= 1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
historyIndex = 0;
|
|
||||||
}
|
|
||||||
return history.get(historyIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getForwHistory(){
|
|
||||||
if(forwHistoryExist()){
|
|
||||||
historyIndex += 1;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
historyIndex = history.size()-1;
|
|
||||||
}
|
|
||||||
return history.get(historyIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getCurrentHistory(){
|
|
||||||
return history.get(historyIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean forwHistoryExist(){
|
|
||||||
if(historyIndex < history.size()-1){
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -332,9 +332,11 @@ public class MultiPrintStream extends PrintStream {
|
||||||
for ( int i=0; i<fields.length; i++ ) {
|
for ( int i=0; i<fields.length; i++ ) {
|
||||||
fields[i].setAccessible( true );
|
fields[i].setAccessible( true );
|
||||||
buffer.append("\n");
|
buffer.append("\n");
|
||||||
buffer.append(head);
|
buffer.append(nextHead);
|
||||||
|
buffer.append( fields[i].getType().getSimpleName() );
|
||||||
|
buffer.append( " " );
|
||||||
buffer.append( fields[i].getName() );
|
buffer.append( fields[i].getName() );
|
||||||
buffer.append( "=" );
|
buffer.append( " = " );
|
||||||
try {
|
try {
|
||||||
Object value = fields[i].get(o);
|
Object value = fields[i].get(o);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
|
@ -357,11 +359,12 @@ public class MultiPrintStream extends PrintStream {
|
||||||
/**
|
/**
|
||||||
* An helper function for the dump function.
|
* An helper function for the dump function.
|
||||||
*/
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
private boolean dumbCapable(Object o){
|
private boolean dumbCapable(Object o){
|
||||||
if(o != null){
|
if(o != null){
|
||||||
if(o.getClass().isArray()) return true;
|
if(o.getClass().isArray()) return true;
|
||||||
else if(o instanceof Collection<?>)return true;
|
else if(o instanceof Collection)return true;
|
||||||
else if(o instanceof Map<?,?>)return true;
|
else if(o instanceof Map)return true;
|
||||||
else if(o instanceof InputStream)return true;
|
else if(o instanceof InputStream)return true;
|
||||||
else if(o instanceof Reader)return true;
|
else if(o instanceof Reader)return true;
|
||||||
else if(o instanceof Dumpable)return true;
|
else if(o instanceof Dumpable)return true;
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ public class MySQLConnection {
|
||||||
public MySQLConnection(String url, String db, String user, String password)
|
public MySQLConnection(String url, String db, String user, String password)
|
||||||
throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException{
|
throws SQLException, InstantiationException, IllegalAccessException, ClassNotFoundException{
|
||||||
Class.forName ("com.mysql.jdbc.Driver").newInstance();
|
Class.forName ("com.mysql.jdbc.Driver").newInstance();
|
||||||
|
DriverManager.setLoginTimeout(10);
|
||||||
conn = DriverManager.getConnection ("jdbc:mysql://"+url+"/"+db, user, password);
|
conn = DriverManager.getConnection ("jdbc:mysql://"+url+"/"+db, user, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,8 +49,11 @@ public class MySQLConnection {
|
||||||
Statement s = conn.createStatement ();
|
Statement s = conn.createStatement ();
|
||||||
s.executeQuery(sql);
|
s.executeQuery(sql);
|
||||||
ResultSet result = s.getResultSet();
|
ResultSet result = s.getResultSet();
|
||||||
if(result.next())
|
if(result.next()){
|
||||||
return result.getString(0);
|
String tmp = result.getString(1);
|
||||||
|
result.close();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,6 +70,22 @@ public class MySQLConnection {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the last inserted id or -1 if there was an error
|
||||||
|
* @throws SQLException
|
||||||
|
*/
|
||||||
|
public int getLastInsertID() throws SQLException{
|
||||||
|
Statement s = conn.createStatement ();
|
||||||
|
s.executeQuery("SELECT LAST_INSERT_ID()");
|
||||||
|
ResultSet result = s.getResultSet();
|
||||||
|
if(result.next()){
|
||||||
|
int tmp = result.getInt(1);
|
||||||
|
result.close();
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs a Prepared Statement.<br>
|
* Runs a Prepared Statement.<br>
|
||||||
* <b>NOTE:</b> Don't forget to close the PreparedStatement or it can lead to memory leak
|
* <b>NOTE:</b> Don't forget to close the PreparedStatement or it can lead to memory leak
|
||||||
|
|
|
||||||
|
|
@ -1,372 +1,48 @@
|
||||||
package zutil.image;
|
package zutil.image;
|
||||||
|
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.geom.AffineTransform;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some util methods for image processing
|
* This is a static class containing image utilities
|
||||||
|
*
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public class ImageUtil {
|
public class ImageUtil {
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the peek value in the image
|
|
||||||
*
|
|
||||||
* @param data The image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return The peak value of the image
|
|
||||||
*/
|
|
||||||
public static int getPeakValue(int[][][] data) {
|
|
||||||
return getPeakValue(data, 0, 0, data[0].length, data.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the peek value in the image
|
|
||||||
*
|
|
||||||
* @param data The image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return The peak value of the image
|
|
||||||
*/
|
|
||||||
public static int getPeakValue(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
|
||||||
int peak = 0;
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
if(data[y][x][1] > peak) peak = data[y][x][1];
|
|
||||||
if(data[y][x][2] > peak) peak = data[y][x][2];
|
|
||||||
if(data[y][x][3] > peak) peak = data[y][x][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return peak;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalizes the image data by the given scale
|
* Resizes an BufferedImage
|
||||||
*
|
*
|
||||||
* @param data The image data
|
* @param source is the image to resize
|
||||||
* @param startX is the x pixel of the image to start from
|
* @param width is the wanted width
|
||||||
* @param startY is the y pixel of the image to start from
|
* @param height is the wanted height
|
||||||
* @param stopX is the x pixel of the image to stop
|
* @param keep_aspect is if the aspect ratio of the image should be kept
|
||||||
* @param stopY is the y pixel of the image to stop
|
* @return the resized image
|
||||||
* @param scale The scale to normalize the image by
|
|
||||||
*/
|
*/
|
||||||
public static void normalize(int[][][] data, int startX, int startY, int stopX, int stopY, double scale) {
|
public static BufferedImage scale(BufferedImage source, int width, int height, boolean keep_aspect){
|
||||||
for(int y=startY; y<stopY ;y++){
|
double scale_width = (double)width / source.getWidth();
|
||||||
for(int x=startX; x<stopX ;x++){
|
double scale_height = (double)height / source.getHeight();
|
||||||
data[y][x][1] = (int)(data[y][x][1] * scale);
|
|
||||||
data[y][x][2] = (int)(data[y][x][2] * scale);
|
|
||||||
data[y][x][3] = (int)(data[y][x][3] * scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalizes the image data by the given scale
|
|
||||||
*
|
|
||||||
* @param output The output data array
|
|
||||||
* @param data The image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @param scale The scale to normalize the image by
|
|
||||||
*/
|
|
||||||
public static void normalize(int[][][] output, int[][][] data, int startX, int startY, int stopX, int stopY, double scale) {
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
output[y][x][1] = (int)(data[y][x][1] * scale);
|
|
||||||
output[y][x][2] = (int)(data[y][x][2] * scale);
|
|
||||||
output[y][x][3] = (int)(data[y][x][3] * scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// aspect calculation
|
||||||
* Returns the RMS value of the image
|
if(keep_aspect){
|
||||||
* (The RMS value is a measure of the width of the color distribution.)
|
if(scale_width * source.getHeight() > height){
|
||||||
*
|
scale_width = scale_height;
|
||||||
* @param data is the image data
|
}else{
|
||||||
* @param startX is the x pixel of the image to start from
|
scale_height = scale_width;
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return The RMS value for the image
|
|
||||||
*/
|
|
||||||
public static int getRMS(int[][][] data, int startX, int startY, int stopX, int stopY){
|
|
||||||
int pixelCount = 0;
|
|
||||||
long accum = 0;
|
|
||||||
for(int y=startY; y <stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
accum += data[y][x][1] * data[y][x][1];
|
|
||||||
accum += data[y][x][2] * data[y][x][2];
|
|
||||||
accum += data[y][x][3] * data[y][x][3];
|
|
||||||
pixelCount += 3;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int meanSquare = (int)(accum/pixelCount);
|
|
||||||
int rms = (int)(Math.sqrt(meanSquare));
|
|
||||||
return rms;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Multiplies the given image data by the given value
|
|
||||||
*
|
|
||||||
* @param data is the image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @param scale is the number to scale the image color by
|
|
||||||
*/
|
|
||||||
public static void scale(int[][][] data, int startX, int startY, int stopX, int stopY, double scale){
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
data[y][x][1] *= scale;
|
|
||||||
data[y][x][2] *= scale;
|
|
||||||
data[y][x][3] *= scale;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
BufferedImage tmp = new BufferedImage(
|
||||||
* Returns the mean value of the given image data
|
(int)(scale_width * source.getWidth()),
|
||||||
*
|
(int)(scale_height * source.getHeight()),
|
||||||
* @param data is the image data
|
BufferedImage.TYPE_INT_RGB);
|
||||||
* @return the mean value of the image
|
Graphics2D g2d = tmp.createGraphics();
|
||||||
*/
|
|
||||||
public static int getMeanValue(int[][][] data){
|
|
||||||
return getMeanValue(data, 0, 0, data[0].length, data.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the mean value of the given image data
|
|
||||||
*
|
|
||||||
* @param data is the image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return the mean value of the image
|
|
||||||
*/
|
|
||||||
public static int getMeanValue(int[][][] data, int startX, int startY, int stopX, int stopY){
|
|
||||||
int[] tmp = getMeanArray(data, startX, startY, stopX, stopY);
|
|
||||||
return (tmp[0] + tmp[1] + tmp[2])/3;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an mean array containing a mean value for each color
|
|
||||||
*
|
|
||||||
* @param data is the image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return the mean value of the image
|
|
||||||
*/
|
|
||||||
public static int[] getMeanArray(int[][][] data, int startX, int startY, int stopX, int stopY){
|
|
||||||
int mean[] = new int[3];
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
mean[0] += data[y][x][1];
|
|
||||||
mean[1] += data[y][x][2];
|
|
||||||
mean[2] += data[y][x][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// calculate the mean value
|
|
||||||
int pixelCount = (stopY-startY)*(stopX-startX);
|
|
||||||
mean[0] /= pixelCount;
|
|
||||||
mean[1] /= pixelCount;
|
|
||||||
mean[2] /= pixelCount;
|
|
||||||
|
|
||||||
return mean;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
AffineTransform at = AffineTransform.getScaleInstance(scale_width, scale_height);
|
||||||
* removes the mean value from the image data
|
g2d.drawRenderedImage(source, at);
|
||||||
*
|
g2d.dispose();
|
||||||
* @param data is the image data
|
return tmp;
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @param mean is the mean value
|
|
||||||
*/
|
|
||||||
public static void remMeanValue(int[][][] data, int startX, int startY, int stopX, int stopY, int mean){
|
|
||||||
addMeanValue(data, startX, startY, stopX, stopY, -mean);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the mean value to the image data
|
|
||||||
*
|
|
||||||
* @param data is the image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @param mean is the mean value
|
|
||||||
*/
|
|
||||||
public static void addMeanValue(int[][][] data, int startX, int startY, int stopX, int stopY, int mean){
|
|
||||||
addMeanArray(data, startX, startY, stopX, stopY, new int[]{mean, mean, mean});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* removes an mean array containing a mean value for each color
|
|
||||||
*
|
|
||||||
* @param data is the image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @param mean is an array of length 3 containing a mean value for each color RGB
|
|
||||||
*/
|
|
||||||
public static void remMeanArray(int[][][] data, int startX, int startY, int stopX, int stopY, int[] mean){
|
|
||||||
addMeanArray(data, startX, startY, stopX, stopY, new int[]{-mean[0], -mean[1], -mean[2]});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an mean array containing a mean value for each color
|
|
||||||
*
|
|
||||||
* @param data is the image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @param mean is an array of length 3 containing a mean value for each color RGB
|
|
||||||
*/
|
|
||||||
public static void addMeanArray(int[][][] data, int startX, int startY, int stopX, int stopY, int[] mean){
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
data[y][x][1] += mean[0];
|
|
||||||
data[y][x][2] += mean[1];
|
|
||||||
data[y][x][3] += mean[2];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies all the pixel data from the image to the new array
|
|
||||||
*
|
|
||||||
* @param data The data to copy
|
|
||||||
* @param xStart X start position on the source
|
|
||||||
* @param yStart Y start position on the source
|
|
||||||
* @param width The amount of pixels to copy
|
|
||||||
* @param hight The amount of pixels to copy
|
|
||||||
* @return A copy of the data array
|
|
||||||
*/
|
|
||||||
public static int[][][] crop(int[][][] data, int xStart, int yStart, int width, int hight){
|
|
||||||
return crop(data, xStart, yStart, null, 0, 0, width, hight);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies all the pixel data from the image to the new array
|
|
||||||
*
|
|
||||||
* @param data The data to copy
|
|
||||||
* @param xData X start position in the source
|
|
||||||
* @param yData Y start position in the source
|
|
||||||
* @param crop The destination
|
|
||||||
* @param xCrop X start position in the destination
|
|
||||||
* @param yCrop Y start position in the destination
|
|
||||||
* @param width The amount of pixels to copy
|
|
||||||
* @param hight The amount of pixels to copy
|
|
||||||
* @return A copy of the data array
|
|
||||||
*/
|
|
||||||
public static int[][][] crop(int[][][] data, int xData, int yData, int[][][] crop, int xCrop, int yCrop, int width, int hight){
|
|
||||||
if(crop==null) crop = new int[width][hight][4];
|
|
||||||
for(int y=0; y<width ;y++){
|
|
||||||
for(int x=0; x<hight ;x++){
|
|
||||||
crop[y+yData][x+xData][0] = data[y+yCrop][x+xCrop][0];
|
|
||||||
crop[y+yData][x+xData][1] = data[y+yCrop][x+xCrop][1];
|
|
||||||
crop[y+yData][x+xData][2] = data[y+yCrop][x+xCrop][2];
|
|
||||||
crop[y+yData][x+xData][3] = data[y+yCrop][x+xCrop][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return crop;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies the given array to a new one that it returns
|
|
||||||
*
|
|
||||||
* @param data The data to duplicate
|
|
||||||
* @return an copy of the array
|
|
||||||
*/
|
|
||||||
public static int[][][] copyArray(int[][][] data){
|
|
||||||
return copyArray(data, 0, 0, data[0].length, data.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies the given array to a new one that it returns
|
|
||||||
*
|
|
||||||
* @param data The data to duplicate
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return The array copy
|
|
||||||
*/
|
|
||||||
public static int[][][] copyArray(int[][][] data, int startX, int startY, int stopX, int stopY){
|
|
||||||
int[][][] copy = new int[data.length][data[0].length][4];
|
|
||||||
return copyArray(data, copy, startX, startY, stopX, stopY);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies the given array to a new one that it returns
|
|
||||||
*
|
|
||||||
* @param data The data to duplicate
|
|
||||||
* @param dest is the array to copy the data to
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
* @return the dest array
|
|
||||||
*/
|
|
||||||
public static int[][][] copyArray(int[][][] data, int[][][] dest, int startX, int startY, int stopX, int stopY){
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
dest[y][x][0] = data[y][x][0];
|
|
||||||
dest[y][x][1] = data[y][x][1];
|
|
||||||
dest[y][x][2] = data[y][x][2];
|
|
||||||
dest[y][x][3] = data[y][x][3];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return dest;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method clips the values of the pixel so that they
|
|
||||||
* are in the range 0-255
|
|
||||||
*
|
|
||||||
* @param data The image data
|
|
||||||
* @param startX is the x pixel of the image to start from
|
|
||||||
* @param startY is the y pixel of the image to start from
|
|
||||||
* @param stopX is the x pixel of the image to stop
|
|
||||||
* @param stopY is the y pixel of the image to stop
|
|
||||||
*/
|
|
||||||
public static void clip(int[][][] data, int startX, int startY, int stopX, int stopY){
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
|
||||||
for(int x=startX; x<stopX ;x++){
|
|
||||||
data[y][x][1] = clip(data[y][x][1]);
|
|
||||||
data[y][x][2] = clip(data[y][x][2]);
|
|
||||||
data[y][x][3] = clip(data[y][x][3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This method clips the values of a color so that it
|
|
||||||
* is in the range 0-255
|
|
||||||
*
|
|
||||||
* @param color
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public static int clip(int color){
|
|
||||||
if(color < 0)
|
|
||||||
return 0;
|
|
||||||
else if(color > 255)
|
|
||||||
return 255;
|
|
||||||
else
|
|
||||||
return color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
372
src/zutil/image/RAWImageUtil.java
Normal file
372
src/zutil/image/RAWImageUtil.java
Normal file
|
|
@ -0,0 +1,372 @@
|
||||||
|
package zutil.image;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some util methods for image processing
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class RAWImageUtil {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the peek value in the image
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return The peak value of the image
|
||||||
|
*/
|
||||||
|
public static int getPeakValue(int[][][] data) {
|
||||||
|
return getPeakValue(data, 0, 0, data[0].length, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the peek value in the image
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return The peak value of the image
|
||||||
|
*/
|
||||||
|
public static int getPeakValue(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
||||||
|
int peak = 0;
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
if(data[y][x][1] > peak) peak = data[y][x][1];
|
||||||
|
if(data[y][x][2] > peak) peak = data[y][x][2];
|
||||||
|
if(data[y][x][3] > peak) peak = data[y][x][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return peak;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the image data by the given scale
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param scale The scale to normalize the image by
|
||||||
|
*/
|
||||||
|
public static void normalize(int[][][] data, int startX, int startY, int stopX, int stopY, double scale) {
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
data[y][x][1] = (int)(data[y][x][1] * scale);
|
||||||
|
data[y][x][2] = (int)(data[y][x][2] * scale);
|
||||||
|
data[y][x][3] = (int)(data[y][x][3] * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalizes the image data by the given scale
|
||||||
|
*
|
||||||
|
* @param output The output data array
|
||||||
|
* @param data The image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param scale The scale to normalize the image by
|
||||||
|
*/
|
||||||
|
public static void normalize(int[][][] output, int[][][] data, int startX, int startY, int stopX, int stopY, double scale) {
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
output[y][x][1] = (int)(data[y][x][1] * scale);
|
||||||
|
output[y][x][2] = (int)(data[y][x][2] * scale);
|
||||||
|
output[y][x][3] = (int)(data[y][x][3] * scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the RMS value of the image
|
||||||
|
* (The RMS value is a measure of the width of the color distribution.)
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return The RMS value for the image
|
||||||
|
*/
|
||||||
|
public static int getRMS(int[][][] data, int startX, int startY, int stopX, int stopY){
|
||||||
|
int pixelCount = 0;
|
||||||
|
long accum = 0;
|
||||||
|
for(int y=startY; y <stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
accum += data[y][x][1] * data[y][x][1];
|
||||||
|
accum += data[y][x][2] * data[y][x][2];
|
||||||
|
accum += data[y][x][3] * data[y][x][3];
|
||||||
|
pixelCount += 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int meanSquare = (int)(accum/pixelCount);
|
||||||
|
int rms = (int)(Math.sqrt(meanSquare));
|
||||||
|
return rms;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplies the given image data by the given value
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param scale is the number to scale the image color by
|
||||||
|
*/
|
||||||
|
public static void scale(int[][][] data, int startX, int startY, int stopX, int stopY, double scale){
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
data[y][x][1] *= scale;
|
||||||
|
data[y][x][2] *= scale;
|
||||||
|
data[y][x][3] *= scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mean value of the given image data
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @return the mean value of the image
|
||||||
|
*/
|
||||||
|
public static int getMeanValue(int[][][] data){
|
||||||
|
return getMeanValue(data, 0, 0, data[0].length, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the mean value of the given image data
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return the mean value of the image
|
||||||
|
*/
|
||||||
|
public static int getMeanValue(int[][][] data, int startX, int startY, int stopX, int stopY){
|
||||||
|
int[] tmp = getMeanArray(data, startX, startY, stopX, stopY);
|
||||||
|
return (tmp[0] + tmp[1] + tmp[2])/3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an mean array containing a mean value for each color
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return the mean value of the image
|
||||||
|
*/
|
||||||
|
public static int[] getMeanArray(int[][][] data, int startX, int startY, int stopX, int stopY){
|
||||||
|
int mean[] = new int[3];
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
mean[0] += data[y][x][1];
|
||||||
|
mean[1] += data[y][x][2];
|
||||||
|
mean[2] += data[y][x][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// calculate the mean value
|
||||||
|
int pixelCount = (stopY-startY)*(stopX-startX);
|
||||||
|
mean[0] /= pixelCount;
|
||||||
|
mean[1] /= pixelCount;
|
||||||
|
mean[2] /= pixelCount;
|
||||||
|
|
||||||
|
return mean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes the mean value from the image data
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param mean is the mean value
|
||||||
|
*/
|
||||||
|
public static void remMeanValue(int[][][] data, int startX, int startY, int stopX, int stopY, int mean){
|
||||||
|
addMeanValue(data, startX, startY, stopX, stopY, -mean);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds the mean value to the image data
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param mean is the mean value
|
||||||
|
*/
|
||||||
|
public static void addMeanValue(int[][][] data, int startX, int startY, int stopX, int stopY, int mean){
|
||||||
|
addMeanArray(data, startX, startY, stopX, stopY, new int[]{mean, mean, mean});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* removes an mean array containing a mean value for each color
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param mean is an array of length 3 containing a mean value for each color RGB
|
||||||
|
*/
|
||||||
|
public static void remMeanArray(int[][][] data, int startX, int startY, int stopX, int stopY, int[] mean){
|
||||||
|
addMeanArray(data, startX, startY, stopX, stopY, new int[]{-mean[0], -mean[1], -mean[2]});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an mean array containing a mean value for each color
|
||||||
|
*
|
||||||
|
* @param data is the image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @param mean is an array of length 3 containing a mean value for each color RGB
|
||||||
|
*/
|
||||||
|
public static void addMeanArray(int[][][] data, int startX, int startY, int stopX, int stopY, int[] mean){
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
data[y][x][1] += mean[0];
|
||||||
|
data[y][x][2] += mean[1];
|
||||||
|
data[y][x][3] += mean[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the pixel data from the image to the new array
|
||||||
|
*
|
||||||
|
* @param data The data to copy
|
||||||
|
* @param xStart X start position on the source
|
||||||
|
* @param yStart Y start position on the source
|
||||||
|
* @param width The amount of pixels to copy
|
||||||
|
* @param hight The amount of pixels to copy
|
||||||
|
* @return A copy of the data array
|
||||||
|
*/
|
||||||
|
public static int[][][] crop(int[][][] data, int xStart, int yStart, int width, int hight){
|
||||||
|
return crop(data, xStart, yStart, null, 0, 0, width, hight);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies all the pixel data from the image to the new array
|
||||||
|
*
|
||||||
|
* @param data The data to copy
|
||||||
|
* @param xData X start position in the source
|
||||||
|
* @param yData Y start position in the source
|
||||||
|
* @param crop The destination
|
||||||
|
* @param xCrop X start position in the destination
|
||||||
|
* @param yCrop Y start position in the destination
|
||||||
|
* @param width The amount of pixels to copy
|
||||||
|
* @param hight The amount of pixels to copy
|
||||||
|
* @return A copy of the data array
|
||||||
|
*/
|
||||||
|
public static int[][][] crop(int[][][] data, int xData, int yData, int[][][] crop, int xCrop, int yCrop, int width, int hight){
|
||||||
|
if(crop==null) crop = new int[width][hight][4];
|
||||||
|
for(int y=0; y<width ;y++){
|
||||||
|
for(int x=0; x<hight ;x++){
|
||||||
|
crop[y+yData][x+xData][0] = data[y+yCrop][x+xCrop][0];
|
||||||
|
crop[y+yData][x+xData][1] = data[y+yCrop][x+xCrop][1];
|
||||||
|
crop[y+yData][x+xData][2] = data[y+yCrop][x+xCrop][2];
|
||||||
|
crop[y+yData][x+xData][3] = data[y+yCrop][x+xCrop][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return crop;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given array to a new one that it returns
|
||||||
|
*
|
||||||
|
* @param data The data to duplicate
|
||||||
|
* @return an copy of the array
|
||||||
|
*/
|
||||||
|
public static int[][][] copyArray(int[][][] data){
|
||||||
|
return copyArray(data, 0, 0, data[0].length, data.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given array to a new one that it returns
|
||||||
|
*
|
||||||
|
* @param data The data to duplicate
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return The array copy
|
||||||
|
*/
|
||||||
|
public static int[][][] copyArray(int[][][] data, int startX, int startY, int stopX, int stopY){
|
||||||
|
int[][][] copy = new int[data.length][data[0].length][4];
|
||||||
|
return copyArray(data, copy, startX, startY, stopX, stopY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies the given array to a new one that it returns
|
||||||
|
*
|
||||||
|
* @param data The data to duplicate
|
||||||
|
* @param dest is the array to copy the data to
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
* @return the dest array
|
||||||
|
*/
|
||||||
|
public static int[][][] copyArray(int[][][] data, int[][][] dest, int startX, int startY, int stopX, int stopY){
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
dest[y][x][0] = data[y][x][0];
|
||||||
|
dest[y][x][1] = data[y][x][1];
|
||||||
|
dest[y][x][2] = data[y][x][2];
|
||||||
|
dest[y][x][3] = data[y][x][3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clips the values of the pixel so that they
|
||||||
|
* are in the range 0-255
|
||||||
|
*
|
||||||
|
* @param data The image data
|
||||||
|
* @param startX is the x pixel of the image to start from
|
||||||
|
* @param startY is the y pixel of the image to start from
|
||||||
|
* @param stopX is the x pixel of the image to stop
|
||||||
|
* @param stopY is the y pixel of the image to stop
|
||||||
|
*/
|
||||||
|
public static void clip(int[][][] data, int startX, int startY, int stopX, int stopY){
|
||||||
|
for(int y=startY; y<stopY ;y++){
|
||||||
|
for(int x=startX; x<stopX ;x++){
|
||||||
|
data[y][x][1] = clip(data[y][x][1]);
|
||||||
|
data[y][x][2] = clip(data[y][x][2]);
|
||||||
|
data[y][x][3] = clip(data[y][x][3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method clips the values of a color so that it
|
||||||
|
* is in the range 0-255
|
||||||
|
*
|
||||||
|
* @param color
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static int clip(int color){
|
||||||
|
if(color < 0)
|
||||||
|
return 0;
|
||||||
|
else if(color > 255)
|
||||||
|
return 255;
|
||||||
|
else
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@ package zutil.image.filters;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import zutil.image.ImageFilterProcessor;
|
import zutil.image.ImageFilterProcessor;
|
||||||
import zutil.image.ImageUtil;
|
import zutil.image.RAWImageUtil;
|
||||||
import zutil.math.ZMath;
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
public class BlurFilter extends ImageFilterProcessor{
|
public class BlurFilter extends ImageFilterProcessor{
|
||||||
|
|
@ -29,10 +29,10 @@ public class BlurFilter extends ImageFilterProcessor{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
||||||
int inputPeak = ImageUtil.getPeakValue(data);
|
int inputPeak = RAWImageUtil.getPeakValue(data);
|
||||||
|
|
||||||
int[][][] tmpData = new int[data.length][data[0].length][4];
|
int[][][] tmpData = new int[data.length][data[0].length][4];
|
||||||
int[][][] output = ImageUtil.copyArray(data);
|
int[][][] output = RAWImageUtil.copyArray(data);
|
||||||
//Perform the convolution one or more times in succession
|
//Perform the convolution one or more times in succession
|
||||||
int redSum, greenSum, blueSum, outputPeak;
|
int redSum, greenSum, blueSum, outputPeak;
|
||||||
for(int i=0; i<blurValue ;i++){
|
for(int i=0; i<blurValue ;i++){
|
||||||
|
|
@ -85,8 +85,8 @@ public class BlurFilter extends ImageFilterProcessor{
|
||||||
}
|
}
|
||||||
|
|
||||||
// getting the new peak value and normalizing the image
|
// getting the new peak value and normalizing the image
|
||||||
outputPeak = ImageUtil.getPeakValue(tmpData);
|
outputPeak = RAWImageUtil.getPeakValue(tmpData);
|
||||||
ImageUtil.normalize(output, tmpData, startX, startY, stopX, stopY, ((double)inputPeak)/outputPeak );
|
RAWImageUtil.normalize(output, tmpData, startX, startY, stopX, stopY, ((double)inputPeak)/outputPeak );
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package zutil.image.filters;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import zutil.image.ImageFilterProcessor;
|
import zutil.image.ImageFilterProcessor;
|
||||||
import zutil.image.ImageUtil;
|
import zutil.image.RAWImageUtil;
|
||||||
|
|
||||||
public class ContrastBrightnessFilter extends ImageFilterProcessor{
|
public class ContrastBrightnessFilter extends ImageFilterProcessor{
|
||||||
private double contrast;
|
private double contrast;
|
||||||
|
|
@ -31,15 +31,15 @@ public class ContrastBrightnessFilter extends ImageFilterProcessor{
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
||||||
int mean = ImageUtil.getMeanValue(data);
|
int mean = RAWImageUtil.getMeanValue(data);
|
||||||
|
|
||||||
int[][][] output = ImageUtil.copyArray(data);
|
int[][][] output = RAWImageUtil.copyArray(data);
|
||||||
|
|
||||||
ImageUtil.addMeanValue(output, startX, startY, stopX, stopY, mean*(-1));
|
RAWImageUtil.addMeanValue(output, startX, startY, stopX, stopY, mean*(-1));
|
||||||
ImageUtil.scale(output, startX, startY, stopX, stopY, contrast);
|
RAWImageUtil.scale(output, startX, startY, stopX, stopY, contrast);
|
||||||
ImageUtil.addMeanValue(output, startX, startY, stopX, stopY, (int)(brightness*mean));
|
RAWImageUtil.addMeanValue(output, startX, startY, stopX, stopY, (int)(brightness*mean));
|
||||||
|
|
||||||
ImageUtil.clip(output, startX, startY, stopX, stopY);
|
RAWImageUtil.clip(output, startX, startY, stopX, stopY);
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package zutil.image.filters;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import zutil.image.ImageFilterProcessor;
|
import zutil.image.ImageFilterProcessor;
|
||||||
import zutil.image.ImageUtil;
|
import zutil.image.RAWImageUtil;
|
||||||
import zutil.math.ZMath;
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -59,7 +59,7 @@ public class ConvolutionFilter extends ImageFilterProcessor{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageUtil.clip(tmpData, startX, startY, stopX, stopY);
|
RAWImageUtil.clip(tmpData, startX, startY, stopX, stopY);
|
||||||
|
|
||||||
return tmpData;
|
return tmpData;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package zutil.image.filters;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import zutil.image.ImageFilterProcessor;
|
import zutil.image.ImageFilterProcessor;
|
||||||
import zutil.image.ImageUtil;
|
import zutil.image.RAWImageUtil;
|
||||||
import zutil.math.ZMath;
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class DitheringFilter extends ImageFilterProcessor{
|
||||||
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
||||||
int error, index;
|
int error, index;
|
||||||
int[] currentPixel;
|
int[] currentPixel;
|
||||||
int[][][] output = ImageUtil.copyArray(data);
|
int[][][] output = RAWImageUtil.copyArray(data);
|
||||||
|
|
||||||
for(int y=startY; y<stopY ;y++){
|
for(int y=startY; y<stopY ;y++){
|
||||||
setProgress(ZMath.percent(0, stopY-startY-1, y));
|
setProgress(ZMath.percent(0, stopY-startY-1, y));
|
||||||
|
|
@ -53,14 +53,14 @@ public class DitheringFilter extends ImageFilterProcessor{
|
||||||
for (int i = 1; i < 4; i++) {
|
for (int i = 1; i < 4; i++) {
|
||||||
error = currentPixel[i] - palette[index][i];
|
error = currentPixel[i] - palette[index][i];
|
||||||
if (x + 1 < output[0].length) {
|
if (x + 1 < output[0].length) {
|
||||||
output[y+0][x+1][i] = ImageUtil.clip( output[y+0][x+1][i] + (error*7)/16 );
|
output[y+0][x+1][i] = RAWImageUtil.clip( output[y+0][x+1][i] + (error*7)/16 );
|
||||||
}
|
}
|
||||||
if (y + 1 < data.length) {
|
if (y + 1 < data.length) {
|
||||||
if (x - 1 > 0)
|
if (x - 1 > 0)
|
||||||
output[y+1][x-1][i] = ImageUtil.clip( output[y+1][x-1][i] + (error*3)/16 );
|
output[y+1][x-1][i] = RAWImageUtil.clip( output[y+1][x-1][i] + (error*3)/16 );
|
||||||
output[y+1][x+0][i] = ImageUtil.clip( output[y+1][x+0][i] + (error*5)/16 );
|
output[y+1][x+0][i] = RAWImageUtil.clip( output[y+1][x+0][i] + (error*5)/16 );
|
||||||
if (x + 1 < data[0].length)
|
if (x + 1 < data[0].length)
|
||||||
output[y+1][x+1][i] = ImageUtil.clip( output[y+1][x+1][i] + (error*1)/16 );
|
output[y+1][x+1][i] = RAWImageUtil.clip( output[y+1][x+1][i] + (error*1)/16 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import zutil.algo.sort.sortable.SortableDataList;
|
import zutil.algo.sort.sortable.SortableDataList;
|
||||||
import zutil.image.ImageFilterProcessor;
|
import zutil.image.ImageFilterProcessor;
|
||||||
import zutil.image.ImageUtil;
|
import zutil.image.RAWImageUtil;
|
||||||
import zutil.math.ZMath;
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -62,7 +62,7 @@ public class MedianFilter extends ImageFilterProcessor{
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
public int[][][] process(int[][][] data, int startX, int startY, int stopX, int stopY) {
|
||||||
int[][][] tmpData = ImageUtil.copyArray(data);
|
int[][][] tmpData = RAWImageUtil.copyArray(data);
|
||||||
|
|
||||||
int edgeX = windowSize / 2;
|
int edgeX = windowSize / 2;
|
||||||
int edgeY = windowSize / 2;
|
int edgeY = windowSize / 2;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package zutil.image.filters;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
|
||||||
import zutil.image.ImageFilterProcessor;
|
import zutil.image.ImageFilterProcessor;
|
||||||
import zutil.image.ImageUtil;
|
import zutil.image.RAWImageUtil;
|
||||||
import zutil.math.ZMath;
|
import zutil.math.ZMath;
|
||||||
|
|
||||||
public class SpotLightFilter extends ImageFilterProcessor{
|
public class SpotLightFilter extends ImageFilterProcessor{
|
||||||
|
|
@ -64,9 +64,9 @@ public class SpotLightFilter extends ImageFilterProcessor{
|
||||||
}
|
}
|
||||||
|
|
||||||
output[y][x][0] = data[y][x][0];
|
output[y][x][0] = data[y][x][0];
|
||||||
output[y][x][1] = ImageUtil.clip((int)(scale * data[y][x][1]));
|
output[y][x][1] = RAWImageUtil.clip((int)(scale * data[y][x][1]));
|
||||||
output[y][x][2] = ImageUtil.clip((int)(scale * data[y][x][2]));
|
output[y][x][2] = RAWImageUtil.clip((int)(scale * data[y][x][2]));
|
||||||
output[y][x][3] = ImageUtil.clip((int)(scale * data[y][x][3]));
|
output[y][x][3] = RAWImageUtil.clip((int)(scale * data[y][x][3]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
return output;
|
||||||
|
|
|
||||||
323
src/zutil/network/SSDPServer.java
Normal file
323
src/zutil/network/SSDPServer.java
Normal file
|
|
@ -0,0 +1,323 @@
|
||||||
|
package zutil.network;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Timer;
|
||||||
|
import java.util.TimerTask;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.network.http.HTTPHeaderParser;
|
||||||
|
import zutil.network.http.HttpPrintStream;
|
||||||
|
import zutil.network.threaded.ThreadedUDPNetworkThread;
|
||||||
|
import zutil.network.threaded.ThreadedUDPNetwork;
|
||||||
|
import zutil.wrapper.StringOutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Server class that announces an service by the SSDP
|
||||||
|
* protocol specified at:
|
||||||
|
* http://coherence.beebits.net/chrome/site/draft-cai-ssdp-v1-03.txt
|
||||||
|
* ftp://ftp.pwg.org/pub/pwg/www/hypermail/ps/att-0188/01-psi_SSDP.pdf
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
* ********* Message clarification:
|
||||||
|
* ****** Incoming:
|
||||||
|
* ST: Search Target, this is object of the discovery request, (e.g., ssdp:all, etc.)
|
||||||
|
* HOST: This is the SSDP multicast address
|
||||||
|
* MAN: Description of packet type, (e.g., "ssdp:discover", )
|
||||||
|
* MX: Wait these few seconds and then send response
|
||||||
|
*
|
||||||
|
* ****** Outgoing:
|
||||||
|
* EXT: required by HTTP - not used with SSDP
|
||||||
|
* SERVER: informational
|
||||||
|
* LOCATION: This is the URL to request the QueryEndpointsInterface endpoint
|
||||||
|
* USN: advertisement UUID
|
||||||
|
* CACHE-CONTROL: max-age = seconds until advertisement expires
|
||||||
|
* NT: Notify target same as ST
|
||||||
|
* NTS: same as Man but for Notify messages
|
||||||
|
*/
|
||||||
|
public class SSDPServer extends ThreadedUDPNetwork implements ThreadedUDPNetworkThread{
|
||||||
|
public static final String SERVER_INFO = "SSDP Java Server by Ziver Koc";
|
||||||
|
public static final int DEFAULT_CACHE_TIME = 60*30; // 30 min
|
||||||
|
public static final int BUFFER_SIZE = 512;
|
||||||
|
public static final String SSDP_MULTICAST_ADDR = "239.255.255.250";
|
||||||
|
public static final int SSDP_PORT = 1900;
|
||||||
|
|
||||||
|
// instance specific values
|
||||||
|
private int cache_time;
|
||||||
|
private NotifyTimer notifyTimer = null;
|
||||||
|
/** HashMap that contains services as < SearchTargetName, Location > */
|
||||||
|
private HashMap<String, String> services;
|
||||||
|
/** A Map of all the used USN:s */
|
||||||
|
private HashMap<String, String> usn_map;
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws IOException{
|
||||||
|
SSDPServer ssdp = new SSDPServer();
|
||||||
|
ssdp.addService("upnp:rootdevice", "nowhere");
|
||||||
|
ssdp.start();
|
||||||
|
MultiPrintStream.out.println("SSDP Server running");
|
||||||
|
}
|
||||||
|
|
||||||
|
public SSDPServer() throws IOException{
|
||||||
|
super( null, SSDP_PORT, SSDP_MULTICAST_ADDR );
|
||||||
|
super.setThread( this );
|
||||||
|
|
||||||
|
services = new HashMap<String, String>();
|
||||||
|
usn_map = new HashMap<String, String>();
|
||||||
|
|
||||||
|
setChacheTime( DEFAULT_CACHE_TIME );
|
||||||
|
enableNotify( true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an service that will be announced.
|
||||||
|
*
|
||||||
|
* @param searchTarget is the ST value in SSDP
|
||||||
|
* @param location is the location of the service
|
||||||
|
*/
|
||||||
|
public void addService(String searchTarget, String location){
|
||||||
|
services.put( searchTarget, location );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Remove a service from being announced. This function will
|
||||||
|
* send out an byebye message to the clients that the service is down.
|
||||||
|
*
|
||||||
|
* @param searchTarget is the ST value in SSDP
|
||||||
|
*/
|
||||||
|
public void removeService(String searchTarget){
|
||||||
|
sendByeBye( searchTarget );
|
||||||
|
services.remove( searchTarget );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cache time that will be sent to
|
||||||
|
* the clients. If notification is enabled then an
|
||||||
|
* notification message will be sent every cache_time/2 seconds
|
||||||
|
*
|
||||||
|
* @param time is the time in seconds
|
||||||
|
*/
|
||||||
|
public void setChacheTime(int time){
|
||||||
|
cache_time = time;
|
||||||
|
if( isNotifyEnabled() ){
|
||||||
|
enableNotify(false);
|
||||||
|
enableNotify(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable notification messages to clients
|
||||||
|
* every cache_time/2 seconds
|
||||||
|
*/
|
||||||
|
public void enableNotify(boolean enable){
|
||||||
|
if( enable && notifyTimer==null ){
|
||||||
|
notifyTimer = new NotifyTimer();
|
||||||
|
Timer timer = new Timer();
|
||||||
|
timer.schedule(new NotifyTimer(), 0, cache_time*1000/2);
|
||||||
|
}else if( !enable && notifyTimer!=null ){
|
||||||
|
notifyTimer.cancel();
|
||||||
|
notifyTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return if notification messages is enabled
|
||||||
|
*/
|
||||||
|
public boolean isNotifyEnabled(){
|
||||||
|
return notifyTimer != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the incoming packets like this:
|
||||||
|
*
|
||||||
|
* ***** REQUEST:
|
||||||
|
* M-SEARCH * HTTP/1.1
|
||||||
|
* S: uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6
|
||||||
|
* Host: 239.255.255.250:reservedSSDPport
|
||||||
|
* Man: "ssdp:discover"
|
||||||
|
* ST: ge:fridge
|
||||||
|
* MX: 3
|
||||||
|
*
|
||||||
|
* ***** RESPONSE;
|
||||||
|
* HTTP/1.1 200 OK
|
||||||
|
* S: uuid:ijklmnop-7dec-11d0-a765-00a0c91e6bf6
|
||||||
|
* Ext:
|
||||||
|
* Cache-Control: no-cache="Ext", max-age = 5000
|
||||||
|
* ST: ge:fridge
|
||||||
|
* USN: uuid:abcdefgh-7dec-11d0-a765-00a0c91e6bf6
|
||||||
|
* AL: <blender:ixl><http://foo/bar>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network) {
|
||||||
|
try {
|
||||||
|
String msg = new String( packet.getData() );
|
||||||
|
|
||||||
|
HTTPHeaderParser header = new HTTPHeaderParser( msg );
|
||||||
|
MultiPrintStream.out.println(header);
|
||||||
|
|
||||||
|
// ******* Respond
|
||||||
|
// Check that the message is an ssdp discovery message
|
||||||
|
if( header.getRequestType().equalsIgnoreCase("M-SEARCH") ){
|
||||||
|
String man = header.getHTTPAttribute("Man").replace("\"", "");
|
||||||
|
String st = header.getHTTPAttribute("ST");
|
||||||
|
// Check that its the correct URL and that its an ssdp:discover message
|
||||||
|
if( header.getRequestURL().equals("*") && man.equalsIgnoreCase("ssdp:discover") ){
|
||||||
|
// Check if the requested service exists
|
||||||
|
if( services.containsKey( st ) ){
|
||||||
|
// Generate the SSDP response
|
||||||
|
StringOutputStream response = new StringOutputStream();
|
||||||
|
HttpPrintStream http = new HttpPrintStream( response );
|
||||||
|
http.setStatusCode(200);
|
||||||
|
http.setHeader("Server", SERVER_INFO );
|
||||||
|
http.setHeader("ST", st );
|
||||||
|
http.setHeader("Location", services.get(st) );
|
||||||
|
http.setHeader("EXT", "" );
|
||||||
|
http.setHeader("Cache-Control", "max-age = "+cache_time );
|
||||||
|
http.setHeader("USN", getUSN(st) );
|
||||||
|
|
||||||
|
http.close();
|
||||||
|
MultiPrintStream.out.println("\n"+response);
|
||||||
|
byte[] data = response.toString().getBytes();
|
||||||
|
packet = new DatagramPacket(
|
||||||
|
data, data.length,
|
||||||
|
packet.getAddress(),
|
||||||
|
packet.getPort());
|
||||||
|
network.send( packet );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This thread is a timer task that sends an
|
||||||
|
* notification message to the network every
|
||||||
|
* cache_time/2 seconds.
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
private class NotifyTimer extends TimerTask {
|
||||||
|
public void run(){
|
||||||
|
sendNotify();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sends keepalive messages to update the cache of the clients
|
||||||
|
*/
|
||||||
|
public void sendNotify(){
|
||||||
|
for(String st : services.keySet()){
|
||||||
|
sendNotify( st );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sends an keepalive message to update the cache of the clients
|
||||||
|
*
|
||||||
|
* @param searchTarget is the ST value of the service
|
||||||
|
*
|
||||||
|
* ********** Message ex:
|
||||||
|
* NOTIFY * HTTP/1.1
|
||||||
|
* Host: 239.255.255.250:reservedSSDPport
|
||||||
|
* NT: blenderassociation:blender
|
||||||
|
* NTS: ssdp:alive
|
||||||
|
* USN: someunique:idscheme3
|
||||||
|
* AL: <blender:ixl><http://foo/bar>
|
||||||
|
* Cache-Control: max-age = 7393
|
||||||
|
*/
|
||||||
|
public void sendNotify(String searchTarget){
|
||||||
|
try {
|
||||||
|
// Generate the SSDP response
|
||||||
|
StringOutputStream msg = new StringOutputStream();
|
||||||
|
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST );
|
||||||
|
http.setRequestType("NOTIFY");
|
||||||
|
http.setRequestURL("*");
|
||||||
|
http.setHeader("Server", SERVER_INFO );
|
||||||
|
http.setHeader("Host", SSDP_MULTICAST_ADDR+":"+SSDP_PORT );
|
||||||
|
http.setHeader("NT", searchTarget );
|
||||||
|
http.setHeader("NTS", "ssdp:alive" );
|
||||||
|
http.setHeader("Location", services.get(searchTarget) );
|
||||||
|
http.setHeader("Cache-Control", "max-age = "+cache_time );
|
||||||
|
http.setHeader("USN", getUSN(searchTarget) );
|
||||||
|
|
||||||
|
http.close();
|
||||||
|
MultiPrintStream.out.println("\n"+msg);
|
||||||
|
byte[] data = msg.toString().getBytes();
|
||||||
|
DatagramPacket packet = new DatagramPacket(
|
||||||
|
data, data.length,
|
||||||
|
InetAddress.getByName( SSDP_MULTICAST_ADDR ),
|
||||||
|
SSDP_PORT );
|
||||||
|
super.send( packet );
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown message is sent to the clients that all
|
||||||
|
* the service is shutting down.
|
||||||
|
*/
|
||||||
|
public void sendByeBye(){
|
||||||
|
for(String st : services.keySet()){
|
||||||
|
sendByeBye( st );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Shutdown message is sent to the clients that the service is shutting down
|
||||||
|
*
|
||||||
|
* @param searchTarget is the ST value of the service
|
||||||
|
*
|
||||||
|
* ********** Message ex:
|
||||||
|
* NOTIFY * HTTP/1.1
|
||||||
|
* Host: 239.255.255.250:reservedSSDPport
|
||||||
|
* NT: someunique:idscheme3
|
||||||
|
* NTS: ssdp:byebye
|
||||||
|
* USN: someunique:idscheme3
|
||||||
|
*/
|
||||||
|
public void sendByeBye(String searchTarget){
|
||||||
|
try {
|
||||||
|
// Generate the SSDP response
|
||||||
|
StringOutputStream msg = new StringOutputStream();
|
||||||
|
HttpPrintStream http = new HttpPrintStream( msg, HttpPrintStream.HTTPMessageType.REQUEST );
|
||||||
|
http.setRequestType("NOTIFY");
|
||||||
|
http.setRequestURL("*");
|
||||||
|
http.setHeader("Server", SERVER_INFO );
|
||||||
|
http.setHeader("Host", SSDP_MULTICAST_ADDR+":"+SSDP_PORT );
|
||||||
|
http.setHeader("NT", searchTarget );
|
||||||
|
http.setHeader("NTS", "ssdp:byebye" );
|
||||||
|
http.setHeader("USN", getUSN(searchTarget) );
|
||||||
|
|
||||||
|
http.close();
|
||||||
|
MultiPrintStream.out.println("\n"+msg);
|
||||||
|
byte[] data = msg.toString().getBytes();
|
||||||
|
DatagramPacket packet = new DatagramPacket(
|
||||||
|
data, data.length,
|
||||||
|
InetAddress.getByName( SSDP_MULTICAST_ADDR ),
|
||||||
|
SSDP_PORT );
|
||||||
|
super.send( packet );
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates an unique USN for the service
|
||||||
|
*
|
||||||
|
* @param searchTarget is the service ST name
|
||||||
|
* @return an unique string that corresponds to the service
|
||||||
|
*/
|
||||||
|
public String getUSN(String searchTarget){
|
||||||
|
if( !usn_map.containsKey( searchTarget ) ){
|
||||||
|
String usn = "uuid:" + UUID.nameUUIDFromBytes( (searchTarget+services.get(searchTarget)).getBytes() );
|
||||||
|
usn_map.put( searchTarget, usn );
|
||||||
|
return usn;
|
||||||
|
}
|
||||||
|
return usn_map.get( searchTarget );
|
||||||
|
}
|
||||||
|
}
|
||||||
237
src/zutil/network/http/HTTPHeaderParser.java
Normal file
237
src/zutil/network/http/HTTPHeaderParser.java
Normal file
|
|
@ -0,0 +1,237 @@
|
||||||
|
package zutil.network.http;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Scanner;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class HTTPHeaderParser {
|
||||||
|
// Some Cached regexes
|
||||||
|
private static final Pattern colonPattern = Pattern.compile(":");
|
||||||
|
private static final Pattern equalPattern = Pattern.compile("=");
|
||||||
|
private static final Pattern andPattern = Pattern.compile("&");
|
||||||
|
private static final Pattern semiColonPattern = Pattern.compile(";");
|
||||||
|
|
||||||
|
// HTTP info
|
||||||
|
private String type;
|
||||||
|
private String url;
|
||||||
|
private HashMap<String, String> url_attr;
|
||||||
|
private float version;
|
||||||
|
|
||||||
|
// params
|
||||||
|
private HashMap<String, String> attributes;
|
||||||
|
private HashMap<String, String> cookies;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the HTTP header information from the stream
|
||||||
|
*
|
||||||
|
* @param in is the stream
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public HTTPHeaderParser(BufferedReader in) throws IOException{
|
||||||
|
url_attr = new HashMap<String, String>();
|
||||||
|
attributes = new HashMap<String, String>();
|
||||||
|
cookies = new HashMap<String, String>();
|
||||||
|
|
||||||
|
String tmp = null;
|
||||||
|
if( (tmp=in.readLine()) != null && !tmp.isEmpty() ){
|
||||||
|
parseStartLine( tmp );
|
||||||
|
while( (tmp=in.readLine()) != null && !tmp.isEmpty() ){
|
||||||
|
parseLine( tmp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseCookies();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the HTTP header information from an String
|
||||||
|
*
|
||||||
|
* @param in is the string
|
||||||
|
*/
|
||||||
|
public HTTPHeaderParser(String in){
|
||||||
|
url_attr = new HashMap<String, String>();
|
||||||
|
attributes = new HashMap<String, String>();
|
||||||
|
cookies = new HashMap<String, String>();
|
||||||
|
|
||||||
|
Scanner sc = new Scanner(in);
|
||||||
|
sc.useDelimiter("\n");
|
||||||
|
String tmp = null;
|
||||||
|
if( sc.hasNext() && !(tmp=sc.next()).isEmpty() ){
|
||||||
|
parseStartLine( tmp );
|
||||||
|
while( sc.hasNext() && !(tmp=sc.next()).isEmpty() ){
|
||||||
|
parseLine( tmp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parseCookies();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the first header line and ads the values to
|
||||||
|
* the map and returns the file name and path
|
||||||
|
*
|
||||||
|
* @param header The header String
|
||||||
|
* @param map The HashMap to put the variables to
|
||||||
|
* @return The path and file name as a String
|
||||||
|
*/
|
||||||
|
protected void parseStartLine(String line){
|
||||||
|
type = (line.substring(0, line.indexOf(" "))).trim();
|
||||||
|
version = Float.parseFloat( line.substring(line.lastIndexOf("HTTP/")+5 , line.length()).trim() );
|
||||||
|
line = (line.substring(type.length()+1, line.lastIndexOf("HTTP/"))).trim();
|
||||||
|
|
||||||
|
// parse URL and attributes
|
||||||
|
if(line.indexOf('?') > -1){
|
||||||
|
url = line.substring(0, line.indexOf('?'));
|
||||||
|
line = line.substring(line.indexOf('?')+1, line.length());
|
||||||
|
parseUrlAttributes(line, url_attr);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
url = line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a String with variables from a get or post
|
||||||
|
* that was sent from a client and puts the data into a HashMap
|
||||||
|
*
|
||||||
|
* @param header is the String containing all the attributes
|
||||||
|
* @param map is the HashMap to put all the values into
|
||||||
|
*/
|
||||||
|
public static void parseUrlAttributes(String attributes, HashMap<String, String> map){
|
||||||
|
String[] tmp;
|
||||||
|
// get the variables
|
||||||
|
String[] data = andPattern.split( attributes );
|
||||||
|
for(String element : data){
|
||||||
|
tmp = equalPattern.split(element, 2);
|
||||||
|
map.put(
|
||||||
|
tmp[0].trim(), // Key
|
||||||
|
(tmp.length>1 ? tmp[1] : "").trim()); //Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the rest of the header
|
||||||
|
*
|
||||||
|
* @param line is the next line in the header
|
||||||
|
*/
|
||||||
|
protected void parseLine(String line){
|
||||||
|
String[] data = colonPattern.split( line, 2 );
|
||||||
|
attributes.put(
|
||||||
|
data[0].trim().toUpperCase(), // Key
|
||||||
|
(data.length>1 ? data[1] : "").trim()); //Value
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the attribute "Cookie" and returns a HashMap
|
||||||
|
* with the values
|
||||||
|
*
|
||||||
|
* @return a HashMap with cookie values
|
||||||
|
*/
|
||||||
|
protected void parseCookies(){
|
||||||
|
if( attributes.containsKey("COOKIE") ){
|
||||||
|
String[] tmp = semiColonPattern.split( attributes.get("COOKIE") );
|
||||||
|
String[] tmp2;
|
||||||
|
for(String cookie : tmp){
|
||||||
|
tmp2 = equalPattern.split(cookie, 2);
|
||||||
|
cookies.put(
|
||||||
|
tmp2[0].trim(), // Key
|
||||||
|
(tmp2.length>1 ? tmp2[1] : "").trim()); //Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the HTTP message type( ex. GET,POST...)
|
||||||
|
*/
|
||||||
|
public String getRequestType(){
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the HTTP version of this header
|
||||||
|
*/
|
||||||
|
public float getHTTPVersion(){
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the URL that the client sent the server
|
||||||
|
*/
|
||||||
|
public String getRequestURL(){
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the URL attribute value of the given name,
|
||||||
|
* returns null if there is no such attribute
|
||||||
|
*/
|
||||||
|
public String getURLAttribute(String name){
|
||||||
|
return url_attr.get( name );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the HTTP attribute value of the given name,
|
||||||
|
* returns null if there is no such attribute
|
||||||
|
*/
|
||||||
|
public String getHTTPAttribute(String name){
|
||||||
|
return attributes.get( name.toUpperCase() );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the cookie value of the given name,
|
||||||
|
* returns null if there is no such attribute
|
||||||
|
*/
|
||||||
|
public String getCookie(String name){
|
||||||
|
return cookies.get( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return athe parsed cookies
|
||||||
|
*/
|
||||||
|
public HashMap<String, String> getCookies(){
|
||||||
|
return cookies;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the parsed URL values
|
||||||
|
*/
|
||||||
|
public HashMap<String, String> getURLAttributes(){
|
||||||
|
return url_attr;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @return the parsed header attributes
|
||||||
|
*/
|
||||||
|
public HashMap<String, String> getAttributes(){
|
||||||
|
return attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String toString(){
|
||||||
|
StringBuffer tmp = new StringBuffer();
|
||||||
|
tmp.append("\nType: ");
|
||||||
|
tmp.append(type);
|
||||||
|
tmp.append("\nHTTP Version: HTTP/");
|
||||||
|
tmp.append(version);
|
||||||
|
|
||||||
|
tmp.append("\nURL: ");
|
||||||
|
tmp.append(url);
|
||||||
|
|
||||||
|
for( String key : url_attr.keySet() ){
|
||||||
|
tmp.append("\nURL Attr: ");
|
||||||
|
tmp.append(key);
|
||||||
|
tmp.append("=");
|
||||||
|
tmp.append( url_attr.get(key) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( String key : attributes.keySet() ){
|
||||||
|
tmp.append("\nHTTP Attr: ");
|
||||||
|
tmp.append(key);
|
||||||
|
tmp.append("=");
|
||||||
|
tmp.append( attributes.get(key) );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( String key : cookies.keySet() ){
|
||||||
|
tmp.append("\nCookie: ");
|
||||||
|
tmp.append(key);
|
||||||
|
tmp.append("=");
|
||||||
|
tmp.append( cookies.get(key) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return tmp.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -11,17 +11,51 @@ import java.util.HashMap;
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class HttpPrintStream extends PrintStream{
|
public class HttpPrintStream extends PrintStream{
|
||||||
private Integer status_code;
|
// Defines the type of message
|
||||||
private HashMap<String, String> header;
|
public enum HTTPMessageType{
|
||||||
private HashMap<String, String> cookie;
|
REQUEST,
|
||||||
private StringBuffer buffer;
|
RESPONSE
|
||||||
private boolean buffer_enabled;
|
}
|
||||||
|
|
||||||
|
// This defines the type of message that will be generated
|
||||||
|
private HTTPMessageType message_type;
|
||||||
|
// The status code of the message, ONLY for response
|
||||||
|
private Integer res_status_code;
|
||||||
|
// The request type of the message ONLY for request
|
||||||
|
private String req_type;
|
||||||
|
// The requesting url ONLY for request
|
||||||
|
private String req_url;
|
||||||
|
// An Map of all the header values
|
||||||
|
private HashMap<String, String> header;
|
||||||
|
// An Map of all the cookies
|
||||||
|
private HashMap<String, String> cookie;
|
||||||
|
// The buffered header
|
||||||
|
private StringBuffer buffer;
|
||||||
|
// If the header buffering is enabled
|
||||||
|
private boolean buffer_enabled;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an new instance of HttpPrintStream with
|
||||||
|
* message type of RESPONSE and buffering disabled.
|
||||||
|
*
|
||||||
|
* @param out is the OutputStream to send the message
|
||||||
|
*/
|
||||||
public HttpPrintStream(OutputStream out) {
|
public HttpPrintStream(OutputStream out) {
|
||||||
|
this( out, HTTPMessageType.RESPONSE );
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates an new instance of HttpPrintStream with
|
||||||
|
* message type buffering disabled.
|
||||||
|
*
|
||||||
|
* @param out is the OutputStream to send the message
|
||||||
|
* @param type is the type of message
|
||||||
|
*/
|
||||||
|
public HttpPrintStream(OutputStream out, HTTPMessageType type) {
|
||||||
super(out);
|
super(out);
|
||||||
|
|
||||||
status_code = 0;
|
this.message_type = type;
|
||||||
|
res_status_code = 0;
|
||||||
header = new HashMap<String, String>();
|
header = new HashMap<String, String>();
|
||||||
cookie = new HashMap<String, String>();
|
cookie = new HashMap<String, String>();
|
||||||
buffer = new StringBuffer();
|
buffer = new StringBuffer();
|
||||||
|
|
@ -49,9 +83,9 @@ public class HttpPrintStream extends PrintStream{
|
||||||
* @param value is the value of the cookie
|
* @param value is the value of the cookie
|
||||||
* @throws Exception Throws exception if the header has already been sent
|
* @throws Exception Throws exception if the header has already been sent
|
||||||
*/
|
*/
|
||||||
public void setCookie(String key, String value) throws Exception{
|
public void setCookie(String key, String value) throws RuntimeException{
|
||||||
if(cookie == null)
|
if(cookie == null)
|
||||||
throw new Exception("Header already sent!!!");
|
throw new RuntimeException("Header already sent!!!");
|
||||||
cookie.put(key, value);
|
cookie.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -62,22 +96,51 @@ public class HttpPrintStream extends PrintStream{
|
||||||
* @param value is the value of the header
|
* @param value is the value of the header
|
||||||
* @throws Exception Throws exception if the header has already been sent
|
* @throws Exception Throws exception if the header has already been sent
|
||||||
*/
|
*/
|
||||||
public void setHeader(String key, String value) throws Exception{
|
public void setHeader(String key, String value) throws RuntimeException{
|
||||||
if(header == null)
|
if(header == null)
|
||||||
throw new Exception("Header already sent!!!");
|
throw new RuntimeException("Header already sent!!!");
|
||||||
header.put(key, value);
|
header.put(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the return status code
|
* Sets the status code of the message, ONLY available in HTTP RESPONSE
|
||||||
*
|
*
|
||||||
* @param code the code from 100 up to 599
|
* @param code the code from 100 up to 599
|
||||||
* @throws Exception Throws exception if the header has already been sent
|
* @throws RuntimeException if the header has already been sent or the message type is wrong
|
||||||
*/
|
*/
|
||||||
public void setStatusCode(int code) throws Exception{
|
public void setStatusCode(int code) throws RuntimeException{
|
||||||
if(status_code == null)
|
if( res_status_code == null )
|
||||||
throw new Exception("Header already sent!!!");
|
throw new RuntimeException("Header already sent!!!");
|
||||||
status_code = code;
|
if( message_type != HTTPMessageType.RESPONSE )
|
||||||
|
throw new RuntimeException("Status Code is only available in HTTP RESPONSE!!!");
|
||||||
|
res_status_code = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the request type of the message, ONLY available in HTTP REQUEST
|
||||||
|
*
|
||||||
|
* @param req_type is the type of the message, e.g. GET, POST...
|
||||||
|
* @throws RuntimeException if the header has already been sent or the message type is wrong
|
||||||
|
*/
|
||||||
|
public void setRequestType(String req_type) throws RuntimeException{
|
||||||
|
if( req_type == null )
|
||||||
|
throw new RuntimeException("Header already sent!!!");
|
||||||
|
if( message_type != HTTPMessageType.REQUEST )
|
||||||
|
throw new RuntimeException("Request Message Type is only available in HTTP REQUEST!!!");
|
||||||
|
this.req_type = req_type;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Sets the requesting URL of the message, ONLY available in HTTP REQUEST
|
||||||
|
*
|
||||||
|
* @param req_url is the URL
|
||||||
|
* @throws RuntimeException if the header has already been sent or the message type is wrong
|
||||||
|
*/
|
||||||
|
public void setRequestURL(String req_url) throws RuntimeException{
|
||||||
|
if( req_url == null )
|
||||||
|
throw new RuntimeException("Header already sent!!!");
|
||||||
|
if( message_type != HTTPMessageType.REQUEST )
|
||||||
|
throw new RuntimeException("Request URL is only available in HTTP REQUEST!!!");
|
||||||
|
this.req_url = req_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -102,10 +165,15 @@ public class HttpPrintStream extends PrintStream{
|
||||||
buffer.append(s);
|
buffer.append(s);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
if(status_code != null){
|
if(res_status_code != null){
|
||||||
super.print("HTTP/1.0 "+status_code+" "+getStatusString(status_code));
|
if( message_type==HTTPMessageType.REQUEST )
|
||||||
|
super.print(req_type+" "+req_url+" HTTP/1.1");
|
||||||
|
else
|
||||||
|
super.print("HTTP/1.1 "+res_status_code+" "+getStatusString(res_status_code));
|
||||||
super.println();
|
super.println();
|
||||||
status_code = null;
|
res_status_code = null;
|
||||||
|
req_type = null;
|
||||||
|
req_url = null;
|
||||||
}
|
}
|
||||||
if(header != null){
|
if(header != null){
|
||||||
for(String key : header.keySet()){
|
for(String key : header.keySet()){
|
||||||
|
|
@ -115,9 +183,20 @@ public class HttpPrintStream extends PrintStream{
|
||||||
header = null;
|
header = null;
|
||||||
}
|
}
|
||||||
if(cookie != null){
|
if(cookie != null){
|
||||||
for(String key : cookie.keySet()){
|
if( !cookie.isEmpty() ){
|
||||||
super.print("Set-Cookie: "+key+"="+cookie.get(key)+";");
|
if( message_type==HTTPMessageType.REQUEST ){
|
||||||
super.println();
|
super.print("Cookie: ");
|
||||||
|
for(String key : cookie.keySet()){
|
||||||
|
super.print(key+"="+cookie.get(key)+"; ");
|
||||||
|
}
|
||||||
|
super.println();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for(String key : cookie.keySet()){
|
||||||
|
super.print("Set-Cookie: "+key+"="+cookie.get(key)+";");
|
||||||
|
super.println();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
super.println();
|
super.println();
|
||||||
cookie = null;
|
cookie = null;
|
||||||
|
|
@ -136,7 +215,7 @@ public class HttpPrintStream extends PrintStream{
|
||||||
buffer.delete(0, buffer.length());
|
buffer.delete(0, buffer.length());
|
||||||
buffer_enabled = true;
|
buffer_enabled = true;
|
||||||
}
|
}
|
||||||
else if(status_code != null || header != null || cookie != null){
|
else if(res_status_code != null || header != null || cookie != null){
|
||||||
printOrBuffer("");
|
printOrBuffer("");
|
||||||
}
|
}
|
||||||
super.flush();
|
super.flush();
|
||||||
|
|
@ -165,7 +244,7 @@ public class HttpPrintStream extends PrintStream{
|
||||||
public void print(int x){ printOrBuffer(String.valueOf(x));}
|
public void print(int x){ printOrBuffer(String.valueOf(x));}
|
||||||
public void print(long x){ printOrBuffer(String.valueOf(x));}
|
public void print(long x){ printOrBuffer(String.valueOf(x));}
|
||||||
public void print(Object x){ printOrBuffer(String.valueOf(x));}
|
public void print(Object x){ printOrBuffer(String.valueOf(x));}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
public void write(int b) { print((char)b);}
|
public void write(int b) { print((char)b);}
|
||||||
public void write(byte buf[], int off, int len){
|
public void write(byte buf[], int off, int len){
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,16 @@ import java.io.BufferedReader;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.security.KeyStoreException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.NoSuchProviderException;
|
|
||||||
import java.security.cert.CertificateException;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import javax.net.ssl.SSLServerSocketFactory;
|
|
||||||
|
|
||||||
import zutil.MultiPrintStream;
|
import zutil.MultiPrintStream;
|
||||||
|
import zutil.network.threaded.ThreadedTCPNetworkServer;
|
||||||
|
import zutil.network.threaded.ThreadedTCPNetworkServerThread;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,7 +22,7 @@ import zutil.MultiPrintStream;
|
||||||
*
|
*
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*/
|
*/
|
||||||
public class HttpServer extends Thread{
|
public class HttpServer extends ThreadedTCPNetworkServer{
|
||||||
public static final boolean DEBUG = false;
|
public static final boolean DEBUG = false;
|
||||||
public static final String SERVER_VERSION = "StaticInt HttpServer 1.0";
|
public static final String SERVER_VERSION = "StaticInt HttpServer 1.0";
|
||||||
public static final int COOKIE_TTL = 200;
|
public static final int COOKIE_TTL = 200;
|
||||||
|
|
@ -36,8 +30,6 @@ public class HttpServer extends Thread{
|
||||||
|
|
||||||
public final String server_url;
|
public final String server_url;
|
||||||
public final int server_port;
|
public final int server_port;
|
||||||
private File keyStore;
|
|
||||||
private String keyStorePass;
|
|
||||||
|
|
||||||
private HashMap<String,HttpPage> pages;
|
private HashMap<String,HttpPage> pages;
|
||||||
private HttpPage defaultPage;
|
private HttpPage defaultPage;
|
||||||
|
|
@ -64,10 +56,9 @@ public class HttpServer extends Thread{
|
||||||
* @param sslCert If this is not null then the server will use a SSL connection with the given certificate
|
* @param sslCert If this is not null then the server will use a SSL connection with the given certificate
|
||||||
*/
|
*/
|
||||||
public HttpServer(String url, int port, File keyStore, String keyStorePass){
|
public HttpServer(String url, int port, File keyStore, String keyStorePass){
|
||||||
|
super( port, keyStore, keyStorePass );
|
||||||
this.server_url = url;
|
this.server_url = url;
|
||||||
this.server_port = port;
|
this.server_port = port;
|
||||||
this.keyStorePass = keyStorePass;
|
|
||||||
this.keyStore = keyStore;
|
|
||||||
|
|
||||||
pages = new HashMap<String,HttpPage>();
|
pages = new HashMap<String,HttpPage>();
|
||||||
sessions = Collections.synchronizedMap(new HashMap<String,Map<String,Object>>());
|
sessions = Collections.synchronizedMap(new HashMap<String,Map<String,Object>>());
|
||||||
|
|
@ -75,6 +66,8 @@ public class HttpServer extends Thread{
|
||||||
|
|
||||||
Timer timer = new Timer();
|
Timer timer = new Timer();
|
||||||
timer.schedule(new GarbageCollector(), 0, SESSION_TTL / 2);
|
timer.schedule(new GarbageCollector(), 0, SESSION_TTL / 2);
|
||||||
|
|
||||||
|
MultiPrintStream.out.println("HTTP"+(keyStore==null?"":"S")+" Server ready!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -119,49 +112,13 @@ public class HttpServer extends Thread{
|
||||||
defaultPage = page;
|
defaultPage = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(){
|
protected ThreadedTCPNetworkServerThread getThreadInstance( Socket s ){
|
||||||
try{
|
try {
|
||||||
ServerSocket ss;
|
return new HttpServerThread( s );
|
||||||
if(keyStorePass != null && keyStore != null){
|
} catch (IOException e) {
|
||||||
registerCertificate(keyStore, keyStorePass);
|
e.printStackTrace( MultiPrintStream.out );
|
||||||
ss = initSSL(server_port);
|
|
||||||
MultiPrintStream.out.println("Https Server Running!!!");
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
ss = new ServerSocket(server_port);
|
|
||||||
MultiPrintStream.out.println("Http Server Running!!!");
|
|
||||||
}
|
|
||||||
|
|
||||||
while(true){
|
|
||||||
new HttpServerThread(ss.accept());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
}
|
||||||
}
|
return null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates a SSLServerSocket
|
|
||||||
*
|
|
||||||
* @param port The port to listen to
|
|
||||||
* @return The SSLServerSocket
|
|
||||||
* @throws IOException
|
|
||||||
*/
|
|
||||||
private ServerSocket initSSL(int port) throws IOException{
|
|
||||||
SSLServerSocketFactory sslserversocketfactory =
|
|
||||||
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
|
||||||
return sslserversocketfactory.createServerSocket(port);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers the given cert file to the KeyStore
|
|
||||||
*
|
|
||||||
* @param certFile The cert file
|
|
||||||
*/
|
|
||||||
protected void registerCertificate(File keyStore, String keyStorePass) throws CertificateException, IOException, KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException{
|
|
||||||
System.setProperty("javax.net.ssl.keyStore", keyStore.getAbsolutePath());
|
|
||||||
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -170,7 +127,7 @@ public class HttpServer extends Thread{
|
||||||
* @author Ziver
|
* @author Ziver
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class HttpServerThread extends Thread{
|
protected class HttpServerThread implements ThreadedTCPNetworkServerThread{
|
||||||
private HttpPrintStream out;
|
private HttpPrintStream out;
|
||||||
private BufferedReader in;
|
private BufferedReader in;
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
|
|
@ -179,16 +136,11 @@ public class HttpServer extends Thread{
|
||||||
out = new HttpPrintStream(socket.getOutputStream());
|
out = new HttpPrintStream(socket.getOutputStream());
|
||||||
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
|
||||||
this.socket = socket;
|
this.socket = socket;
|
||||||
start();
|
if(DEBUG) MultiPrintStream.out.println("New Connection!!! "+socket.getInetAddress().getHostName());
|
||||||
if(DEBUG)MultiPrintStream.out.println("New Connection!!! "+socket.getInetAddress().getHostName());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void run(){
|
public void run(){
|
||||||
String tmp = null;
|
String tmp = null;
|
||||||
String[] tmpArray, tmpArray2;
|
|
||||||
Pattern colonPattern = Pattern.compile(":");
|
|
||||||
Pattern semiColonPattern = Pattern.compile(";");
|
|
||||||
Pattern equalPattern = Pattern.compile("=");
|
|
||||||
|
|
||||||
String page_url = "";
|
String page_url = "";
|
||||||
HashMap<String,String> client_info = new HashMap<String,String>();
|
HashMap<String,String> client_info = new HashMap<String,String>();
|
||||||
|
|
@ -197,45 +149,19 @@ public class HttpServer extends Thread{
|
||||||
|
|
||||||
//**************************** REQUEST *********************************
|
//**************************** REQUEST *********************************
|
||||||
try {
|
try {
|
||||||
if(DEBUG)MultiPrintStream.out.println("Reciving Http Request!!!");
|
if(DEBUG) MultiPrintStream.out.println("Reciving Http Request!!!");
|
||||||
while((tmp=in.readLine()) != null && !tmp.isEmpty()){
|
|
||||||
//System.err.println(tmp);
|
HTTPHeaderParser parser = new HTTPHeaderParser(in);
|
||||||
//*********** Handling Get variables
|
if(DEBUG) MultiPrintStream.out.println(parser);
|
||||||
if(tmp.startsWith("GET")){
|
client_info = parser.getAttributes();
|
||||||
// Gets the file URL and get values
|
request = parser.getURLAttributes();
|
||||||
tmp = (tmp.substring(5, tmp.indexOf("HTTP/"))).trim();
|
cookie = parser.getCookies();
|
||||||
page_url = parseHttpHeader(tmp, request);
|
|
||||||
}
|
|
||||||
//********* Handling Post variable data
|
|
||||||
else if(tmp.startsWith("POST")){
|
|
||||||
// Gets the file URL and get values
|
|
||||||
tmp = (tmp.substring(6, tmp.indexOf("HTTP/"))).trim();
|
|
||||||
page_url = parseHttpHeader(tmp, request);
|
|
||||||
}
|
|
||||||
//********* Handling Cookies
|
|
||||||
else if(tmp.startsWith("Cookie")){
|
|
||||||
tmp = colonPattern.split(tmp)[1];
|
|
||||||
tmpArray = semiColonPattern.split(tmp);
|
|
||||||
for(String e : tmpArray){
|
|
||||||
tmpArray2 = equalPattern.split(e);
|
|
||||||
cookie.put(
|
|
||||||
tmpArray2[0].trim(), // Key
|
|
||||||
(tmpArray2.length>1 ? tmpArray2[1] : "").trim()); //Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//********* Handling Client info
|
|
||||||
else{
|
|
||||||
tmpArray = colonPattern.split(tmp);
|
|
||||||
client_info.put(
|
|
||||||
tmpArray[0].trim(), // Key
|
|
||||||
(tmpArray.length>1 ? tmpArray[1] : "").trim()); //Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//******* Read in the post data if available
|
//******* Read in the post data if available
|
||||||
if(client_info.containsKey("Content-Length")){
|
if( parser.getHTTPAttribute("Content-Length")!=null ){
|
||||||
// Reads the post data size
|
// Reads the post data size
|
||||||
tmp = client_info.get("Content-Length");
|
tmp = parser.getHTTPAttribute("Content-Length");
|
||||||
int post_data_length = Integer.parseInt( tmp );
|
int post_data_length = Integer.parseInt( tmp );
|
||||||
// read the data
|
// read the data
|
||||||
StringBuffer tmpb = new StringBuffer();
|
StringBuffer tmpb = new StringBuffer();
|
||||||
|
|
@ -244,19 +170,20 @@ public class HttpServer extends Thread{
|
||||||
tmpb.append((char)in.read());
|
tmpb.append((char)in.read());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(client_info.get("Content-Type").contains("application/x-www-form-urlencoded")){
|
tmp = parser.getHTTPAttribute("Content-Type");
|
||||||
|
if( tmp.contains("application/x-www-form-urlencoded") ){
|
||||||
// get the variables
|
// get the variables
|
||||||
parseVariables(tmpb.toString(), request);
|
HTTPHeaderParser.parseUrlAttributes( tmpb.toString(), request );
|
||||||
}
|
}
|
||||||
else if(client_info.get("Content-Type").contains("application/soap+xml") ||
|
else if( tmp.contains("application/soap+xml" ) ||
|
||||||
client_info.get("Content-Type").contains("text/xml") ||
|
tmp.contains("text/xml") ||
|
||||||
client_info.get("Content-Type").contains("text/plain")){
|
tmp.contains("text/plain") ){
|
||||||
// save the variables
|
// save the variables
|
||||||
request.put("" , tmpb.toString());
|
request.put( "" , tmpb.toString() );
|
||||||
}
|
}
|
||||||
else if(client_info.get("Content-Type").contains("multipart/form-data")){
|
else if( tmp.contains("multipart/form-data") ){
|
||||||
// TODO: File upload
|
// TODO: File upload
|
||||||
throw new Exception("\"multipart-form-data\" Not implemented!!!");
|
throw new Exception( "\"multipart-form-data\" Not implemented!!!" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -264,118 +191,71 @@ public class HttpServer extends Thread{
|
||||||
// Get the client session or create one
|
// Get the client session or create one
|
||||||
Map<String, Object> client_session;
|
Map<String, Object> client_session;
|
||||||
long ttl_time = System.currentTimeMillis()+SESSION_TTL;
|
long ttl_time = System.currentTimeMillis()+SESSION_TTL;
|
||||||
if(cookie.containsKey("session_id") && sessions.containsKey(cookie.get("session_id"))){
|
if( cookie.containsKey("session_id") && sessions.containsKey(cookie.get("session_id")) ){
|
||||||
client_session = sessions.get(cookie.get("session_id"));
|
client_session = sessions.get( cookie.get("session_id") );
|
||||||
// Check if session is still valid
|
// Check if session is still valid
|
||||||
if((Long)client_session.get("ttl") < System.currentTimeMillis()){
|
if( (Long)client_session.get("ttl") < System.currentTimeMillis() ){
|
||||||
int session_id = (Integer)client_session.get("session_id");
|
int session_id = (Integer)client_session.get("session_id");
|
||||||
client_session = Collections.synchronizedMap(new HashMap<String, Object>());
|
client_session = Collections.synchronizedMap(new HashMap<String, Object>());
|
||||||
client_session.put("session_id", session_id);
|
client_session.put( "session_id", session_id);
|
||||||
sessions.put(""+session_id, client_session);
|
sessions.put( ""+session_id, client_session);
|
||||||
}
|
}
|
||||||
// renew the session TTL
|
// renew the session TTL
|
||||||
client_session.put("ttl", ttl_time);
|
client_session.put( "ttl", ttl_time );
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
client_session = Collections.synchronizedMap(new HashMap<String, Object>());
|
client_session = Collections.synchronizedMap(new HashMap<String, Object>());
|
||||||
client_session.put("session_id", nextSessionId);
|
client_session.put( "session_id", nextSessionId );
|
||||||
client_session.put("ttl", ttl_time);
|
client_session.put( "ttl", ttl_time );
|
||||||
sessions.put(""+nextSessionId, client_session);
|
sessions.put( ""+nextSessionId, client_session );
|
||||||
nextSessionId++;
|
nextSessionId++;
|
||||||
}
|
}
|
||||||
// Debug
|
// Debug
|
||||||
if(DEBUG){
|
if(DEBUG){
|
||||||
MultiPrintStream.out.println("# page_url: "+page_url);
|
MultiPrintStream.out.println( "# page_url: "+page_url );
|
||||||
MultiPrintStream.out.println("# cookie: "+cookie);
|
MultiPrintStream.out.println( "# cookie: "+cookie );
|
||||||
MultiPrintStream.out.println("# client_session: "+client_session);
|
MultiPrintStream.out.println( "# client_session: "+client_session );
|
||||||
MultiPrintStream.out.println("# client_info: "+client_info);
|
MultiPrintStream.out.println( "# client_info: "+client_info );
|
||||||
MultiPrintStream.out.println("# request: "+request);
|
MultiPrintStream.out.println( "# request: "+request );
|
||||||
}
|
}
|
||||||
//**************************** RESPONSE ************************************
|
//**************************** RESPONSE ************************************
|
||||||
if(DEBUG)MultiPrintStream.out.println("Sending Http Response!!!");
|
if(DEBUG) MultiPrintStream.out.println("Sending Http Response!!!");
|
||||||
out.setStatusCode(200);
|
out.setStatusCode(200);
|
||||||
out.setHeader("Server", SERVER_VERSION);
|
out.setHeader( "Server", SERVER_VERSION );
|
||||||
out.setHeader("Content-Type", "text/html");
|
out.setHeader( "Content-Type", "text/html" );
|
||||||
out.setCookie("session_id", ""+client_session.get("session_id"));
|
out.setCookie( "session_id", ""+client_session.get("session_id") );
|
||||||
|
|
||||||
if(!page_url.isEmpty() && pages.containsKey(page_url)){
|
if( !page_url.isEmpty() && pages.containsKey(page_url) ){
|
||||||
pages.get(page_url).respond(out, client_info, client_session, cookie, request);
|
pages.get(page_url).respond(out, client_info, client_session, cookie, request);
|
||||||
}
|
}
|
||||||
else if(defaultPage != null){
|
else if( defaultPage != null ){
|
||||||
defaultPage.respond(out, client_info, client_session, cookie, request);
|
defaultPage.respond(out, client_info, client_session, cookie, request);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
out.setStatusCode(404);
|
out.setStatusCode( 404 );
|
||||||
out.println("404 Page Not Found");
|
out.println( "404 Page Not Found" );
|
||||||
}
|
}
|
||||||
|
|
||||||
//********************************************************************************
|
//********************************************************************************
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace(MultiPrintStream.out);
|
e.printStackTrace( MultiPrintStream.out );
|
||||||
try {
|
try {
|
||||||
out.setStatusCode(500);
|
out.setStatusCode( 500 );
|
||||||
} catch (Exception e1) {}
|
} catch (Exception e1) {}
|
||||||
if(e.getMessage() != null)
|
if(e.getMessage() != null)
|
||||||
out.println("500 Internal Server Error(Header: "+tmp+"): "+e.getMessage());
|
out.println( "500 Internal Server Error: "+e.getMessage() );
|
||||||
else{
|
else{
|
||||||
out.println("500 Internal Server Error(Header: "+tmp+"): "+e.getCause().getMessage());
|
out.println( "500 Internal Server Error: "+e.getCause().getMessage() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try{
|
try{
|
||||||
if(DEBUG)MultiPrintStream.out.println("Conection Closed!!!");
|
if(DEBUG) MultiPrintStream.out.println("Conection Closed!!!");
|
||||||
out.close();
|
out.close();
|
||||||
in.close();
|
in.close();
|
||||||
socket.close();
|
socket.close();
|
||||||
} catch (Exception e) {
|
} catch( Exception e ) {
|
||||||
e.printStackTrace(MultiPrintStream.out);
|
e.printStackTrace( MultiPrintStream.out );
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses the first header line and ads the values to
|
|
||||||
* the map and returns the file name and path
|
|
||||||
*
|
|
||||||
* @param header The header String
|
|
||||||
* @param map The HashMap to put the variables to
|
|
||||||
* @return The path and file name as a String
|
|
||||||
*/
|
|
||||||
private String parseHttpHeader(String header, HashMap<String, String> map){
|
|
||||||
String page_url = "";
|
|
||||||
// cut out the page name
|
|
||||||
if(header.indexOf('?') > -1){
|
|
||||||
page_url = header.substring(0, header.indexOf('?'));
|
|
||||||
header = header.substring(header.indexOf('?')+1, header.length());
|
|
||||||
parseVariables(header, map);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
page_url = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
return page_url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a String with variables from a get or post
|
|
||||||
* from a client and puts the data into a HashMap
|
|
||||||
*
|
|
||||||
* @param header A String with all the variables
|
|
||||||
* @param map The HashMap to put all the variables into
|
|
||||||
*/
|
|
||||||
private void parseVariables(String header, HashMap<String, String> map){
|
|
||||||
int tmp;
|
|
||||||
// get the variables
|
|
||||||
String[] data = header.split("&");
|
|
||||||
for(String element : data){
|
|
||||||
tmp = element.indexOf('=');
|
|
||||||
if(tmp > 0){
|
|
||||||
map.put(
|
|
||||||
element.substring(0, tmp ).trim(), // Key
|
|
||||||
element.substring(tmp+1, element.length() ).trim() ); //Value
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
map.put(element, "");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ public abstract class NioNetwork implements Runnable {
|
||||||
* 2 = message debug
|
* 2 = message debug
|
||||||
* 3 = selector debug
|
* 3 = selector debug
|
||||||
*/
|
*/
|
||||||
public static int DEBUG = 2;
|
public static final int DEBUG = 2;
|
||||||
public static enum NetworkType {SERVER, CLIENT};
|
public static enum NetworkType {SERVER, CLIENT};
|
||||||
|
|
||||||
private NetworkType type;
|
private NetworkType type;
|
||||||
|
|
|
||||||
115
src/zutil/network/threaded/ThreadedTCPNetworkServer.java
Normal file
115
src/zutil/network/threaded/ThreadedTCPNetworkServer.java
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
package zutil.network.threaded;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.security.KeyStoreException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
|
||||||
|
import javax.net.ssl.SSLServerSocketFactory;
|
||||||
|
|
||||||
|
import zutil.MultiPrintStream;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple web server that handles both cookies and
|
||||||
|
* sessions for all the clients
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public abstract class ThreadedTCPNetworkServer extends Thread{
|
||||||
|
public final int port;
|
||||||
|
private File keyStore;
|
||||||
|
private String keyStorePass;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the sever
|
||||||
|
*
|
||||||
|
* @param port The port that the server should listen to
|
||||||
|
*/
|
||||||
|
public ThreadedTCPNetworkServer(int port){
|
||||||
|
this(port, null, null);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Creates a new instance of the sever
|
||||||
|
*
|
||||||
|
* @param port The port that the server should listen to
|
||||||
|
* @param sslCert If this is not null then the server will use SSL connection with this keyStore file path
|
||||||
|
* @param sslCert If this is not null then the server will use a SSL connection with the given certificate
|
||||||
|
*/
|
||||||
|
public ThreadedTCPNetworkServer(int port, File keyStore, String keyStorePass){
|
||||||
|
this.port = port;
|
||||||
|
this.keyStorePass = keyStorePass;
|
||||||
|
this.keyStore = keyStore;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
ServerSocket ss = null;
|
||||||
|
try{
|
||||||
|
if(keyStorePass != null && keyStore != null){
|
||||||
|
registerCertificate(keyStore, keyStorePass);
|
||||||
|
ss = initSSL( port );
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ss = new ServerSocket( port );
|
||||||
|
}
|
||||||
|
|
||||||
|
while(true){
|
||||||
|
Socket s = ss.accept();
|
||||||
|
ThreadedTCPNetworkServerThread t = getThreadInstance( s );
|
||||||
|
if( t!=null )
|
||||||
|
new Thread( t ).start();
|
||||||
|
else{
|
||||||
|
MultiPrintStream.out.println("Unable to instantiate ThreadedTCPNetworkServerThread, closing connection!");
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
e.printStackTrace( MultiPrintStream.out );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( ss!=null ){
|
||||||
|
try{
|
||||||
|
ss.close();
|
||||||
|
}catch(IOException e){ e.printStackTrace( MultiPrintStream.out ); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns an new instance of the ThreadedTCPNetworkServerThread
|
||||||
|
* that will handle the newly made connection, if an null value is returned
|
||||||
|
* then the ThreadedTCPNetworkServer will close the new connection.
|
||||||
|
*
|
||||||
|
* @param s is an new connection to an host
|
||||||
|
* @return a new instance of an thread or null
|
||||||
|
*/
|
||||||
|
protected abstract ThreadedTCPNetworkServerThread getThreadInstance( Socket s );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initiates a SSLServerSocket
|
||||||
|
*
|
||||||
|
* @param port The port to listen to
|
||||||
|
* @return The SSLServerSocket
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
private ServerSocket initSSL(int port) throws IOException{
|
||||||
|
SSLServerSocketFactory sslserversocketfactory =
|
||||||
|
(SSLServerSocketFactory) SSLServerSocketFactory.getDefault();
|
||||||
|
return sslserversocketfactory.createServerSocket(port);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers the given cert file to the KeyStore
|
||||||
|
*
|
||||||
|
* @param certFile The cert file
|
||||||
|
*/
|
||||||
|
protected void registerCertificate(File keyStore, String keyStorePass) throws CertificateException, IOException, KeyStoreException, NoSuchProviderException, NoSuchAlgorithmException{
|
||||||
|
System.setProperty("javax.net.ssl.keyStore", keyStore.getAbsolutePath());
|
||||||
|
System.setProperty("javax.net.ssl.keyStorePassword", keyStorePass);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
package zutil.network.threaded;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class that will handle the TCP connection will incclude
|
||||||
|
* this interface
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ThreadedTCPNetworkServerThread extends Runnable{
|
||||||
|
|
||||||
|
}
|
||||||
103
src/zutil/network/threaded/ThreadedUDPNetwork.java
Normal file
103
src/zutil/network/threaded/ThreadedUDPNetwork.java
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
package zutil.network.threaded;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
import java.net.DatagramSocket;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.net.MulticastSocket;
|
||||||
|
import java.net.SocketException;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple web server that handles both cookies and
|
||||||
|
* sessions for all the clients
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*/
|
||||||
|
public class ThreadedUDPNetwork extends Thread{
|
||||||
|
public static final int BUFFER_SIZE = 512;
|
||||||
|
|
||||||
|
// Type of UDP socket
|
||||||
|
enum UDPType{
|
||||||
|
MULTICAST,
|
||||||
|
UNICAST
|
||||||
|
}
|
||||||
|
protected final UDPType type;
|
||||||
|
protected final int port;
|
||||||
|
protected DatagramSocket socket;
|
||||||
|
protected ThreadedUDPNetworkThread thread = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new unicast instance of the sever
|
||||||
|
*
|
||||||
|
* @param thread is the class that will handle incoming packets
|
||||||
|
* @param port is the port that the server should listen to
|
||||||
|
* @throws SocketException
|
||||||
|
*/
|
||||||
|
public ThreadedUDPNetwork(ThreadedUDPNetworkThread thread, int port) throws SocketException{
|
||||||
|
this.type = UDPType.UNICAST;
|
||||||
|
this.port = port;
|
||||||
|
setThread( thread );
|
||||||
|
|
||||||
|
socket = new DatagramSocket( port );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new multicast instance of the sever
|
||||||
|
*
|
||||||
|
* @param thread is the class that will handle incoming packets
|
||||||
|
* @param port is the port that the server should listen to
|
||||||
|
* @param multicast_addr is the multicast address that the server will listen on
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public ThreadedUDPNetwork(ThreadedUDPNetworkThread thread, int port, String multicast_addr ) throws IOException{
|
||||||
|
this.type = UDPType.MULTICAST;
|
||||||
|
this.port = port;
|
||||||
|
setThread( thread );
|
||||||
|
|
||||||
|
// init udp socket
|
||||||
|
MulticastSocket msocket = new MulticastSocket( port );
|
||||||
|
InetAddress group = InetAddress.getByName( multicast_addr );
|
||||||
|
msocket.joinGroup( group );
|
||||||
|
|
||||||
|
socket = msocket;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void run(){
|
||||||
|
try{
|
||||||
|
while(true){
|
||||||
|
byte[] buf = new byte[BUFFER_SIZE];
|
||||||
|
DatagramPacket packet = new DatagramPacket(buf, buf.length);
|
||||||
|
socket.receive( packet );
|
||||||
|
if( thread!=null )
|
||||||
|
thread.receivedPacket( packet, this );
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends the given packet
|
||||||
|
*
|
||||||
|
* @param packet is the packet to send
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
public synchronized void send( DatagramPacket packet ) throws IOException{
|
||||||
|
socket.send(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the thread that will handle the incoming packets
|
||||||
|
*
|
||||||
|
* @param thread is the thread
|
||||||
|
*/
|
||||||
|
public void setThread(ThreadedUDPNetworkThread thread){
|
||||||
|
this.thread = thread;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
21
src/zutil/network/threaded/ThreadedUDPNetworkThread.java
Normal file
21
src/zutil/network/threaded/ThreadedUDPNetworkThread.java
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
package zutil.network.threaded;
|
||||||
|
|
||||||
|
import java.net.DatagramPacket;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is for processing received packets
|
||||||
|
* from the TNetworkUDPServer
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface ThreadedUDPNetworkThread extends Runnable{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Packet will be processed in this method
|
||||||
|
*
|
||||||
|
* @param packet is the received packet
|
||||||
|
* @param network is the network class that received the packet
|
||||||
|
*/
|
||||||
|
public void receivedPacket(DatagramPacket packet, ThreadedUDPNetwork network);
|
||||||
|
}
|
||||||
105
src/zutil/struct/HistoryList.java
Normal file
105
src/zutil/struct/HistoryList.java
Normal file
|
|
@ -0,0 +1,105 @@
|
||||||
|
package zutil.struct;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
|
||||||
|
public class HistoryList<T> implements Iterable<T>{
|
||||||
|
public int history_length;
|
||||||
|
private LinkedList<T> history;
|
||||||
|
private int historyIndex = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an HistoryList object
|
||||||
|
*/
|
||||||
|
public HistoryList(){
|
||||||
|
this( Integer.MAX_VALUE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an HistoryList object with an max size
|
||||||
|
*
|
||||||
|
* @param histlength the maximum size of the list
|
||||||
|
*/
|
||||||
|
public HistoryList(int histlength){
|
||||||
|
history_length = histlength;
|
||||||
|
history = new LinkedList<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the item in the given index
|
||||||
|
*
|
||||||
|
* @param i is the index
|
||||||
|
* @return item in that index
|
||||||
|
*/
|
||||||
|
public T get(int i){
|
||||||
|
return history.get( i );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an item to the list and removes the last if
|
||||||
|
* the list is bigger than the max length.
|
||||||
|
*
|
||||||
|
* @param item is the item to add
|
||||||
|
*/
|
||||||
|
public void add(T item){
|
||||||
|
while(historyIndex < history.size()-1){
|
||||||
|
history.removeLast();
|
||||||
|
}
|
||||||
|
history.addLast(item);
|
||||||
|
if(history_length < history.size()){
|
||||||
|
history.removeFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
historyIndex = history.size()-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the previous item in the list
|
||||||
|
*/
|
||||||
|
public T getPrevious(){
|
||||||
|
if(historyIndex > 0){
|
||||||
|
historyIndex -= 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
historyIndex = 0;
|
||||||
|
}
|
||||||
|
return history.get(historyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the next item in the list
|
||||||
|
*/
|
||||||
|
public T getNext(){
|
||||||
|
if(next()){
|
||||||
|
historyIndex += 1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
historyIndex = history.size()-1;
|
||||||
|
}
|
||||||
|
return history.get(historyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getCurrent(){
|
||||||
|
return history.get(historyIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return if there are items newer than the current
|
||||||
|
*/
|
||||||
|
public boolean next(){
|
||||||
|
if(historyIndex < history.size()-1){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return an iterator of the list
|
||||||
|
*/
|
||||||
|
public Iterator<T> iterator(){
|
||||||
|
return history.iterator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,7 @@ package zutil.test;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
import java.util.ArrayList;
|
import java.util.List;
|
||||||
|
|
||||||
import zutil.FileFinder;
|
import zutil.FileFinder;
|
||||||
import zutil.Hasher;
|
import zutil.Hasher;
|
||||||
|
|
@ -12,7 +12,7 @@ public class FileFinderHasherTest {
|
||||||
String relativePath = "zutil/test";
|
String relativePath = "zutil/test";
|
||||||
|
|
||||||
File path = FileFinder.find(relativePath);
|
File path = FileFinder.find(relativePath);
|
||||||
ArrayList<File> files = FileFinder.search(path);
|
List<File> files = FileFinder.search(path);
|
||||||
for(int i=0; i<files.size(); i++){
|
for(int i=0; i<files.size(); i++){
|
||||||
try {
|
try {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
|
|
|
||||||
45
src/zutil/wrapper/StringOutputStream.java
Normal file
45
src/zutil/wrapper/StringOutputStream.java
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
package zutil.wrapper;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class saves all the input data in to an StringBuffer
|
||||||
|
*
|
||||||
|
* @author Ziver
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class StringOutputStream extends OutputStream{
|
||||||
|
// The buffer
|
||||||
|
protected StringBuffer buffer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an new instance of this class
|
||||||
|
*/
|
||||||
|
public StringOutputStream(){
|
||||||
|
buffer = new StringBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
buffer.append( b );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b) {
|
||||||
|
buffer.append( new String(b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) {
|
||||||
|
buffer.append( new String(b, off, len) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the String with the data
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue