javajs.util.CompoundDocument Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jmol Show documentation
Show all versions of jmol Show documentation
Jmol: an open-source Java viewer for chemical structures in 3D
/* $RCSfile$
* $Author: egonw $
* $Date: 2006-03-18 15:59:33 -0600 (Sat, 18 Mar 2006) $
* $Revision: 4652 $
*
* Copyright (C) 2003-2005 Miguel, Jmol Development, www.jmol.org
*
* Contact: [email protected]
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package javajs.util;
import java.io.DataInputStream;
import java.io.BufferedInputStream;
import java.util.Map;
import javajs.api.GenericZipTools;
/* a simple compound document reader.
*
* DIRECTORY STRUCTURE IS NOT REGENERATED
*
* See http://sc.openoffice.org/compdocfileformat.pdf
*
* random access file info:
* http://java.sun.com/docs/books/tutorial/essential/io/rafs.html
*
* SHOOT! random access is only for applications, not applets!
*
* With a bit more work, this could be set up to deliver binary files, but
* right now I've only implemented it for string-based data.
*
*/
public class CompoundDocument extends BinaryDocument{
// RandomAccessFile file;
CompoundDocHeader header = new CompoundDocHeader(this);
Lst directory = new Lst();
CompoundDocDirEntry rootEntry;
protected GenericZipTools jzt;
int[] SAT;
int[] SSAT;
int sectorSize;
int shortSectorSize;
int nShortSectorsPerStandardSector;
int nIntPerSector;
int nDirEntriesperSector;
// called by reflection
public CompoundDocument(){
super();
this.isBigEndian = true;
}
public void setDocStream(GenericZipTools jzt, BufferedInputStream bis) {
this.jzt = jzt;
if (!isRandom) {
stream = new DataInputStream(bis);
}
stream.mark(Integer.MAX_VALUE);
if (!readHeader())
return;
getSectorAllocationTable();
getShortSectorAllocationTable();
getDirectoryTable();
}
public Lst getDirectory() {
return directory;
}
public String getDirectoryListing(String separator) {
SB sb = new SB();
for (int i = 0; i < directory.size(); i++) {
CompoundDocDirEntry thisEntry = directory.get(i);
if (!thisEntry.isEmpty)
sb.append(separator).append(thisEntry.entryName)
.append("\tlen=").appendI(thisEntry.lenStream)
.append("\tSID=").appendI(thisEntry.SIDfirstSector)
.append(thisEntry.isStandard ? "\tfileOffset="
+ getOffset(thisEntry.SIDfirstSector) : "");
}
return sb.toString();
}
public SB getAllData() {
return getAllDataFiles(null, null);
}
/**
* reads a compound document directory and saves all data in a Hashtable
* so that the files may be organized later in a different order. Also adds
* a #Directory_Listing entry.
*
* Files are bracketed by BEGIN Directory Entry and END Directory Entry lines,
* similar to ZipUtil.getAllData.
*
* @param prefix
* @param binaryFileList |-separated list of files that should be saved
* as xx xx xx hex byte strings. The directory listing
* is appended with ":asBinaryString"
* @param fileData
*/
@Override
public void getAllDataMapped(String prefix,
String binaryFileList, Map fileData) {
fileData.put("#Directory_Listing", getDirectoryListing("|"));
binaryFileList = "|" + binaryFileList + "|";
for (int i = 0; i < directory.size(); i++) {
CompoundDocDirEntry thisEntry = directory.get(i);
if (!thisEntry.isEmpty && thisEntry.entryType != 5) {
String name = thisEntry.entryName;
System.out.println("CompoundDocument file " + name);
boolean isBinary = (binaryFileList.indexOf("|" + name + "|") >= 0);
if (isBinary)
name += ":asBinaryString";
fileData.put(prefix + "/" + name, appendData(new SB(), name, thisEntry, isBinary).toString());
}
}
close();
}
@Override
public SB getAllDataFiles(String binaryFileList, String firstFile) {
// firstFile is now ignored
// if (firstFile != null) {
// for (int i = 0; i < directory.size(); i++) {
// CompoundDocDirEntry thisEntry = directory.get(i);
// if (thisEntry.entryName.equals(firstFile)) {
// directory.remove(i);
// directory.add(1, thisEntry); // after ROOT_ENTRY
// break;
// }
// }
// }
SB data = new SB();
data.append("Compound Document File Directory: ");
data.append(getDirectoryListing("|"));
data.append("\n");
CompoundDocDirEntry thisEntry;
binaryFileList = "|" + binaryFileList + "|";
for (int i = 0, n = directory.size(); i < n; i++) {
thisEntry = directory.get(i);
//System.out.println("CompoundDocument reading " + thisEntry.entryName);
String name = thisEntry.entryName;
switch (thisEntry.entryType) {
case 5: // root
break;
case 1: // user storage (dir)
data.append("NEW Directory ").append(name).append("\n");
break;
case 2: // user stream (file)
if (name.endsWith(".gz"))
name = name.substring(0, name.length() - 3);
appendData(data, name, thisEntry, binaryFileList.indexOf("|" + thisEntry.entryName + "|") >= 0);
break;
}
}
close();
return data;
}
private SB appendData(SB data, String name, CompoundDocDirEntry thisEntry,
boolean isBinary) {
data.append("BEGIN Directory Entry ").append(name).append("\n");
data.appendSB(getEntryAsString(thisEntry, isBinary));
data.append("\nEND Directory Entry ").append(name).append("\n");
return data;
}
public SB getFileAsString(String entryName) {
for (int i = 0; i < directory.size(); i++) {
CompoundDocDirEntry thisEntry = directory.get(i);
if (thisEntry.entryName.equals(entryName))
return getEntryAsString(thisEntry, false);
}
return new SB();
}
private long getOffset(int SID) {
return (SID + 1) * sectorSize;
}
private void gotoSector(int SID) {
seek(getOffset(SID));
}
private boolean readHeader() {
if (!header.readData())
return false;
sectorSize = 1 << header.sectorPower;
shortSectorSize = 1 << header.shortSectorPower;
nShortSectorsPerStandardSector = sectorSize / shortSectorSize; // e.g. 512 / 64 = 8
nIntPerSector = sectorSize / 4; // e.g. 512 / 4 = 128
nDirEntriesperSector = sectorSize / 128; // e.g. 512 / 128 = 4
// System.out.println(
// "compound document: revNum=" + header.revNumber +
// " verNum=" + header.verNumber + " isBigEndian=" + isBigEndian +
// " bytes per standard/short sector=" + sectorSize + "/" + shortSectorSize);
return true;
}
private void getSectorAllocationTable() {
int nSID = 0;
int thisSID;
SAT = new int[header.nSATsectors * nIntPerSector + 109];
try {
for (int i = 0; i < 109; i++) {
thisSID = header.MSAT0[i];
if (thisSID < 0)
break;
gotoSector(thisSID);
for (int j = 0; j < nIntPerSector; j++) {
SAT[nSID++] = readInt();
//Logger.debug(thisSID+"."+j + "/" + (nSID - 1) + " : " + SAT[nSID - 1]);
}
}
int nMaster = header.nAdditionalMATsectors;
thisSID = header.SID_MSAT_next;
int[] MSAT = new int[nIntPerSector];
out: while (nMaster-- > 0 && thisSID >= 0) {
// read a page of sector identifiers pointing to SAT sectors
gotoSector(thisSID);
for (int i = 0; i < nIntPerSector; i++)
MSAT[i] = readInt();
// read each page of SAT sector identifiers
// last entry is pointer to next master sector allocation table page
for (int i = 0; i < nIntPerSector - 1; i++) {
thisSID = MSAT[i];
if (thisSID < 0)
break out;
gotoSector(thisSID);
for (int j = nIntPerSector; --j >= 0;)
SAT[nSID++] = readInt();
}
thisSID = MSAT[nIntPerSector - 1];
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
private void getShortSectorAllocationTable() {
int nSSID = 0;
int thisSID = header.SID_SSAT_start;
int nMax = header.nSSATsectors * nIntPerSector;
SSAT = new int[nMax];
try {
while (thisSID > 0 && nSSID < nMax) {
gotoSector(thisSID);
for (int j = 0; j < nIntPerSector; j++) {
SSAT[nSSID++] = readInt();
//System.out.println("short: " + thisSID+"."+j+" SSID=" +(nSSID-1)+" "+SSAT[nSSID-1]);
}
thisSID = SAT[thisSID];
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
private void getDirectoryTable() {
int thisSID = header.SID_DIR_start;
CompoundDocDirEntry thisEntry;
rootEntry = null;
try {
while (thisSID > 0) {
gotoSector(thisSID);
for (int j = nDirEntriesperSector; --j >= 0;) {
thisEntry = new CompoundDocDirEntry(this);
thisEntry.readData();
directory.addLast(thisEntry);
if (thisEntry.entryType == 5)
rootEntry = thisEntry;
}
thisSID = SAT[thisSID];
}
} catch (Exception e) {
System.out.println(e.toString());
}
// System.out.println("CompoundDocument directory entry: \n"
// + getDirectoryListing("\n"));
}
private SB getEntryAsString(CompoundDocDirEntry thisEntry, boolean asBinaryString) {
if(thisEntry.isEmpty)
return new SB();
//System.out.println(thisEntry.entryName + " " + thisEntry.entryType + " " + thisEntry.lenStream + " " + thisEntry.isStandard + " " + thisEntry.SIDfirstSector);
return (thisEntry.isStandard ? getStandardStringData(
thisEntry.SIDfirstSector, thisEntry.lenStream, asBinaryString)
: getShortStringData(thisEntry.SIDfirstSector, thisEntry.lenStream, asBinaryString));
}
private SB getStandardStringData(int thisSID, int nBytes,
boolean asBinaryString) {
SB data = new SB();
byte[] byteBuf = new byte[sectorSize];
ZipData gzipData = new ZipData(nBytes);
try {
while (thisSID > 0 && nBytes > 0) {
gotoSector(thisSID);
nBytes = getSectorData(data, byteBuf, sectorSize, nBytes, asBinaryString, gzipData);
thisSID = SAT[thisSID];
}
if (nBytes == -9999)
return new SB();
} catch (Exception e) {
System.out.println(e.toString());
}
if (gzipData.isEnabled)
gzipData.addTo(jzt, data);
return data;
}
private int getSectorData(SB data, byte[] byteBuf,
int nSectorBytes, int nBytes,
boolean asBinaryString, ZipData gzipData)
throws Exception {
readByteArray(byteBuf, 0, byteBuf.length);
int n = gzipData.addBytes(byteBuf, nSectorBytes, nBytes);
if (n >= 0)
return n;
if (asBinaryString) {
for (int i = 0; i < nSectorBytes; i++) {
data.append(Integer.toHexString(byteBuf[i] & 0xFF)).appendC(' ');
if (--nBytes < 1)
break;
}
} else {
for (int i = 0; i < nSectorBytes; i++) {
if (byteBuf[i] == 0)
return -9999; // don't allow binary data
data.appendC((char) byteBuf[i]);
if (--nBytes < 1)
break;
}
}
return nBytes;
}
private SB getShortStringData(int shortSID, int nBytes, boolean asBinaryString) {
SB data = new SB();
if (rootEntry == null)
return data;
int thisSID = rootEntry.SIDfirstSector;
int ptShort = 0;
byte[] byteBuf = new byte[shortSectorSize];
ZipData gzipData = new ZipData(nBytes);
try {
//System.out.println("CD shortSID=" + shortSID);
// point to correct short data sector, 512/64 = 4 per page
while (thisSID >= 0 && shortSID >= 0 && nBytes > 0) {
while (shortSID - ptShort >= nShortSectorsPerStandardSector) {
ptShort += nShortSectorsPerStandardSector;
thisSID = SAT[thisSID];
}
seek(getOffset(thisSID) + (shortSID - ptShort) * shortSectorSize);
nBytes = getSectorData(data, byteBuf, shortSectorSize, nBytes, asBinaryString, gzipData);
shortSID = SSAT[shortSID];
//System.out.println("CD shortSID=" + shortSID);
}
} catch (Exception e) {
System.out.println(data.toString());
System.out.println("reader error in CompoundDocument " + e.toString());
}
if (gzipData.isEnabled)
gzipData.addTo(jzt, data);
return data;
}
}