package jhplot.io;
import java.io.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import java.util.*;
import promc.io.PBufFile;
import promc.io.PBufFile.*;
import jhplot.*;
import jhplot.gui.HelpBrowser;
/**
*
* Write or read objects in sequential order using Google's Prototype Buffer
* scheme. Each record inside files is compressed on-fly. The file size are
* smaller than when using HFile class. All graphical attributes are
* lost (use HFile class for this). You can unzip the file to see its structure.
* Normally, files should extension "jpbu". Files can be viewed using BrowserPFile.
* Unlike the usual XML, the file size is small. At this moment,
* the following objects are supported: a string,P0I, P0D, P1D, PND, PNI, F1D,F2D, FND,PRN,
* H1D, H2D.
* A protocol Buffers file is provided which can be used for C++ input.
* This I/O is mainly for "named" objects (which implement the method setTitle() or setName().
* Use CBook package to create such files in C++.
*
*
* Use this approach for storing P0D, P0I, P1D, H1D, H2D, F1D, F2D objects.
*
* @author S.Chekanov
*
*/
public class PFile {
private FileOutputStream oof = null;
private FileInputStream iif = null;
private int nev = 0;
static final private int FILE_VERSION = 1;
private ZipOutputStream zout;
static final int BUFFER = 2048;
private byte data[];
private ZipInputStream zin;
private ZipFile zipFile;
private Map map=null;
private ArrayList entries=null;
/**
* Open a file to write/read objects to/from a file in sequential
* order. If "w" option is set, the old file will be removed. Use close() to
* flash the buffer and close the file. You can set buffer size for I/O .
* Make it larger for a heavy I/O. It is best to use buffer sizes that are
* multiples of 1024 bytes. That works best with most built-in buffering in
* hard disks
*
* @param file
* File name
* @param option
* Option to create the file. If "w" - write a file (or read)
* file, if "r" only read created file.
* @param mapnames
* set to true (slower) to make association between object name and its position in the record.
* In this case, one can read objects as read(name). If file is large and you run over records
* sequentially using ID, call with "false" for fast load.
*
*/
public PFile(String file, String option, boolean mapNames) {
nev = 0;
map=null;
entries=null;
if (option.equalsIgnoreCase("w")) {
try {
(new File(file)).delete();
oof = new FileOutputStream(file);
zout = new ZipOutputStream(new BufferedOutputStream(oof));
data = new byte[BUFFER];
zipFile = null;
// write file version
ZipEntry entry = new ZipEntry("info");
zout.putNextEntry(entry);
String a = new String(Integer.toString(FILE_VERSION));
byte[] theByteArray = a.getBytes();
entry.setSize(theByteArray.length);
zout.write(theByteArray);
zout.closeEntry();
} catch (IOException e) {
e.printStackTrace();
}
} else if (option.equalsIgnoreCase("r")) {
try {
zipFile = new ZipFile(file);
iif = new FileInputStream(file);
zin = new ZipInputStream(iif);
if (mapNames) mapNames();
} catch (IOException e) {
e.printStackTrace();
}
} else {
ErrorMessage("Wrong option!. Only \"r\" or \"w\" is allowed");
}
};
/**
* Generate an association between record number and object name.
* Call this method only if the constructor was called without map option.
*
* @return false if something is wrong
*
*/
public boolean mapNames() {
if (zin == null || zipFile == null) return false;
//it exits!
if (map != null || entries != null) return false;
map = new HashMap(); // hash table
entries=new ArrayList();
try {
ZipEntry ze;
while ((ze = zin.getNextEntry()) != null) {
String a=ze.getName();
if (!a.equals("info")) {
promc.io.PBufFile.Record record=null;
try {
InputStream zz = zipFile.getInputStream(ze);
record = PBufFile.Record.parseFrom(zz);
String title="";
if (record == null ) return false;
if (record.hasName()) {
title = record.getName();
} else if (record.hasF1D()) {
title = record.getF1D().getName();
} else if (record.hasF2D()) {
title = record.getF2D().getName();
} else if (record.hasFND()) {
title = record.getFND().getName();
} else if (record.hasFPR()) {
title = record.getFPR().getName();
} else if (record.hasP0I()) {
title = record.getP0I().getName();
} else if (record.hasP0D()) {
title = record.getP0D().getName();
}else if (record.hasPXY()) { // P1D in 2 dimensions
title = record.getPXY().getName();
}else if (record.hasPXYZ()) { // P1D in 2 dimensions
title = record.getPXYZ().getName();
}else if (record.hasP1D()) { // P1D in 2 dimensions
title = record.getP1D().getName();
}else if (record.hasH1D()) { // P1D in 2 dimensions
title = record.getH1D().getName();
}else if (record.hasPND()) { // P1D in 2 dimensions
title = record.getPND().getName();
}else if (record.hasPNI()) { // P1D in 2 dimensions
title = record.getPNI().getName();
}else if (record.hasH2D()) { // P1D in 2 dimensions
title = record.getH2D().getName();
} else {
title="";
}
map.put(title, new Integer(a.toString()));
entries.add(new FileEntry(title,new Integer(a.toString()),ze.getCompressedSize(),record.getSerializedSize()));
zin.closeEntry();
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* Get version of the input file. The version is an integer
* written as an additional entry in the file "version".
* Check this by unzipping the file.
* @return version of the created file.
*/
public int getVersion() {
String tmp="0";
if (zipFile == null)
return 0;
ZipEntry ze = zipFile.getEntry("info");
long size = ze.getSize();
if (size > 0) {
// System.out.println("Length is " + size);
BufferedReader br;
try {
br = new BufferedReader(
new InputStreamReader(zipFile.getInputStream(ze)));
String line;
while ((line = br.readLine()) != null) {
tmp=line;
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return Integer.parseInt(tmp);
}
/**
* Open file for reading objects from a serialized file in sequential order.
* This constructor maps names automatically.
*
* @param file
* File name
*/
public PFile(String file) {
this(file, "r", true);
};
/**
* Open file for reading objects from a serialized file in sequential order.
* This constructor maps names automatically in the read mode.
*
* @param option
* set "r" to read and "w" to write.
*
* @param file
* File name
*/
public PFile(String file, String option) {
this(file,option, true);
};
/**
* Add an object to a file. Can be P1D, P0D,H1D,PND, etc. i.e. any jHplot array
*
* @param ob
* Object
*
* @return true if success
*/
public boolean write(Object ob) {
boolean success = true;
promc.io.PBufFile.Record.Builder record = promc.io.PBufFile.Record.newBuilder();
if (ob instanceof java.lang.String) {
record.setName((String) ob);
success=true;
} else if (ob instanceof jhplot.F1D) {
F1D f1d = (jhplot.F1D)ob;
promc.io.PBufFile.Record.F1D.Builder p = promc.io.PBufFile.Record.F1D.newBuilder().setName(f1d.getTitle());
p.setDefinition(f1d.getName() );
p.setMax(f1d.getMax()); p.setMin(f1d.getMin());
success=true;
} else if (ob instanceof jhplot.FND) {
FND fnd = (jhplot.FND)ob;
promc.io.PBufFile.Record.FND.Builder p = promc.io.PBufFile.Record.FND.newBuilder().setName(fnd.getTitle());
p.setDefinition(fnd.getName());
p.setVars(fnd.getVarString());
success=true;
} else if (ob instanceof jhplot.F2D) {
F2D f2d = (jhplot.F2D)ob;
promc.io.PBufFile.Record.F2D.Builder p = promc.io.PBufFile.Record.F2D.newBuilder().setName(f2d.getTitle());
p.setDefinition(f2d.getName() );
p.setMaxX(f2d.getMaxX()); p.setMinX(f2d.getMinX());
p.setMaxY(f2d.getMaxY()); p.setMinY(f2d.getMinY());
success=true;
} else if (ob instanceof jhplot.FPR) {
FPR fpr = (jhplot.FPR)ob;
promc.io.PBufFile.Record.FPR.Builder p = promc.io.PBufFile.Record.FPR.newBuilder().setName(fpr.getTitle());
p.setDefinition(fpr.getName() );
p.setDivU(fpr.getDivU()); p.setDivV(fpr.getDivV());
success=true;
} else if (ob instanceof jhplot.P0I) {
promc.io.PBufFile.Record.P0I.Builder p0i = promc.io.PBufFile.Record.P0I.newBuilder().setName(
((jhplot.P0I) ob).getTitle());
for (int i = 0; i < ((jhplot.P0I) ob).size(); i++)
p0i.addValue(((jhplot.P0I) ob).get(i));
record.setP0I(p0i);
success=true;
} else if (ob instanceof jhplot.P0D) {
promc.io.PBufFile.Record.P0D.Builder p0d = promc.io.PBufFile.Record.P0D.newBuilder().setName(
((jhplot.P0D) ob).getTitle());
for (int i = 0; i < ((jhplot.P0D) ob).size(); i++)
p0d.addValue(((jhplot.P0D) ob).get(i));
record.setP0D(p0d);
success=true;
}else if (ob instanceof jhplot.P2D) {
P2D p2d = (jhplot.P2D) ob;
promc.io.PBufFile.Record.PXYZ.Builder p = promc.io.PBufFile.Record.PXYZ.newBuilder().setName(p2d.getTitle());
for (int i = 0; i < ((jhplot.P2D) ob).size(); i++) {
p.addX(p2d.getX(i)); p.addY(p2d.getY(i)); p.addZ(p2d.getZ(i));}
record.setPXYZ(p);
success=true;
}else if (ob instanceof jhplot.PND) {
PND pnd = (jhplot.PND) ob;
promc.io.PBufFile.Record.PND.Builder p = promc.io.PBufFile.Record.PND.newBuilder().setName(pnd.getTitle());
int n=pnd.getDimension();
p.setDimension(n);
for (int i=0; i " + a.getName()+" --> "+s1 + " --> "+s2+"\n";
}
return tmp;
}
/**
* Get object from a file using its index.
*
* @param index
* of the object
* @return Object extracted object (or null)
*/
public Object read(int index) {
Object ob = null;
if (zipFile == null) return ob;
ZipEntry entry = zipFile.getEntry(Integer.toString(index));
if (entry == null) return ob;
InputStream zz = null;
promc.io.PBufFile.Record record = null;
try {
zz = zipFile.getInputStream(entry);
record = PBufFile.Record.parseFrom(zz);
} catch (IOException e) {
e.printStackTrace();
return ob;
}
if (record == null) return ob;
if (record.hasName()) {
return record.getName();
} else if (record.hasF1D()) {
promc.io.PBufFile.Record.F1D f1d = record.getF1D();
F1D p = new F1D(f1d.getName(), f1d.getDefinition(), f1d.getMin(), f1d.getMax() );
return p;
} else if (record.hasF2D()) {
promc.io.PBufFile.Record.F2D f2d = record.getF2D();
F2D p = new F2D(f2d.getName(), f2d.getDefinition(),f2d.getMinX(),
f2d.getMaxX(), f2d.getMinY(), f2d.getMaxY() );
return p;
} else if (record.hasFND()) {
promc.io.PBufFile.Record.FND fnd = record.getFND();
FND p = new FND(fnd.getName(), fnd.getDefinition(), fnd.getVars() );
return p;
} else if (record.hasFPR()) {
promc.io.PBufFile.Record.FPR f1d = record.getFPR();
F1D p = new F1D(f1d.getName(), f1d.getDefinition(), f1d.getDivU(), f1d.getDivV() );
return p;
} else if (record.hasP0I()) {
promc.io.PBufFile.Record.P0I p0i = record.getP0I();
P0I p = new P0I(p0i.getName());
for (int i = 0; i < p0i.getValueCount(); i++)
p.add((int) p0i.getValue(i));
return p;
} else if (record.hasP0D()) {
promc.io.PBufFile.Record.P0D p0d = record.getP0D();
P0D p = new P0D(p0d.getName());
for (int i = 0; i < p0d.getValueCount(); i++)
p.add((double) p0d.getValue(i));
return p;
} else if (record.hasPND()) {
promc.io.PBufFile.Record.PND pnd = record.getPND();
PND p = new PND(pnd.getName());
P0D pp=new P0D("row");
int nn=0;
for (int i=0; i