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