Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache.poi.hdf » extractor » [javadoc | source]
    1   
    2   /* ====================================================================
    3      Licensed to the Apache Software Foundation (ASF) under one or more
    4      contributor license agreements.  See the NOTICE file distributed with
    5      this work for additional information regarding copyright ownership.
    6      The ASF licenses this file to You under the Apache License, Version 2.0
    7      (the "License"); you may not use this file except in compliance with
    8      the License.  You may obtain a copy of the License at
    9   
   10          http://www.apache.org/licenses/LICENSE-2.0
   11   
   12      Unless required by applicable law or agreed to in writing, software
   13      distributed under the License is distributed on an "AS IS" BASIS,
   14      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15      See the License for the specific language governing permissions and
   16      limitations under the License.
   17   ==================================================================== */
   18           
   19   
   20   
   21   package org.apache.poi.hdf.extractor;
   22   
   23   
   24   import org.apache.poi.hdf.extractor.util;
   25   import org.apache.poi.hdf.extractor.data;
   26   import java.util;
   27   import java.io;
   28   
   29   import org.apache.poi.poifs.filesystem.POIFSFileSystem;
   30   import org.apache.poi.poifs.filesystem.DocumentEntry;
   31   
   32   import org.apache.poi.util.LittleEndian;
   33   
   34   /**
   35    * This class contains the main functionality for the Word file "reader". Much
   36    * of the code in this class is based on the Word 97 document file format. Only
   37    * works for non-complex files
   38    *
   39    * @author Ryan Ackley
   40    */
   41   
   42   public class WordDocument
   43   {
   44     /** byte buffer containing the main Document stream*/
   45     byte[] _header;
   46     /** contains all style information for this document see Word 97 Doc spec*/
   47     StyleSheet _styleSheet;
   48     /** contains All list information for this document*/
   49     ListTables _listTables;
   50     /** contains global Document properties for this document*/
   51     DOP _docProps = new DOP();
   52   
   53     int _currentList = -1;
   54     int _tableSize;
   55     int _sectionCounter = 1;
   56     /** fonts available for this document*/
   57     FontTable _fonts;
   58   
   59     /** document's text blocks*/
   60     BTreeSet _text = new BTreeSet();
   61     /** document's character runs */
   62     BTreeSet _characterTable = new BTreeSet();
   63     /** document's paragraphs*/
   64     BTreeSet _paragraphTable = new BTreeSet();
   65     /** doucment's sections*/
   66     BTreeSet _sectionTable = new BTreeSet();
   67   
   68     /** used for XSL-FO conversion*/
   69     StringBuffer _headerBuffer = new StringBuffer();
   70     /** used for XSL-FO conversion*/
   71     StringBuffer _bodyBuffer = new StringBuffer();
   72     /** used for XSL-FO table conversion*/
   73     StringBuffer _cellBuffer;
   74     /** used for XSL-FO table conversion*/
   75     ArrayList _cells;
   76     /** used for XSL-FO table conversion*/
   77     ArrayList _table;
   78   
   79     /** document's header and footer information*/
   80     byte[] _plcfHdd;
   81   
   82     /** starting position of text in main document stream*/
   83     int _fcMin;
   84     /** length of main document text stream*/
   85     int _ccpText;
   86     /** length of footnotes text*/
   87     int _ccpFtn;
   88   
   89     /** The name of the file to write to */
   90     private static String _outName;
   91   
   92     /** OLE stuff*/
   93     private InputStream istream;
   94     /** OLE stuff*/
   95     private POIFSFileSystem filesystem;
   96   
   97     //used internally
   98     private static int HEADER_EVEN_INDEX = 0;
   99     private static int HEADER_ODD_INDEX = 1;
  100     private static int FOOTER_EVEN_INDEX = 2;
  101     private static int FOOTER_ODD_INDEX = 3;
  102     private static int HEADER_FIRST_INDEX = 4;
  103     private static int FOOTER_FIRST_INDEX = 5;
  104   
  105     /**
  106      *  right now this function takes one parameter: a Word file, and outputs an
  107      *  XSL-FO document at c:\test.xml (this is hardcoded)
  108      */
  109     public static void main(String args[])
  110     {
  111         /*try
  112         {
  113           WordDocument file = new WordDocument(args[0], "r");
  114           Writer out = new BufferedWriter(new FileWriter(args[1]));
  115           file.writeAllText(out);
  116           out.flush();
  117           out.close();
  118         }
  119         catch(Throwable t)
  120         {
  121           t.printStackTrace();
  122         }*/
  123         try
  124         {
  125             _outName = args[1];
  126             WordDocument file = new WordDocument(args[0]);
  127             file.closeDoc();
  128         }
  129         catch(Exception e)
  130         {
  131             e.printStackTrace();
  132         }
  133         System.exit(0);
  134     }
  135     /**
  136      * Spits out the document text
  137      *
  138      * @param out The Writer to write the text to.
  139      * @throws IOException if there is a problem while reading from the file or
  140      *         writing out the text.
  141      */
  142     public void writeAllText(Writer out) throws IOException
  143     {
  144       int textStart = Utils.convertBytesToInt(_header, 0x18);
  145       int textEnd = Utils.convertBytesToInt(_header, 0x1c);
  146       ArrayList textPieces = findProperties(textStart, textEnd, _text.root);
  147       int size = textPieces.size();
  148   
  149       for(int x = 0; x < size; x++)
  150       {
  151         TextPiece nextPiece = (TextPiece)textPieces.get(x);
  152         int start = nextPiece.getStart();
  153         int end = nextPiece.getEnd();
  154         boolean unicode = nextPiece.usesUnicode();
  155         int add = 1;
  156   
  157         if(unicode)
  158         {
  159           add = 2;
  160           char ch;
  161           for(int y = start; y < end; y += add)
  162           {
  163   	  ch = (char)Utils.convertBytesToShort(_header, y);
  164   	  out.write(ch);
  165           }
  166         }
  167         else
  168         {
  169   	String sText = new String(_header, start, end-start);
  170   	out.write(sText);
  171         }
  172       }
  173     }
  174     /**
  175      * Constructs a Word document from fileName. Parses the document and places
  176      * all the important stuff into data structures.
  177      *
  178      * @param fileName The name of the file to read.
  179      * @throws IOException if there is a problem while parsing the document.
  180      */
  181     public WordDocument(String fileName) throws IOException
  182     {
  183     	this(new FileInputStream(fileName));
  184     }
  185     
  186     public WordDocument(InputStream inputStream) throws IOException
  187     {
  188           //do Ole stuff
  189           istream = inputStream;
  190           filesystem = new POIFSFileSystem(istream);
  191   
  192           //get important stuff from the Header block and parse all the
  193           //data structures
  194           readFIB();
  195   
  196           //get the SEPS for the main document text
  197           ArrayList sections = findProperties(_fcMin, _fcMin + _ccpText, _sectionTable.root);
  198   
  199           //iterate through sections, paragraphs, and character runs doing what
  200           //you will with the data.
  201           int size = sections.size();
  202           for(int x = 0; x < size; x++)
  203           {
  204             SepxNode node = (SepxNode)sections.get(x);
  205             int start = node.getStart();
  206             int end = node.getEnd();
  207             SEP sep = (SEP)StyleSheet.uncompressProperty(node.getSepx(), new SEP(), _styleSheet);
  208             writeSection(Math.max(_fcMin, start), Math.min(_fcMin + _ccpText, end), sep, _text, _paragraphTable, _characterTable, _styleSheet);
  209           }
  210           //finish
  211           istream.close();
  212   
  213     }
  214     /**
  215      * Extracts the main document stream from the POI file then hands off to other
  216      * functions that parse other areas.
  217      *
  218      * @throws IOException
  219      */
  220     private void readFIB() throws IOException
  221     {
  222         //get the main document stream
  223         DocumentEntry headerProps =
  224           (DocumentEntry)filesystem.getRoot().getEntry("WordDocument");
  225   
  226         //I call it the header but its also the main document stream
  227         _header = new byte[headerProps.getSize()];
  228         filesystem.createDocumentInputStream("WordDocument").read(_header);
  229   
  230         //Get the information we need from the header
  231         int info = LittleEndian.getShort(_header, 0xa);
  232   
  233         _fcMin = LittleEndian.getInt(_header, 0x18);
  234         _ccpText = LittleEndian.getInt(_header, 0x4c);
  235         _ccpFtn = LittleEndian.getInt(_header, 0x50);
  236   
  237         int charPLC = LittleEndian.getInt(_header, 0xfa);
  238         int charPlcSize = LittleEndian.getInt(_header, 0xfe);
  239         int parPLC = LittleEndian.getInt(_header, 0x102);
  240         int parPlcSize = LittleEndian.getInt(_header, 0x106);
  241         boolean useTable1 = (info & 0x200) != 0;
  242   
  243         //process the text and formatting properties
  244         processComplexFile(useTable1, charPLC, charPlcSize, parPLC, parPlcSize);
  245     }
  246   
  247     /**
  248      * Extracts the correct Table stream from the POI filesystem then hands off to
  249      * other functions to process text and formatting info. the name is based on
  250      * the fact that in Word 8(97) all text (not character or paragraph formatting)
  251      * is stored in complex format.
  252      *
  253      * @param useTable1 boolean that specifies if we should use table1 or table0
  254      * @param charTable offset in table stream of character property bin table
  255      * @param charPlcSize size of character property bin table
  256      * @param parTable offset in table stream of paragraph property bin table.
  257      * @param parPlcSize size of paragraph property bin table.
  258      * @return boolean indocating success of
  259      * @throws IOException
  260      */
  261     private void processComplexFile(boolean useTable1, int charTable,
  262                                        int charPlcSize, int parTable, int parPlcSize) throws IOException
  263     {
  264   
  265         //get the location of the piece table
  266         int complexOffset = LittleEndian.getInt(_header, 0x1a2);
  267   
  268         String tablename=null;
  269         DocumentEntry tableEntry = null;
  270         if(useTable1)
  271         {
  272             tablename="1Table";
  273         }
  274         else
  275         {
  276             tablename="0Table";
  277         }
  278         tableEntry = (DocumentEntry)filesystem.getRoot().getEntry(tablename);
  279   
  280         //load the table stream into a buffer
  281         int size = tableEntry.getSize();
  282         byte[] tableStream = new byte[size];
  283         filesystem.createDocumentInputStream(tablename).read(tableStream);
  284   
  285         //init the DOP for this document
  286         initDocProperties(tableStream);
  287         //load the header/footer raw data for this document
  288         initPclfHdd(tableStream);
  289         //parse out the text locations
  290         findText(tableStream, complexOffset);
  291         //parse out text formatting
  292         findFormatting(tableStream, charTable, charPlcSize, parTable, parPlcSize);
  293   
  294     }
  295     /**
  296      * Goes through the piece table and parses out the info regarding the text
  297      * blocks. For Word 97 and greater all text is stored in the "complex" way
  298      * because of unicode.
  299      *
  300      * @param tableStream buffer containing the main table stream.
  301      * @param beginning of the complex data.
  302      * @throws IOException
  303      */
  304     private void findText(byte[] tableStream, int complexOffset) throws IOException
  305     {
  306       //actual text
  307       int pos = complexOffset;
  308       //skips through the prms before we reach the piece table. These contain data
  309       //for actual fast saved files
  310       while(tableStream[pos] == 1)
  311       {
  312           pos++;
  313           int skip = LittleEndian.getShort(tableStream, pos);
  314           pos += 2 + skip;
  315       }
  316       if(tableStream[pos] != 2)
  317       {
  318           throw new IOException("corrupted Word file");
  319       }
  320       else
  321       {
  322           //parse out the text pieces
  323           int pieceTableSize = LittleEndian.getInt(tableStream, ++pos);
  324           pos += 4;
  325           int pieces = (pieceTableSize - 4) / 12;
  326           for (int x = 0; x < pieces; x++)
  327           {
  328               int filePos = LittleEndian.getInt(tableStream, pos + ((pieces + 1) * 4) + (x * 8) + 2);
  329               boolean unicode = false;
  330               if ((filePos & 0x40000000) == 0)
  331               {
  332                   unicode = true;
  333               }
  334               else
  335               {
  336                   unicode = false;
  337                   filePos &= ~(0x40000000);//gives me FC in doc stream
  338                   filePos /= 2;
  339               }
  340               int totLength = LittleEndian.getInt(tableStream, pos + (x + 1) * 4) -
  341                               LittleEndian.getInt(tableStream, pos + (x * 4));
  342   
  343               TextPiece piece = new TextPiece(filePos, totLength, unicode);
  344               _text.add(piece);
  345   
  346           }
  347   
  348       }
  349     }
  350   
  351     /**
  352      * Does all of the formatting parsing
  353      *
  354      * @param tableStream Main table stream buffer.
  355      * @param charOffset beginning of the character bin table.
  356      * @param chrPlcSize size of the char bin table.
  357      * @param parOffset offset of the paragraph bin table.
  358      * @param size of the paragraph bin table.
  359      */
  360     private void findFormatting(byte[] tableStream, int charOffset,
  361                                 int charPlcSize, int parOffset, int parPlcSize) throws IOException
  362     {
  363         openDoc();
  364         createStyleSheet(tableStream);
  365         createListTables(tableStream);
  366         createFontTable(tableStream);
  367   
  368         //find character runs
  369         //Get all the chpx info and store it
  370   
  371         int arraySize = (charPlcSize - 4)/8;
  372   
  373         //first we must go through the bin table and find the fkps
  374         for(int x = 0; x < arraySize; x++)
  375         {
  376   
  377   
  378             //get page number(has nothing to do with document page)
  379             //containing the chpx for the paragraph
  380             int PN = LittleEndian.getInt(tableStream, charOffset + (4 * (arraySize + 1) + (4 * x)));
  381   
  382             byte[] fkp = new byte[512];
  383             System.arraycopy(_header, (PN * 512), fkp, 0, 512);
  384             //take each fkp and get the chpxs
  385             int crun = Utils.convertUnsignedByteToInt(fkp[511]);
  386             for(int y = 0; y < crun; y++)
  387             {
  388                 //get the beginning fc of each paragraph text run
  389                 int fcStart = LittleEndian.getInt(fkp, y * 4);
  390                 int fcEnd = LittleEndian.getInt(fkp, (y+1) * 4);
  391                 //get the offset in fkp of the papx for this paragraph
  392                 int chpxOffset = 2 * Utils.convertUnsignedByteToInt(fkp[((crun + 1) * 4) + y]);
  393   
  394                 //optimization if offset == 0 use "Normal" style
  395                 if(chpxOffset == 0)
  396   
  397                 {
  398                   _characterTable.add(new ChpxNode(fcStart, fcEnd, new byte[0]));
  399                   continue;
  400                 }
  401   
  402                 int size = Utils.convertUnsignedByteToInt(fkp[chpxOffset]);
  403   
  404                 byte[] chpx = new byte[size];
  405                 System.arraycopy(fkp, ++chpxOffset, chpx, 0, size);
  406                 //_papTable.put(new Integer(fcStart), papx);
  407                 _characterTable.add(new ChpxNode(fcStart, fcEnd, chpx));
  408             }
  409   
  410         }
  411   
  412         //find paragraphs
  413         arraySize = (parPlcSize - 4)/8;
  414         //first we must go through the bin table and find the fkps
  415         for(int x = 0; x < arraySize; x++)
  416         {
  417             int PN = LittleEndian.getInt(tableStream, parOffset + (4 * (arraySize + 1) + (4 * x)));
  418   
  419             byte[] fkp = new byte[512];
  420             System.arraycopy(_header, (PN * 512), fkp, 0, 512);
  421             //take each fkp and get the paps
  422             int crun = Utils.convertUnsignedByteToInt(fkp[511]);
  423             for(int y = 0; y < crun; y++)
  424             {
  425                 //get the beginning fc of each paragraph text run
  426                 int fcStart = LittleEndian.getInt(fkp, y * 4);
  427                 int fcEnd = LittleEndian.getInt(fkp, (y+1) * 4);
  428                 //get the offset in fkp of the papx for this paragraph
  429                 int papxOffset = 2 * Utils.convertUnsignedByteToInt(fkp[((crun + 1) * 4) + (y * 13)]);
  430                 int size = 2 * Utils.convertUnsignedByteToInt(fkp[papxOffset]);
  431                 if(size == 0)
  432                 {
  433                     size = 2 * Utils.convertUnsignedByteToInt(fkp[++papxOffset]);
  434                 }
  435                 else
  436                 {
  437                     size--;
  438                 }
  439   
  440                 byte[] papx = new byte[size];
  441                 System.arraycopy(fkp, ++papxOffset, papx, 0, size);
  442                 _paragraphTable.add(new PapxNode(fcStart, fcEnd, papx));
  443   
  444             }
  445   
  446         }
  447   
  448         //find sections
  449         int fcMin = Utils.convertBytesToInt(_header, 0x18);
  450         int plcfsedFC = Utils.convertBytesToInt(_header, 0xca);
  451         int plcfsedSize = Utils.convertBytesToInt(_header, 0xce);
  452         byte[] plcfsed = new byte[plcfsedSize];
  453         System.arraycopy(tableStream, plcfsedFC, plcfsed, 0, plcfsedSize);
  454   
  455         arraySize = (plcfsedSize - 4)/16;
  456   
  457         //openDoc();
  458   
  459         for(int x = 0; x < arraySize; x++)
  460         {
  461             int sectionStart = Utils.convertBytesToInt(plcfsed, x * 4) + fcMin;
  462             int sectionEnd = Utils.convertBytesToInt(plcfsed, (x+1) * 4) + fcMin;
  463             int sepxStart = Utils.convertBytesToInt(plcfsed, 4 * (arraySize + 1) + (x * 12) + 2);
  464             int sepxSize = Utils.convertBytesToShort(_header, sepxStart);
  465             byte[] sepx = new byte[sepxSize];
  466             System.arraycopy(_header, sepxStart + 2, sepx, 0, sepxSize);
  467             SepxNode node = new SepxNode(x + 1, sectionStart, sectionEnd, sepx);
  468             _sectionTable.add(node);
  469         }
  470   
  471   
  472     }
  473   
  474     public void openDoc()
  475     {
  476       _headerBuffer.append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\r\n");
  477       _headerBuffer.append("<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\r\n");
  478       _headerBuffer.append("<fo:layout-master-set>\r\n");
  479   
  480     }
  481     private HeaderFooter findSectionHdrFtr(int type, int index)
  482     {
  483       if(_plcfHdd.length < 50)
  484       {
  485         return new HeaderFooter(0,0,0);
  486       }
  487       int start = _fcMin + _ccpText + _ccpFtn;
  488       int end = start;
  489       int arrayIndex = 0;
  490   
  491       switch(type)
  492       {
  493         case HeaderFooter.HEADER_EVEN:
  494              arrayIndex = (HEADER_EVEN_INDEX + (index * 6));
  495              break;
  496         case HeaderFooter.FOOTER_EVEN:
  497              arrayIndex = (FOOTER_EVEN_INDEX + (index * 6));
  498              break;
  499         case HeaderFooter.HEADER_ODD:
  500              arrayIndex = (HEADER_ODD_INDEX + (index * 6));
  501              break;
  502         case HeaderFooter.FOOTER_ODD:
  503              arrayIndex = (FOOTER_ODD_INDEX + (index * 6));
  504              break;
  505         case HeaderFooter.HEADER_FIRST:
  506              arrayIndex = (HEADER_FIRST_INDEX + (index * 6));
  507              break;
  508         case HeaderFooter.FOOTER_FIRST:
  509              arrayIndex = (FOOTER_FIRST_INDEX + (index * 6));
  510              break;
  511       }
  512       start += Utils.convertBytesToInt(_plcfHdd, (arrayIndex * 4));
  513       end += Utils.convertBytesToInt(_plcfHdd, (arrayIndex + 1) * 4);
  514   
  515       HeaderFooter retValue = new HeaderFooter(type, start, end);
  516   
  517       if((end - start) == 0 && index > 1)
  518       {
  519         retValue = findSectionHdrFtr(type, index - 1);
  520       }
  521       return retValue;
  522     }
  523     /**
  524      * inits this document DOP structure.
  525      *
  526      * @param tableStream The documents table stream.
  527      */
  528     private void initDocProperties(byte[] tableStream)
  529     {
  530       int pos = LittleEndian.getInt(_header, 0x192);
  531       int size = LittleEndian.getInt(_header, 0x196);
  532       byte[] dop = new byte[size];
  533   
  534       System.arraycopy(tableStream, pos, dop, 0, size);
  535   
  536       _docProps._fFacingPages = (dop[0] & 0x1) > 0;
  537       _docProps._fpc = (dop[0] & 0x60) >> 5;
  538   
  539       short num = LittleEndian.getShort(dop, 2);
  540       _docProps._rncFtn = (num & 0x3);
  541       _docProps._nFtn = (short)(num & 0xfffc) >> 2;
  542       num = LittleEndian.getShort(dop, 52);
  543       _docProps._rncEdn = num & 0x3;
  544       _docProps._nEdn = (short)(num & 0xfffc) >> 2;
  545       num = LittleEndian.getShort(dop, 54);
  546       _docProps._epc = num & 0x3;
  547     }
  548   
  549     public void writeSection(int start, int end, SEP sep, BTreeSet text,
  550                              BTreeSet paragraphTable, BTreeSet characterTable,
  551                              StyleSheet stylesheet)
  552     {
  553   
  554       HeaderFooter titleHeader = findSectionHdrFtr(HeaderFooter.HEADER_FIRST, _sectionCounter);
  555       HeaderFooter titleFooter = findSectionHdrFtr(HeaderFooter.FOOTER_FIRST, _sectionCounter);
  556       HeaderFooter oddHeader = findSectionHdrFtr(HeaderFooter.HEADER_ODD, _sectionCounter);
  557       HeaderFooter evenHeader = findSectionHdrFtr(HeaderFooter.HEADER_EVEN, _sectionCounter);
  558       HeaderFooter oddFooter = findSectionHdrFtr(HeaderFooter.FOOTER_ODD, _sectionCounter);
  559       HeaderFooter evenFooter = findSectionHdrFtr(HeaderFooter.FOOTER_EVEN, _sectionCounter);
  560   
  561       String titlePage = null;
  562       String evenPage = null;
  563       String oddPage = null;
  564       String regPage = null;
  565   
  566       String sequenceName = null;
  567   
  568       /*if(sep._fTitlePage)
  569       {
  570         titlePage = createPageMaster(sep, "first", _sectionCounter, createRegion("before", "title-header"), createRegion("after", "title-footer"));
  571   
  572         if(!titleHeader.isEmpty())
  573         {
  574           addStaticContent("title-header" + _sectionCounter, titleHeader);
  575         }
  576         if(!titleFooter.isEmpty())
  577         {
  578           addStaticContent("title-footer" + _sectionCounter, titleFooter);
  579         }
  580       }*/
  581   
  582       if(_docProps._fFacingPages)
  583       {
  584         if(sep._fTitlePage)
  585         {
  586           String before = createRegion(true, titleHeader, sep, "title-header" + _sectionCounter);
  587           String after = createRegion(false, titleFooter, sep, "title-footer" + _sectionCounter);
  588           titlePage = createPageMaster(sep, "first", _sectionCounter, before, after);
  589         }
  590         String before = createRegion(true, evenHeader, sep, "even-header" + _sectionCounter);
  591         String after = createRegion(false, evenFooter, sep, "even-footer" + _sectionCounter);
  592         evenPage = createPageMaster(sep, "even", _sectionCounter, before, after);
  593         before = createRegion(true, oddHeader, sep, "odd-header" + _sectionCounter);
  594         after = createRegion(false, oddFooter, sep, "odd-footer" + _sectionCounter);
  595         oddPage = createPageMaster(sep, "odd", _sectionCounter, before, after);
  596         sequenceName = createEvenOddPageSequence(titlePage, evenPage, oddPage, _sectionCounter);
  597   
  598         openPage(sequenceName, "reference");
  599   
  600         if(sep._fTitlePage)
  601         {
  602   
  603   
  604           if(!titleHeader.isEmpty())
  605           {
  606             addStaticContent("title-header" + _sectionCounter, titleHeader);
  607           }
  608           if(!titleFooter.isEmpty())
  609           {
  610             addStaticContent("title-footer" + _sectionCounter, titleFooter);
  611           }
  612         }
  613   
  614         //handle the headers and footers for odd and even pages
  615         if(!oddHeader.isEmpty())
  616         {
  617           addStaticContent("odd-header" + _sectionCounter, oddHeader);
  618         }
  619         if(!oddFooter.isEmpty())
  620         {
  621           addStaticContent("odd-footer" + _sectionCounter, oddFooter);
  622         }
  623         if(!evenHeader.isEmpty())
  624         {
  625           addStaticContent("even-header" + _sectionCounter, evenHeader);
  626         }
  627         if(!evenFooter.isEmpty())
  628         {
  629           addStaticContent("even-footer" + _sectionCounter, evenFooter);
  630         }
  631         openFlow();
  632         addBlockContent(start, end, text, paragraphTable, characterTable);
  633         closeFlow();
  634         closePage();
  635       }
  636       else
  637       {
  638         /*if(sep._fTitlePage)
  639         {
  640           String before = createRegion(true, titleHeader, sep);
  641           String after = createRegion(false, titleFooter, sep);
  642           titlePage = createPageMaster(sep, "first", _sectionCounter, before, after);
  643         }*/
  644         String before = createRegion(true, oddHeader, sep, null);
  645         String after = createRegion(false, oddFooter, sep, null);
  646         regPage = createPageMaster(sep, "page", _sectionCounter, before, after);
  647   
  648         if(sep._fTitlePage)
  649         {
  650           before = createRegion(true, titleHeader, sep, "title-header" + _sectionCounter);
  651           after = createRegion(false, titleFooter, sep, "title-footer" + _sectionCounter);
  652           titlePage = createPageMaster(sep, "first", _sectionCounter, before, after);
  653           sequenceName = createPageSequence(titlePage, regPage, _sectionCounter);
  654           openPage(sequenceName, "reference");
  655   
  656           if(!titleHeader.isEmpty())
  657           {
  658             addStaticContent("title-header" + _sectionCounter, titleHeader);
  659           }
  660           if(!titleFooter.isEmpty())
  661           {
  662             addStaticContent("title-footer" + _sectionCounter, titleFooter);
  663           }
  664         }
  665         else
  666         {
  667           openPage(regPage, "name");
  668         }
  669         if(!oddHeader.isEmpty())
  670         {
  671           addStaticContent("xsl-region-before", oddHeader);
  672         }
  673         if(!oddFooter.isEmpty())
  674         {
  675           addStaticContent("xsl-region-after", oddFooter);
  676         }
  677         openFlow();
  678         addBlockContent(start, end, text, paragraphTable, characterTable);
  679         closeFlow();
  680         closePage();
  681       }
  682       _sectionCounter++;
  683     }
  684   
  685     private int calculateHeaderHeight(int start, int end, int pageWidth)
  686     {
  687       ArrayList paragraphs = findProperties(start, end, _paragraphTable.root);
  688       int size = paragraphs.size();
  689       ArrayList lineHeights = new ArrayList();
  690       //StyleContext context = StyleContext.getDefaultStyleContext();
  691   
  692       for(int x = 0; x < size; x++)
  693       {
  694         PapxNode node = (PapxNode)paragraphs.get(x);
  695         int parStart = Math.max(node.getStart(), start);
  696         int parEnd = Math.min(node.getEnd(), end);
  697   
  698         int lineWidth = 0;
  699         int maxHeight = 0;
  700   
  701         ArrayList textRuns = findProperties(parStart, parEnd, _characterTable.root);
  702         int charSize = textRuns.size();
  703   
  704         //StringBuffer lineBuffer = new StringBuffer();
  705         for(int y = 0; y < charSize; y++)
  706         {
  707           ChpxNode charNode = (ChpxNode)textRuns.get(y);
  708           int istd = Utils.convertBytesToShort(node.getPapx(), 0);
  709           StyleDescription sd = _styleSheet.getStyleDescription(istd);
  710           CHP chp = (CHP)StyleSheet.uncompressProperty(charNode.getChpx(), sd.getCHP(), _styleSheet);
  711   
  712           //get Font info
  713           //FontMetrics metrics = getFontMetrics(chp, context);
  714   
  715           int height = 10;//metrics.getHeight();
  716           maxHeight = Math.max(maxHeight, height);
  717   
  718           int charStart = Math.max(parStart, charNode.getStart());
  719           int charEnd = Math.min(parEnd, charNode.getEnd());
  720   
  721           ArrayList text = findProperties(charStart, charEnd, _text.root);
  722   
  723           int textSize = text.size();
  724           StringBuffer buf = new StringBuffer();
  725           for(int z = 0; z < textSize; z++)
  726           {
  727   
  728             TextPiece piece = (TextPiece)text.get(z);
  729             int textStart = Math.max(piece.getStart(), charStart);
  730             int textEnd = Math.min(piece.getEnd(), charEnd);
  731   
  732             if(piece.usesUnicode())
  733             {
  734               addUnicodeText(textStart, textEnd, buf);
  735             }
  736             else
  737             {
  738               addText(textStart, textEnd, buf);
  739             }
  740           }
  741   
  742           String tempString = buf.toString();
  743           lineWidth += 10 * tempString.length();//metrics.stringWidth(tempString);
  744           if(lineWidth > pageWidth)
  745           {
  746             lineHeights.add(new Integer(maxHeight));
  747             maxHeight = 0;
  748             lineWidth = 0;
  749           }
  750         }
  751         lineHeights.add(new Integer(maxHeight));
  752       }
  753       int sum = 0;
  754       size = lineHeights.size();
  755       for(int x = 0; x < size; x++)
  756       {
  757         Integer height = (Integer)lineHeights.get(x);
  758         sum += height.intValue();
  759       }
  760   
  761       return sum;
  762     }
  763   /*  private FontMetrics getFontMetrics(CHP chp, StyleContext context)
  764     {
  765       String fontName = _fonts.getFont(chp._ftcAscii);
  766       int style = 0;
  767       if(chp._bold)
  768       {
  769         style |= Font.BOLD;
  770       }
  771       if(chp._italic)
  772       {
  773         style |= Font.ITALIC;
  774       }
  775   
  776       Font font = new Font(fontName, style, chp._hps/2);
  777   
  778   
  779       return context.getFontMetrics(font);
  780     }*/
  781     private String createRegion(boolean before, HeaderFooter header, SEP sep, String name)
  782     {
  783       if(header.isEmpty())
  784       {
  785         return "";
  786       }
  787       String region = "region-name=\"" + name + "\"";
  788       if(name == null)
  789       {
  790         region = "";
  791       }
  792       int height = calculateHeaderHeight(header.getStart(), header.getEnd(), sep._xaPage/20);
  793       int marginTop = 0;
  794       int marginBottom = 0;
  795       int extent = 0;
  796       String where = null;
  797       String align = null;
  798   
  799       if(before)
  800       {
  801         where = "before";
  802         align = "before";
  803         marginTop = sep._dyaHdrTop/20;
  804         extent = height + marginTop;
  805         sep._dyaTop = Math.max(extent*20, sep._dyaTop);
  806       }
  807       else
  808       {
  809         where = "after";
  810         align = "after";
  811         marginBottom = sep._dyaHdrBottom/20;
  812         extent = height + marginBottom;
  813         sep._dyaBottom = Math.max(extent*20, sep._dyaBottom);
  814       }
  815   
  816       int marginLeft = sep._dxaLeft/20;
  817       int marginRight = sep._dxaRight/20;
  818   
  819       return "<fo:region-" + where + " display-align=\"" + align + "\" extent=\""
  820                + extent + "pt\" "+region+"/>";
  821   // org.apache.fop.fo.expr.PropertyException: 
  822   // Border and padding for region "xsl-region-before" must be '0' 
  823   // (See 6.4.13 in XSL 1.0).
  824   //             extent + "pt\" padding-left=\"" + marginLeft + "pt\" padding-right=\"" +
  825   //             marginRight + "pt\" padding-top=\"" + marginTop + "pt\" padding-bottom=\"" +
  826   //             marginBottom + "pt\" " + region + "/>";
  827   
  828     }
  829     private String createRegion(String where, String name)
  830     {
  831       return "<fo:region-" + where + " overflow=\"scroll\" region-name=\"" + name + "\"/>";
  832     }
  833     private String createEvenOddPageSequence(String titlePage, String evenPage, String oddPage, int counter)
  834     {
  835       String name = "my-sequence" + counter;
  836       _headerBuffer.append("<fo:page-sequence-master master-name=\"" + name + "\"> ");
  837       _headerBuffer.append("<fo:repeatable-page-master-alternatives>");
  838       if(titlePage != null)
  839       {
  840         _headerBuffer.append("<fo:conditional-page-master-reference " +
  841                              "page-position=\"first\" master-reference=\"" +
  842                               titlePage + "\"/>");
  843       }
  844       _headerBuffer.append("<fo:conditional-page-master-reference odd-or-even=\"odd\" ");
  845       _headerBuffer.append("master-reference=\""+ oddPage + "\"/> ");
  846       _headerBuffer.append("<fo:conditional-page-master-reference odd-or-even=\"even\" ");
  847       _headerBuffer.append("master-reference=\"" + evenPage + "\"/> ");
  848       _headerBuffer.append("</fo:repeatable-page-master-alternatives>");
  849       _headerBuffer.append("</fo:page-sequence-master>");
  850       return name;
  851     }
  852     private String createPageSequence(String titlePage, String regPage, int counter)
  853     {
  854       String name = null;
  855       if(titlePage != null)
  856       {
  857         name = "my-sequence" + counter;
  858         _headerBuffer.append("<fo:page-sequence-master master-name=\"" + name + "\"> ");
  859         _headerBuffer.append("<fo:single-page-master-reference master-reference=\"" + titlePage + "\"/>");
  860         _headerBuffer.append("<fo:repeatable-page-master-reference master-reference=\"" + regPage + "\"/>");
  861         _headerBuffer.append("</fo:page-sequence-master>");
  862       }
  863       return name;
  864     }
  865     private void addBlockContent(int start, int end, BTreeSet text,
  866                                 BTreeSet paragraphTable, BTreeSet characterTable)
  867     {
  868   
  869       BTreeSet.BTreeNode root = paragraphTable.root;
  870       ArrayList pars = findProperties(start, end, root);
  871       //root = characterTable.root;
  872       int size = pars.size();
  873   
  874       for(int c = 0; c < size; c++)
  875       {
  876         PapxNode currentNode = (PapxNode)pars.get(c);
  877         createParagraph(start, end, currentNode, characterTable, text);
  878       }
  879       //closePage();
  880     }
  881     private String getTextAlignment(byte jc)
  882     {
  883       switch(jc)
  884       {
  885         case 0:
  886           return "start";
  887         case 1:
  888           return "center";
  889         case 2:
  890           return "end";
  891         case 3:
  892           return "justify";
  893         default:
  894           return "left";
  895       }
  896     }
  897     private void createParagraph(int start, int end, PapxNode currentNode,
  898                                  BTreeSet characterTable, BTreeSet text)
  899     {
  900       StringBuffer blockBuffer = _bodyBuffer;
  901       byte[] papx = currentNode.getPapx();
  902       int istd = Utils.convertBytesToShort(papx, 0);
  903       StyleDescription std = _styleSheet.getStyleDescription(istd);
  904       PAP pap = (PAP)StyleSheet.uncompressProperty(papx, std.getPAP(), _styleSheet);
  905   
  906       //handle table cells
  907       if(pap._fInTable > 0)
  908       {
  909         if(pap._fTtp == 0)
  910         {
  911           if(_cellBuffer == null)
  912           {
  913             _cellBuffer = new StringBuffer();
  914           }
  915           blockBuffer = _cellBuffer;
  916         }
  917         else
  918         {
  919           if(_table == null)
  920           {
  921             _table = new ArrayList();
  922           }
  923           TAP tap = (TAP)StyleSheet.uncompressProperty(papx, new TAP(), _styleSheet);
  924           TableRow nextRow = new TableRow(_cells, tap);
  925           _table.add(nextRow);
  926           _cells = null;
  927           return;
  928         }
  929       }
  930       else
  931       {
  932         //just prints out any table that is stored in _table
  933         printTable();
  934       }
  935   
  936       if(pap._ilfo > 0)
  937       {
  938         LVL lvl = _listTables.getLevel(pap._ilfo, pap._ilvl);
  939         addListParagraphContent(lvl, blockBuffer, pap, currentNode, start, end, std);
  940       }
  941       else
  942       {
  943         addParagraphContent(blockBuffer, pap, currentNode, start, end, std);
  944       }
  945   
  946     }
  947   
  948     private void addListParagraphContent(LVL lvl, StringBuffer blockBuffer, PAP pap,
  949                                          PapxNode currentNode, int start, int end,
  950                                          StyleDescription std)
  951     {
  952       pap = (PAP)StyleSheet.uncompressProperty(lvl._papx, pap, _styleSheet, false);
  953   
  954       addParagraphProperties(pap, blockBuffer);
  955   
  956       ArrayList charRuns = findProperties(Math.max(currentNode.getStart(), start),
  957                                        Math.min(currentNode.getEnd(), end),
  958                                        _characterTable.root);
  959       int len = charRuns.size();
  960   
  961       CHP numChp = (CHP)StyleSheet.uncompressProperty(((ChpxNode)charRuns.get(len-1)).getChpx(), std.getCHP(), _styleSheet);
  962   
  963       numChp = (CHP)StyleSheet.uncompressProperty(lvl._chpx, numChp, _styleSheet);
  964   
  965       //StyleContext context = StyleContext.getDefaultStyleContext();
  966       //FontMetrics metrics = getFontMetrics(numChp, context);
  967       int indent = -1 * pap._dxaLeft1;
  968       String bulletText = getBulletText(lvl, pap);
  969   
  970       indent = indent - (bulletText.length() * 10) * 20;//(metrics.stringWidth(bulletText) * 20);
  971   
  972       if(indent > 0)
  973       {
  974         numChp._paddingEnd = (short)indent;
  975       }
  976   
  977       addCharacterProperties(numChp, blockBuffer);
  978       int listNum = 0;
  979   
  980       //if(number != null)
  981       //{
  982       blockBuffer.append(bulletText);
  983         //listNum = 1;
  984       //}
  985   
  986       //for(;listNum < lvl._xst.length; listNum++)
  987       //{
  988       //  addText(lvl._xst[listNum], blockBuffer);
  989       //}
  990   
  991   
  992       switch (lvl._ixchFollow)
  993       {
  994         case 0:
  995           addText('\u0009', blockBuffer);
  996           break;
  997         case 1:
  998           addText(' ', blockBuffer);
  999           break;
 1000       }
 1001   
 1002       closeLine(blockBuffer);
 1003       for(int x = 0; x < len; x++)
 1004       {
 1005         ChpxNode charNode = (ChpxNode)charRuns.get(x);
 1006         byte[] chpx = charNode.getChpx();
 1007         CHP chp = (CHP)StyleSheet.uncompressProperty(chpx, std.getCHP(), _styleSheet);
 1008   
 1009   
 1010         addCharacterProperties(chp, blockBuffer);
 1011   
 1012         int charStart = Math.max(charNode.getStart(), currentNode.getStart());
 1013         int charEnd = Math.min(charNode.getEnd(), currentNode.getEnd());
 1014         ArrayList textRuns = findProperties(charStart, charEnd, _text.root);
 1015         int textRunLen = textRuns.size();
 1016         for(int y = 0; y < textRunLen; y++)
 1017         {
 1018           TextPiece piece = (TextPiece)textRuns.get(y);
 1019           charStart = Math.max(charStart, piece.getStart());
 1020           charEnd = Math.min(charEnd, piece.getEnd());
 1021   
 1022           if(piece.usesUnicode())
 1023           {
 1024             addUnicodeText(charStart, charEnd, blockBuffer);
 1025           }
 1026           else
 1027           {
 1028             addText(charStart, charEnd, blockBuffer);
 1029           }
 1030           closeLine(blockBuffer);
 1031         }
 1032       }
 1033       closeBlock(blockBuffer);
 1034     }
 1035   
 1036     private void addParagraphContent(StringBuffer blockBuffer, PAP pap,
 1037                                      PapxNode currentNode, int start, int end,
 1038                                      StyleDescription std)
 1039     {
 1040       addParagraphProperties(pap, blockBuffer);
 1041   
 1042       ArrayList charRuns = findProperties(Math.max(currentNode.getStart(), start),
 1043                                        Math.min(currentNode.getEnd(), end),
 1044                                        _characterTable.root);
 1045       int len = charRuns.size();
 1046   
 1047       for(int x = 0; x < len; x++)
 1048       {
 1049         ChpxNode charNode = (ChpxNode)charRuns.get(x);
 1050         byte[] chpx = charNode.getChpx();
 1051         CHP chp = (CHP)StyleSheet.uncompressProperty(chpx, std.getCHP(), _styleSheet);
 1052   
 1053         addCharacterProperties(chp, blockBuffer);
 1054   
 1055         int charStart = Math.max(charNode.getStart(), currentNode.getStart());
 1056         int charEnd = Math.min(charNode.getEnd(), currentNode.getEnd());
 1057         ArrayList textRuns = findProperties(charStart, charEnd, _text.root);
 1058         int textRunLen = textRuns.size();
 1059         for(int y = 0; y < textRunLen; y++)
 1060         {
 1061           TextPiece piece = (TextPiece)textRuns.get(y);
 1062           charStart = Math.max(charStart, piece.getStart());
 1063           charEnd = Math.min(charEnd, piece.getEnd());
 1064   
 1065           if(piece.usesUnicode())
 1066           {
 1067             addUnicodeText(charStart, charEnd, blockBuffer);
 1068           }
 1069           else
 1070           {
 1071             addText(charStart, charEnd, blockBuffer);
 1072           }
 1073           closeLine(blockBuffer);
 1074         }
 1075       }
 1076       closeBlock(blockBuffer);
 1077     }
 1078     private void addText(int start, int end, StringBuffer buf)
 1079     {
 1080       for(int x = start; x < end; x++)
 1081       {
 1082         char ch = '?';
 1083   
 1084   
 1085         ch = (char)_header[x];
 1086   
 1087         addText(ch, buf);
 1088       }
 1089     }
 1090     private void addText(char ch, StringBuffer buf)
 1091     {
 1092       int num = 0xffff & ch;
 1093       if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
 1094         (ch >= '0' && ch <= '9') || ch == '_' || ch == ' ' || ch == '-' || ch == '.' || ch == '$')
 1095       {
 1096         buf.append(ch);
 1097       }
 1098       else if(num == 0x07 && _cellBuffer != null)
 1099       {
 1100   
 1101         if(_cells == null)
 1102         {
 1103           _cells = new ArrayList();
 1104         }
 1105         closeLine(_cellBuffer);
 1106         closeBlock(_cellBuffer);
 1107         _cells.add(_cellBuffer.toString());
 1108         _cellBuffer = null;
 1109   
 1110       }
 1111   
 1112       else
 1113       {
 1114         /** @todo handle special characters */
 1115         if(num < 0x20)
 1116         num=0x20;
 1117         buf.append("&#");
 1118         buf.append(num);
 1119         buf.append(';');
 1120       }
 1121     }
 1122     private void addUnicodeText(int start, int end, StringBuffer buf)
 1123     {
 1124       for(int x = start; x < end; x += 2)
 1125       {
 1126         char ch = Utils.getUnicodeCharacter(_header, x);
 1127         //if(ch < 0x0020)
 1128         //{
 1129         //  _bodyBuffer.append('?');
 1130         //}
 1131         //else
 1132         //{
 1133           addText(ch, buf);
 1134         //}
 1135       }
 1136     }
 1137     private void addParagraphProperties(PAP pap, StringBuffer buf)
 1138     {
 1139       buf.append("<fo:block ");
 1140       buf.append("text-align=\"" + getTextAlignment(pap._jc) + "\"\r\n");
 1141       buf.append("linefeed-treatment=\"preserve\" ");
 1142       buf.append("white-space-collapse=\"false\" ");
 1143   
 1144       if(pap._fKeep > 0)
 1145       {
 1146         buf.append("keep-together.within-page=\"always\"\r\n");
 1147       }
 1148       if(pap._fKeepFollow > 0)
 1149       {
 1150         buf.append("keep-with-next.within-page=\"always\"\r\n");
 1151       }
 1152       if(pap._fPageBreakBefore > 0)
 1153       {
 1154         buf.append("break-before=\"page\"\r\n");
 1155       }
 1156       if(pap._fNoAutoHyph == 0)
 1157       {
 1158         buf.append("hyphenate=\"true\"\r\n");
 1159       }
 1160       else
 1161       {
 1162         buf.append("hyphenate=\"false\"\r\n");
 1163       }
 1164       if(pap._dxaLeft > 0)
 1165       {
 1166         buf.append("start-indent=\"" + ((float)pap._dxaLeft)/1440.0f + "in\"\r\n");
 1167       }
 1168       if(pap._dxaRight > 0)
 1169       {
 1170         buf.append("end-indent=\"" + ((float)pap._dxaRight)/1440.0f + "in\"\r\n");
 1171       }
 1172       if(pap._dxaLeft1 != 0)
 1173       {
 1174         buf.append("text-indent=\"" + ((float)pap._dxaLeft1)/1440.0f + "in\"\r\n");
 1175       }
 1176       if(pap._lspd[1] == 0)
 1177       {
 1178         //buf.append("line-height=\"" + ((float)pap._lspd[0])/1440.0f + "in\"\r\n");
 1179       }
 1180       addBorder(buf, pap._brcTop, "top");
 1181       addBorder(buf, pap._brcBottom, "bottom");
 1182       addBorder(buf, pap._brcLeft, "left");
 1183       addBorder(buf, pap._brcRight, "right");
 1184   
 1185       buf.append(">");
 1186   
 1187     }
 1188   
 1189     private void addCharacterProperties(CHP chp, StringBuffer buf)
 1190     {
 1191       buf.append("<fo:inline ");
 1192       buf.append("font-family=\"" + _fonts.getFont(chp._ftcAscii) + "\" ");
 1193       buf.append("font-size=\"" + (chp._hps / 2) + "pt\" ");
 1194       buf.append("color=\"" + getColor(chp._ico) + "\" ");
 1195       //not supported by fop
 1196       //buf.append("letter-spacing=\"" + ((double)chp._dxaSpace)/1440.0f + "in\" ");
 1197   
 1198       addBorder(buf, chp._brc, "top");
 1199       addBorder(buf, chp._brc, "bottom");
 1200       addBorder(buf, chp._brc, "left");
 1201       addBorder(buf, chp._brc, "right");
 1202   
 1203       if(chp._italic)
 1204       {
 1205         buf.append("font-style=\"italic\" ");
 1206       }
 1207       if(chp._bold)
 1208       {
 1209         buf.append("font-weight=\"bold\" ");
 1210       }
 1211       if(chp._fSmallCaps)
 1212       {
 1213         buf.append("font-variant=\"small-caps\" ");
 1214       }
 1215       if(chp._fCaps)
 1216       {
 1217         buf.append("text-transform=\"uppercase\" ");
 1218       }
 1219       if(chp._fStrike || chp._fDStrike)
 1220       {
 1221         buf.append("text-decoration=\"line-through\" ");
 1222       }
 1223       if(chp._fShadow)
 1224       {
 1225         int size = chp._hps/24;
 1226         buf.append("text-shadow=\"" + size + "pt\"");
 1227       }
 1228       if(chp._fLowerCase)
 1229       {
 1230         buf.append("text-transform=\"lowercase\" ");
 1231       }
 1232       if(chp._kul > 0)
 1233       {
 1234         buf.append("text-decoration=\"underline\" ");
 1235       }
 1236       if(chp._highlighted)
 1237       {
 1238         buf.append("background-color=\"" + getColor(chp._icoHighlight) + "\" ");
 1239       }
 1240       if(chp._paddingStart != 0)
 1241       {
 1242         buf.append("padding-start=\"" + (float)chp._paddingStart/1440.0f + "in\" ");
 1243       }
 1244       if(chp._paddingEnd != 0)
 1245       {
 1246         buf.append("padding-end=\"" + (float)chp._paddingEnd/1440.0f + "in\" ");
 1247       }
 1248       buf.append(">");
 1249     }
 1250     private void addStaticContent(String flowName, HeaderFooter content)
 1251     {
 1252       _bodyBuffer.append("<fo:static-content flow-name=\"" + flowName + "\">");
 1253       //_bodyBuffer.append("<fo:float float=\"before\">");
 1254       addBlockContent(content.getStart(), content.getEnd(),_text, _paragraphTable, _characterTable);
 1255       //_bodyBuffer.append("</fo:float>");
 1256       _bodyBuffer.append("</fo:static-content>");
 1257   
 1258     }
 1259     private String getBulletText(LVL lvl, PAP pap)
 1260     {
 1261       StringBuffer bulletBuffer = new StringBuffer();
 1262       for(int x = 0; x < lvl._xst.length; x++)
 1263       {
 1264         if(lvl._xst[x] < 9)
 1265         {
 1266           LVL numLevel = _listTables.getLevel(pap._ilfo, lvl._xst[x]);
 1267           int num = numLevel._iStartAt;
 1268           if(lvl == numLevel)
 1269           {
 1270             numLevel._iStartAt++;
 1271           }
 1272           else if(num > 1)
 1273           {
 1274             num--;
 1275           }
 1276           bulletBuffer.append(NumberFormatter.getNumber(num, lvl._nfc));
 1277   
 1278         }
 1279         else
 1280         {
 1281           bulletBuffer.append(lvl._xst[x]);
 1282         }
 1283   
 1284       }
 1285       return bulletBuffer.toString();
 1286     }
 1287     /**
 1288      * finds all chpx's that are between start and end
 1289      */
 1290     private ArrayList findProperties(int start, int end, BTreeSet.BTreeNode root)
 1291     {
 1292       ArrayList results = new ArrayList();
 1293       BTreeSet.Entry[] entries = root.entries;
 1294   
 1295       for(int x = 0; x < entries.length; x++)
 1296       {
 1297         if(entries[x] != null)
 1298         {
 1299           BTreeSet.BTreeNode child = entries[x].child;
 1300           PropertyNode xNode = (PropertyNode)entries[x].element;
 1301           if(xNode != null)
 1302           {
 1303             int xStart = xNode.getStart();
 1304             int xEnd = xNode.getEnd();
 1305             if(xStart < end)
 1306             {
 1307               if(xStart >= start)
 1308               {
 1309                 if(child != null)
 1310                 {
 1311                   ArrayList beforeItems = findProperties(start, end, child);
 1312                   results.addAll(beforeItems);
 1313                 }
 1314                 results.add(xNode);
 1315               }
 1316               else if(start < xEnd)
 1317               {
 1318                 results.add(xNode);
 1319                 //break;
 1320               }
 1321             }
 1322             else
 1323             {
 1324               if(child != null)
 1325               {
 1326                 ArrayList beforeItems = findProperties(start, end, child);
 1327                 results.addAll(beforeItems);
 1328               }
 1329               break;
 1330             }
 1331           }
 1332           else if(child != null)
 1333           {
 1334             ArrayList afterItems = findProperties(start, end, child);
 1335             results.addAll(afterItems);
 1336           }
 1337         }
 1338         else
 1339         {
 1340           break;
 1341         }
 1342       }
 1343       return results;
 1344     }
 1345     private void openPage(String page, String type)
 1346     {
 1347       _bodyBuffer.append("<fo:page-sequence master-reference=\"" + page + "\">\r\n");
 1348     }
 1349     private void openFlow()
 1350     {
 1351       _bodyBuffer.append("<fo:flow flow-name=\"xsl-region-body\">\r\n");
 1352     }
 1353     private void closeFlow()
 1354     {
 1355       _bodyBuffer.append("</fo:flow>\r\n");
 1356     }
 1357     private void closePage()
 1358     {
 1359       _bodyBuffer.append("</fo:page-sequence>\r\n");
 1360     }
 1361     private void closeLine(StringBuffer buf)
 1362     {
 1363       buf.append("</fo:inline>");
 1364     }
 1365     private void closeBlock(StringBuffer buf)
 1366     {
 1367       buf.append("</fo:block>\r\n");
 1368     }
 1369     private ArrayList findPAPProperties(int start, int end, BTreeSet.BTreeNode root)
 1370     {
 1371       ArrayList results = new ArrayList();
 1372       BTreeSet.Entry[] entries = root.entries;
 1373   
 1374       for(int x = 0; x < entries.length; x++)
 1375       {
 1376         if(entries[x] != null)
 1377         {
 1378           BTreeSet.BTreeNode child = entries[x].child;
 1379           PapxNode papxNode = (PapxNode)entries[x].element;
 1380           if(papxNode != null)
 1381           {
 1382             int papxStart = papxNode.getStart();
 1383             if(papxStart < end)
 1384             {
 1385               if(papxStart >= start)
 1386               {
 1387                 if(child != null)
 1388                 {
 1389                   ArrayList beforeItems = findPAPProperties(start, end, child);
 1390                   results.addAll(beforeItems);
 1391                 }
 1392                 results.add(papxNode);
 1393               }
 1394             }
 1395             else
 1396             {
 1397               if(child != null)
 1398               {
 1399                 ArrayList beforeItems = findPAPProperties(start, end, child);
 1400                 results.addAll(beforeItems);
 1401               }
 1402               break;
 1403             }
 1404           }
 1405           else if(child != null)
 1406           {
 1407             ArrayList afterItems = findPAPProperties(start, end, child);
 1408             results.addAll(afterItems);
 1409           }
 1410         }
 1411         else
 1412         {
 1413           break;
 1414         }
 1415       }
 1416       return results;
 1417     }
 1418   
 1419     private String createPageMaster(SEP sep, String type, int section,
 1420                                     String regionBefore, String regionAfter)
 1421     {
 1422       float height = ((float)sep._yaPage)/1440.0f;
 1423       float width = ((float)sep._xaPage)/1440.0f;
 1424       float leftMargin = ((float)sep._dxaLeft)/1440.0f;
 1425       float rightMargin = ((float)sep._dxaRight)/1440.0f;
 1426       float topMargin = ((float)sep._dyaTop)/1440.0f;
 1427       float bottomMargin = ((float)sep._dyaBottom)/1440.0f;
 1428   
 1429       //add these to the header
 1430       String thisPage = type + "-page" + section;
 1431   
 1432       _headerBuffer.append("<fo:simple-page-master master-name=\"" +
 1433                           thisPage + "\"\r\n");
 1434       _headerBuffer.append("page-height=\"" + height + "in\"\r\n");
 1435       _headerBuffer.append("page-width=\"" + width + "in\"\r\n");
 1436       _headerBuffer.append(">\r\n");
 1437   
 1438   
 1439   
 1440       _headerBuffer.append("<fo:region-body ");
 1441       //top right bottom left
 1442   
 1443       _headerBuffer.append("margin=\"" + topMargin + "in " + rightMargin + "in " +
 1444                            bottomMargin + "in " + leftMargin + "in\"\r\n");
 1445   
 1446       //String style = null;
 1447       //String color = null;
 1448       addBorder(_headerBuffer, sep._brcTop, "top");
 1449       addBorder(_headerBuffer, sep._brcBottom, "bottom");
 1450       addBorder(_headerBuffer, sep._brcLeft, "left");
 1451       addBorder(_headerBuffer, sep._brcRight, "right");
 1452   
 1453       if(sep._ccolM1 > 0)
 1454       {
 1455         _headerBuffer.append("column-count=\"" + (sep._ccolM1 + 1) + "\" ");
 1456         if(sep._fEvenlySpaced)
 1457         {
 1458           _headerBuffer.append("column-gap=\"" + ((float)(sep._dxaColumns))/1440.0f + "in\"");
 1459         }
 1460         else
 1461         {
 1462           _headerBuffer.append("column-gap=\"0.25in\"");
 1463         }
 1464       }
 1465       _headerBuffer.append("/>\r\n");
 1466   
 1467       if(regionBefore != null)
 1468       {
 1469         _headerBuffer.append(regionBefore);
 1470       }
 1471       if(regionAfter != null)
 1472       {
 1473         _headerBuffer.append(regionAfter);
 1474       }
 1475   
 1476       _headerBuffer.append("</fo:simple-page-master>\r\n");
 1477       return thisPage;
 1478     }
 1479     private void addBorder(StringBuffer buf, short[] brc, String where)
 1480     {
 1481       if((brc[0] & 0xff00) != 0 && brc[0] != -1)
 1482       {
 1483         int type = (brc[0] & 0xff00) >> 8;
 1484         float width = ((float)(brc[0] & 0x00ff))/8.0f;
 1485         String style = getBorderStyle(brc[0]);
 1486         String color = getColor(brc[1] & 0x00ff);
 1487         String thickness = getBorderThickness(brc[0]);
 1488         buf.append("border-" + where + "-style=\"" + style + "\"\r\n");
 1489         buf.append("border-" + where + "-color=\"" + color + "\"\r\n");
 1490         buf.append("border-" + where + "-width=\"" + width + "pt\"\r\n");
 1491       }
 1492     }
 1493     public void closeDoc()
 1494     {
 1495       _headerBuffer.append("</fo:layout-master-set>");
 1496       _bodyBuffer.append("</fo:root>");
 1497       //_headerBuffer.append();
 1498   
 1499       //test code
 1500       try
 1501       {
 1502         OutputStreamWriter test = new OutputStreamWriter(new FileOutputStream(_outName), "8859_1");
 1503         test.write(_headerBuffer.toString());
 1504         test.write(_bodyBuffer.toString());
 1505         test.flush();
 1506         test.close();
 1507       }
 1508       catch(Throwable t)
 1509       {
 1510         t.printStackTrace();
 1511       }
 1512     }
 1513     private String getBorderThickness(int style)
 1514     {
 1515       switch(style)
 1516       {
 1517         case 1:
 1518           return "medium";
 1519         case 2:
 1520           return "thick";
 1521         case 3:
 1522           return "medium";
 1523         case 5:
 1524           return "thin";
 1525         default:
 1526           return "medium";
 1527       }
 1528     }
 1529   
 1530   
 1531     private String getColor(int ico)
 1532     {
 1533       switch(ico)
 1534       {
 1535         case 1:
 1536           return "black";
 1537         case 2:
 1538           return "blue";
 1539         case 3:
 1540           return "cyan";
 1541         case 4:
 1542           return "green";
 1543         case 5:
 1544           return "magenta";
 1545         case 6:
 1546           return "red";
 1547         case 7:
 1548           return "yellow";
 1549         case 8:
 1550           return "white";
 1551         case 9:
 1552           return "darkblue";
 1553         case 10:
 1554           return "darkcyan";
 1555         case 11:
 1556           return "darkgreen";
 1557         case 12:
 1558           return "darkmagenta";
 1559         case 13:
 1560           return "darkred";
 1561         case 14:
 1562           return "darkyellow";
 1563         case 15:
 1564           return "darkgray";
 1565         case 16:
 1566           return "lightgray";
 1567         default:
 1568           return "black";
 1569       }
 1570     }
 1571   
 1572     private String getBorderStyle(int type)
 1573     {
 1574   
 1575       switch(type)
 1576       {
 1577         case 1:
 1578         case 2:
 1579           return "solid";
 1580         case 3:
 1581           return "double";
 1582         case 5:
 1583           return "solid";
 1584         case 6:
 1585           return "dotted";
 1586         case 7:
 1587         case 8:
 1588           return "dashed";
 1589         case 9:
 1590           return "dotted";
 1591         case 10:
 1592         case 11:
 1593         case 12:
 1594         case 13:
 1595         case 14:
 1596         case 15:
 1597         case 16:
 1598         case 17:
 1599         case 18:
 1600         case 19:
 1601           return "double";
 1602         case 20:
 1603           return "solid";
 1604         case 21:
 1605           return "double";
 1606         case 22:
 1607           return "dashed";
 1608         case 23:
 1609           return "dashed";
 1610         case 24:
 1611           return "ridge";
 1612         case 25:
 1613           return "grooved";
 1614         default:
 1615           return "solid";
 1616       }
 1617     }
 1618     /**
 1619      * creates the List data
 1620      *
 1621      * @param tableStream Main table stream buffer.
 1622      */
 1623     private void createListTables(byte[] tableStream)
 1624     {
 1625   
 1626   
 1627       int lfoOffset = LittleEndian.getInt(_header, 0x2ea);
 1628       int lfoSize = LittleEndian.getInt(_header, 0x2ee);
 1629       byte[] plflfo = new byte[lfoSize];
 1630   
 1631       System.arraycopy(tableStream, lfoOffset, plflfo, 0, lfoSize);
 1632   
 1633       int lstOffset = LittleEndian.getInt(_header, 0x2e2);
 1634       int lstSize = LittleEndian.getInt(_header, 0x2e2);
 1635       if(lstOffset > 0 && lstSize > 0)
 1636       {
 1637         lstSize = lfoOffset - lstOffset;
 1638         byte[] plcflst = new byte[lstSize];
 1639         System.arraycopy(tableStream, lstOffset, plcflst, 0, lstSize);
 1640         _listTables = new ListTables(plcflst, plflfo);
 1641       }
 1642   
 1643     }
 1644     /**
 1645      * Creates the documents StyleSheet
 1646      *
 1647      * @param tableStream Main table stream buffer.
 1648      *
 1649      */
 1650     private void createStyleSheet(byte[] tableStream)
 1651     {
 1652         int stshIndex = LittleEndian.getInt(_header, 0xa2);
 1653         int stshSize = LittleEndian.getInt(_header, 0xa6);
 1654         byte[] stsh = new byte[stshSize];
 1655         System.arraycopy(tableStream, stshIndex, stsh, 0, stshSize);
 1656   
 1657         _styleSheet = new StyleSheet(stsh);
 1658   
 1659     }
 1660     /**
 1661      * creates the Font table
 1662      *
 1663      * @param tableStream Main table stream buffer.
 1664      */
 1665     private void createFontTable(byte[] tableStream)
 1666     {
 1667       int fontTableIndex = LittleEndian.getInt(_header, 0x112);
 1668       int fontTableSize = LittleEndian.getInt(_header, 0x116);
 1669       byte[] fontTable = new byte[fontTableSize];
 1670       System.arraycopy(tableStream, fontTableIndex, fontTable, 0, fontTableSize);
 1671       _fonts = new FontTable(fontTable);
 1672     }
 1673   
 1674   
 1675     private void overrideCellBorder(int row, int col, int height,
 1676                                     int width, TC tc, TAP tap)
 1677     {
 1678   
 1679       if(row == 0)
 1680       {
 1681         if(tc._brcTop[0] == 0 || tc._brcTop[0] == -1)
 1682         {
 1683           tc._brcTop = tap._brcTop;
 1684         }
 1685         if(tc._brcBottom[0] == 0 || tc._brcBottom[0] == -1)
 1686         {
 1687           tc._brcBottom = tap._brcHorizontal;
 1688         }
 1689       }
 1690       else if(row == (height - 1))
 1691       {
 1692         if(tc._brcTop[0] == 0 || tc._brcTop[0] == -1)
 1693         {
 1694           tc._brcTop = tap._brcHorizontal;
 1695         }
 1696         if(tc._brcBottom[0] == 0 || tc._brcBottom[0] == -1)
 1697         {
 1698           tc._brcBottom = tap._brcBottom;
 1699         }
 1700       }
 1701       else
 1702       {
 1703         if(tc._brcTop[0] == 0 || tc._brcTop[0] == -1)
 1704         {
 1705           tc._brcTop = tap._brcHorizontal;
 1706         }
 1707         if(tc._brcBottom[0] == 0 || tc._brcBottom[0] == -1)
 1708         {
 1709           tc._brcBottom = tap._brcHorizontal;
 1710         }
 1711       }
 1712       if(col == 0)
 1713       {
 1714         if(tc._brcLeft[0] == 0 || tc._brcLeft[0] == -1)
 1715         {
 1716           tc._brcLeft = tap._brcLeft;
 1717         }
 1718         if(tc._brcRight[0] == 0 || tc._brcRight[0] == -1)
 1719         {
 1720           tc._brcRight = tap._brcVertical;
 1721         }
 1722       }
 1723       else if(col == (width - 1))
 1724       {
 1725         if(tc._brcLeft[0] == 0 || tc._brcLeft[0] == -1)
 1726         {
 1727           tc._brcLeft = tap._brcVertical;
 1728         }
 1729         if(tc._brcRight[0] == 0 || tc._brcRight[0] == -1)
 1730         {
 1731           tc._brcRight = tap._brcRight;
 1732         }
 1733       }
 1734       else
 1735       {
 1736         if(tc._brcLeft[0] == 0 || tc._brcLeft[0] == -1)
 1737         {
 1738           tc._brcLeft = tap._brcVertical;
 1739         }
 1740         if(tc._brcRight[0] == 0 || tc._brcRight[0] == -1)
 1741         {
 1742           tc._brcRight = tap._brcVertical;
 1743         }
 1744       }
 1745     }
 1746     private void printTable()
 1747     {
 1748       if(_table != null)
 1749       {
 1750         int size = _table.size();
 1751   
 1752         //local buffers for the table
 1753         StringBuffer tableHeaderBuffer = new StringBuffer();
 1754         StringBuffer tableBodyBuffer = new StringBuffer();
 1755   
 1756         for(int x = 0; x < size; x++)
 1757         {
 1758           StringBuffer rowBuffer = tableBodyBuffer;
 1759           TableRow row = (TableRow)_table.get(x);
 1760           TAP tap = row.getTAP();
 1761           ArrayList cells = row.getCells();
 1762   
 1763           if(tap._fTableHeader)
 1764           {
 1765             rowBuffer = tableHeaderBuffer;
 1766           }
 1767           rowBuffer.append("<fo:table-row ");
 1768           if(tap._dyaRowHeight > 0)
 1769           {
 1770             rowBuffer.append("height=\"" + ((float)tap._dyaRowHeight)/1440.0f + "in\" ");
 1771           }
 1772           if(tap._fCantSplit)
 1773           {
 1774             rowBuffer.append("keep-together=\"always\" ");
 1775           }
 1776           rowBuffer.append(">");
 1777           //add cells
 1778           for(int y = 0; y < tap._itcMac; y++)
 1779           {
 1780             TC tc = tap._rgtc[y];
 1781             overrideCellBorder(x, y, size, tap._itcMac, tc, tap);
 1782             rowBuffer.append("<fo:table-cell ");
 1783             rowBuffer.append("width=\"" + ((float)(tap._rgdxaCenter[y+1] - tap._rgdxaCenter[y]))/1440.0f + "in\" ");
 1784             rowBuffer.append("padding-start=\"" + ((float)tap._dxaGapHalf)/1440.0f + "in\" ");
 1785             rowBuffer.append("padding-end=\"" + ((float)tap._dxaGapHalf)/1440.0f + "in\" ");
 1786             addBorder(rowBuffer, tc._brcTop, "top");
 1787             addBorder(rowBuffer, tc._brcLeft, "left");
 1788             addBorder(rowBuffer, tc._brcBottom, "bottom");
 1789             addBorder(rowBuffer, tc._brcRight, "right");
 1790             rowBuffer.append(">");
 1791             rowBuffer.append((String)cells.get(y));
 1792             rowBuffer.append("</fo:table-cell>");
 1793           }
 1794           rowBuffer.append("</fo:table-row>");
 1795         }
 1796         StringBuffer tableBuffer = new StringBuffer();
 1797         tableBuffer.append("<fo:table>");
 1798         if(tableHeaderBuffer.length() > 0)
 1799         {
 1800           tableBuffer.append("<fo:table-header>");
 1801           tableBuffer.append(tableHeaderBuffer.toString());
 1802           tableBuffer.append("</fo:table-header>");
 1803         }
 1804         tableBuffer.append("<fo:table-body>");
 1805         tableBuffer.append(tableBodyBuffer.toString());
 1806         tableBuffer.append("</fo:table-body>");
 1807         tableBuffer.append("</fo:table>");
 1808         _bodyBuffer.append(tableBuffer.toString());
 1809         _table = null;
 1810       }
 1811     }
 1812     private void initPclfHdd(byte[] tableStream)
 1813     {
 1814       int size = Utils.convertBytesToInt(_header, 0xf6);
 1815       int pos = Utils.convertBytesToInt(_header, 0xf2);
 1816   
 1817       _plcfHdd = new byte[size];
 1818   
 1819       System.arraycopy(tableStream, pos, _plcfHdd, 0, size);
 1820     }
 1821   
 1822   
 1823   
 1824   
 1825   }

Save This Page
Home » poi-src-3.2-FINAL-20081019 » org.apache.poi.hdf » extractor » [javadoc | source]