Files
secondo/Javagui/viewer/hoese/Dsplexternal.java
2026-01-23 17:03:45 +08:00

343 lines
10 KiB
Java

//This file is part of SECONDO.
//Copyright (C) 2004, University in Hagen, Department of Computer Science,
//Database Systems for New Applications.
//SECONDO is free software; you can redistribute it and/or modify
//it under the terms of the GNU General Public License as published by
//the Free Software Foundation; either version 2 of the License, or
//(at your option) any later version.
//SECONDO is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//You should have received a copy of the GNU General Public License
//along with SECONDO; if not, write to the Free Software
//Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package viewer.hoese;
import java.io.*;
import javax.swing.*;
import sj.lang.ListExpr;
import viewer.HoeseViewer;
import tools.Reporter;
/**
* The general class for all datatypes that a viewed by a external application.
* An external type must be registered in the configuration-file. A temporal file is created
* for the data, that need to be decoded from Base64 -format.
* @author Thomas Hoese
* @version 0.99 1.1.02
*/
public class Dsplexternal
implements DsplBase {
protected String AttrName;
protected boolean selected;
private boolean visible = true;
private String FileType, Command, App;
private static Launcher LaunchApp = new Launcher();
/**
* Constructor
* @param String app The application together with any parameters
* @param String type The datatype.
* @see <a href="Dsplexternalsrc.html#Dsplexternal">Source</a>
*/
public Dsplexternal (String app, String type) {
FileType = type;
App = app;
}
/**
* In relations it is neccessary to get the name of the attribute of this datatype instance in
* a tuple.
* @return attribute name
* @see <a href="Dsplexternalsrc.html#getAttrName">Source</a>
*/
public String getAttrName () {
return AttrName;
}
/**
* If this datatype shouldn't be displayed in the default 2D-geographical viewer this
* method returns the specialized frame, which can do this.
* @return The instance of the Launcher to execute the external app.
* @see generic.SecondoFrame
* @see generic.Launcher
* @see <a href="Dsplexternalsrc.html#getFrame">Source</a>
*/
public SecondoFrame getFrame () {
return LaunchApp;
}
/**
*
* @return A String that holds the application with the temp. file
* @see <a href="Dsplexternalsrc.html#getCommand">Source</a>
*/
public String getCommand () {
return Command;
}
/**
* The data of exernal-types have Base64-format. So it must be decoded and then written to
* a temp. file. This file will be deleted after closing the GBS.
* @param data The data to write in Base64
* @return The temporal File
* @see <a href="Dsplexternalsrc.html#convertDataTofile">Source</a>
*/
private File convertDataToFile (String data) {
File f;
try {
f = File.createTempFile("GBS", null);
FileOutputStream fw = new FileOutputStream(f);
//convert data here
fw.write(decode(data));
fw.close();
return f;
} catch (IOException e) {
return null;
}
}
/**
* Builds Commandstring out of App-name and temp. file.
* @param app The app. String
* @param f The temp. File
* @return The application-name +parameters + tempfile-name
* @see <a href="Dsplexternalsrc.html#buildCmdString">Source</a>
*/
private String buildCmdString (String app, File f) {
int i = app.lastIndexOf("%f");
if (i == -1)
return app + " " + f.getAbsolutePath();
else {
StringBuffer sb = new StringBuffer(app);
sb.replace(i, i + 2, f.getAbsolutePath());
return sb.toString();
}
}
/**
* Scans the ListExpr for a textatom with the data, then creates a temp. file, calls
* convertDataTofile and buildCmdString.
* @param value The ListExpr with the data.
* @return null if no error occurs
* @see <a href="Dsplexternalsrc.html#scanValue">Source</a>
*/
private String scanValue (ListExpr value) {
if ((!value.isAtom()) || (value.atomType() != ListExpr.TEXT_ATOM))
return "wrong format";
File filename = convertDataToFile(value.textValue());
if (filename == null)
return "temp. file creation failed";
filename.deleteOnExit();
Command = buildCmdString(App, filename);
return null;
}
/**
* This method is used to analyse the type and value in NestedList format and build
* up the intern datastructures for this type. An alphanumeric representation is
* neccessary for the displaying this type in the queryresultlist.
* @param type A symbolatom with the datatype
* @param value The value of this object a textatom
* @param qr The queryresultlist to add alphanumeric representation
* @see generic.QueryResult
* @see sj.lang.ListExpr
* @see <a href="Dsplexternalsrc.html#init">Source</a>
*/
public void init (String name, int nameWidth, int indent,
ListExpr type, ListExpr value,
QueryResult qr) {
AttrName = DsplGeneric.extendString(name,nameWidth, indent);
String s = scanValue(value);
if (s != null)
qr.addEntry("(external?:" + s + ")");
else
qr.addEntry(this);
return;
}
/**
* Sets the visibility of an object
* @param b true=show false=hide
* @see <a href="Dsplexternalsrc.html#setVisible">Source</a>
*/
public void setVisible (boolean b) {
visible = b;
}
/**
* Gets the visibility of an object
* @return true if visible, false if not
* @see <a href="Dsplexternalsrc.html#getVisible">Source</a>
*/
public boolean getVisible () {
return visible;
}
/**
* Sets the select status of an object, textual or graphical.
* @param b true if selected, false if not.
* @see <a href="Dsplexternalsrc.html#setSelected">Source</a>
*/
public void setSelected (boolean b) {
selected = b;
}
/**
* Gets the select status of an object, textual or graphical
* @return true if selected, false if not
* @see <a href="Dsplexternalsrc.html#getSelected">Source</a>
*/
public boolean getSelected () {
return selected;
}
/**
*
* @return AttrName+datatype
* @see <a href="Dsplexternalsrc.html#toString">Source</a>
*/
public String toString () {
return AttrName + ":(" + FileType + " Attr.)";
}
/**
* Base64 encoder :Encode some data and return a String.
* @return A String with the Base64 data
* @see <a href="Dsplexternalsrc.html#encode">Source</a>
*/
public final static String encode(byte[] d)
{
if (d == null) return null;
byte data[] = new byte[d.length+2];
System.arraycopy(d, 0, data, 0, d.length);
byte dest[] = new byte[(data.length/3)*4];
// 3-byte to 4-byte conversion
for (int sidx = 0, didx=0; sidx < d.length; sidx += 3, didx += 4)
{
dest[didx] = (byte) ((data[sidx] >>> 2) & 077);
dest[didx+1] = (byte) ((data[sidx+1] >>> 4) & 017 |
(data[sidx] << 4) & 077);
dest[didx+2] = (byte) ((data[sidx+2] >>> 6) & 003 |
(data[sidx+1] << 2) & 077);
dest[didx+3] = (byte) (data[sidx+2] & 077);
}
// 0-63 to ascii printable conversion
for (int idx = 0; idx <dest.length; idx++)
{
if (dest[idx] < 26) dest[idx] = (byte)(dest[idx] + 'A');
else if (dest[idx] < 52) dest[idx] = (byte)(dest[idx] + 'a' - 26);
else if (dest[idx] < 62) dest[idx] = (byte)(dest[idx] + '0' - 52);
else if (dest[idx] < 63) dest[idx] = (byte)'+';
else dest[idx] = (byte)'/';
}
// add padding
for (int idx = dest.length-1; idx > (d.length*4)/3; idx--)
{
dest[idx] = (byte)'=';
}
return new String(dest);
}
/**
* Base64 decoder: Decode data and return bytes.
* @return A byte array with the decoded data.
* @see <a href="Dsplexternalsrc.html#decode">Source</a>
*/
public final static byte[] decode(String str)
{
if (str == null) return null;
byte data[] = str.getBytes();
return decode(data);
}
/**
* Base64 decoder:Decode data and return bytes. Assumes that the data passed
* in is ASCII text.
*/
public final static byte[] decode(byte[] data)
{
int tail = data.length;
while (data[tail-1] == '=') tail--;
byte dest[] = new byte[tail - data.length/4];
// ascii printable to 0-63 conversion
for (int idx = 0; idx <data.length; idx++)
{
if (data[idx] == '=') data[idx] = 0;
else if (data[idx] == '/') data[idx] = 63;
else if (data[idx] == '+') data[idx] = 62;
else if (data[idx] >= '0' && data[idx] <= '9')
data[idx] = (byte)(data[idx] - ('0' - 52));
else if (data[idx] >= 'a' && data[idx] <= 'z')
data[idx] = (byte)(data[idx] - ('a' - 26));
else if (data[idx] >= 'A' && data[idx] <= 'Z')
data[idx] = (byte)(data[idx] - 'A');
}
// 4-byte to 3-byte conversion
int sidx, didx;
for (sidx = 0, didx=0; didx < dest.length-2; sidx += 4, didx += 3)
{
dest[didx] = (byte) ( ((data[sidx] << 2) & 255) |
((data[sidx+1] >>> 4) & 3) );
dest[didx+1] = (byte) ( ((data[sidx+1] << 4) & 255) |
((data[sidx+2] >>> 2) & 017) );
dest[didx+2] = (byte) ( ((data[sidx+2] << 6) & 255) |
(data[sidx+3] & 077) );
}
if (didx < dest.length)
{
dest[didx] = (byte) ( ((data[sidx] << 2) & 255) |
((data[sidx+1] >>> 4) & 3) );
}
if (++didx < dest.length)
{
dest[didx] = (byte) ( ((data[sidx+1] << 4) & 255) |
((data[sidx+2] >>> 2) & 017) );
}
return dest;
}
/**
* A simple test that encodes and decodes the first commandline argument.
* @see <a href="Dsplexternalsrc.html#main">Source</a>
*/
public static final void main(String args[])
{
if (args.length != 1)
{
Reporter.writeError("Usage: Base64 string");
System.exit(0);
}
try
{
String e = Dsplexternal.encode(args[0].getBytes());
String d = new String(Dsplexternal.decode(e));
Reporter.write("Input = '" + args[0] + "'");
Reporter.write("Encoded = '" + e + "'");
Reporter.write("Decoded = '" + d + "'");
}
catch (Exception x)
{
Reporter.debug(x);
}
}
}