Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /* ====================================================================
      Licensed to the Apache Software Foundation (ASF) under one or more
      contributor license agreements.  See the NOTICE file distributed with
      this work for additional information regarding copyright ownership.
      The ASF licenses this file to You under the Apache License, Version 2.0
      (the "License"); you may not use this file except in compliance with
      the License.  You may obtain a copy of the License at
   
          http://www.apache.org/licenses/LICENSE-2.0
  
     Unless required by applicable law or agreed to in writing, software
     distributed under the License is distributed on an "AS IS" BASIS,
     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     See the License for the specific language governing permissions and
     limitations under the License.
  ==================================================================== */
  
  package org.apache.poi.hdf.extractor;
  
  
  import java.util.*;
  import java.io.*;
  
  
This class contains the main functionality for the Word file "reader". Much of the code in this class is based on the Word 97 document file format. Only works for non-complex files

Author(s):
Ryan Ackley
  
  public final class WordDocument {
  	// TODO - name this constant properly
  	private static final float K_1440_0F = 1440.0f;
byte buffer containing the main Document strea
  
    byte[] _header;
  
contains all style information for this document see Word 97 Doc spe
  
contains All list information for this documen
  
contains global Document properties for this documen
  
    DOP _docProps = new DOP();
  
    int _currentList = -1;
    int _tableSize;
    int _sectionCounter = 1;
  
fonts available for this documen
  
    FontTable _fonts;

  
document's text block
  
    BTreeSet _text = new BTreeSet();
  
document's character runs
  
    BTreeSet _characterTable = new BTreeSet();
  
document's paragraph
  
    BTreeSet _paragraphTable = new BTreeSet();
  
doucment's section
  
    BTreeSet _sectionTable = new BTreeSet();

  
used for XSL-FO conversio
  
    StringBuffer _headerBuffer = new StringBuffer();
  
used for XSL-FO conversio
  
    StringBuffer _bodyBuffer = new StringBuffer();
  
used for XSL-FO table conversio
  
used for XSL-FO table conversio
  
    ArrayList _cells;
  
used for XSL-FO table conversio
  
    ArrayList _table;

  
document's header and footer informatio
  
    byte[] _plcfHdd;

  
starting position of text in main document strea
  
    int _fcMin;
  
length of main document text strea
  
    int _ccpText;
  
length of footnotes tex
  
    int _ccpFtn;

  
The name of the file to write to
  
    private static String _outName;

  
OLE stuf
  
    private InputStream istream;
  
OLE stuf
  
    private POIFSFileSystem filesystem;
  
    //used internally
    private static int HEADER_EVEN_INDEX = 0;
    private static int HEADER_ODD_INDEX = 1;
    private static int FOOTER_EVEN_INDEX = 2;
    private static int FOOTER_ODD_INDEX = 3;
   private static int HEADER_FIRST_INDEX = 4;
   private static int FOOTER_FIRST_INDEX = 5;

  
right now this function takes one parameter: a Word file, and outputs an XSL-FO document at c:\test.xml (this is hardcoded)
 
   public static void main(String args[])
   {
       /*try
       {
         WordDocument file = new WordDocument(args[0], "r");
         Writer out = new BufferedWriter(new FileWriter(args[1]));
         file.writeAllText(out);
         out.flush();
         out.close();
       }
       catch(Throwable t)
       {
         t.printStackTrace();
       }*/
       try
       {
            = args[1];
           WordDocument file = new WordDocument(args[0]);
           file.closeDoc();
       }
       catch(Exception e)
       {
           e.printStackTrace();
       }
       System.exit(0);
   }
  
Spits out the document text

Parameters:
out The Writer to write the text to.
Throws:
java.io.IOException if there is a problem while reading from the file or writing out the text.
 
   public void writeAllText(Writer outthrows IOException
   {
     int textStart = Utils.convertBytesToInt(, 0x18);
     int textEnd = Utils.convertBytesToInt(, 0x1c);
     ArrayList textPieces = findProperties(textStarttextEnd.);
     int size = textPieces.size();
 
     for(int x = 0; x < sizex++)
     {
       TextPiece nextPiece = (TextPiece)textPieces.get(x);
       int start = nextPiece.getStart();
       int end = nextPiece.getEnd();
       boolean unicode = nextPiece.usesUnicode();
       int add = 1;
 
       if(unicode)
       {
         add = 2;
         char ch;
         for(int y = starty < endy += add)
         {
 	  ch = (char)Utils.convertBytesToShort(y);
 	  out.write(ch);
         }
       }
       else
       {
 	String sText = new String(startend-start);
 	out.write(sText);
       }
     }
   }
  
Constructs a Word document from fileName. Parses the document and places all the important stuff into data structures.

Parameters:
fileName The name of the file to read.
Throws:
java.io.IOException if there is a problem while parsing the document.
 
   public WordDocument(String fileNamethrows IOException
   {
   	this(new FileInputStream(fileName));
   }
 
   public WordDocument(InputStream inputStreamthrows IOException
   {
         //do Ole stuff
          = inputStream;
          = new POIFSFileSystem();
 
         //get important stuff from the Header block and parse all the
         //data structures
         readFIB();
 
         //get the SEPS for the main document text
         ArrayList sections = findProperties( + .);
 
         //iterate through sections, paragraphs, and character runs doing what
         //you will with the data.
         int size = sections.size();
         for(int x = 0; x < sizex++)
         {
           SepxNode node = (SepxNode)sections.get(x);
           int start = node.getStart();
           int end = node.getEnd();
           SEP sep = (SEP)StyleSheet.uncompressProperty(node.getSepx(), new SEP(), );
           writeSection(Math.max(start), Math.min( + end), sep);
         }
         //finish
         .close();
 
   }
  
Extracts the main document stream from the POI file then hands off to other functions that parse other areas.

 
   private void readFIB() throws IOException
   {
       //get the main document stream
       DocumentEntry headerProps =
         (DocumentEntry).getRoot().getEntry("WordDocument");
 
       //I call it the header but its also the main document stream
        = new byte[headerProps.getSize()];
       .createDocumentInputStream("WordDocument").read();
 
       //Get the information we need from the header
       int info = LittleEndian.getShort(, 0xa);
 
        = LittleEndian.getInt(, 0x18);
        = LittleEndian.getInt(, 0x4c);
        = LittleEndian.getInt(, 0x50);
 
       int charPLC = LittleEndian.getInt(, 0xfa);
       int charPlcSize = LittleEndian.getInt(, 0xfe);
       int parPLC = LittleEndian.getInt(, 0x102);
       int parPlcSize = LittleEndian.getInt(, 0x106);
       boolean useTable1 = (info & 0x200) != 0;
 
       //process the text and formatting properties
       processComplexFile(useTable1charPLCcharPlcSizeparPLCparPlcSize);
   }

  
Extracts the correct Table stream from the POI filesystem then hands off to other functions to process text and formatting info. the name is based on the fact that in Word 8(97) all text (not character or paragraph formatting) is stored in complex format.

Parameters:
useTable1 boolean that specifies if we should use table1 or table0
charTable offset in table stream of character property bin table
charPlcSize size of character property bin table
parTable offset in table stream of paragraph property bin table.
parPlcSize size of paragraph property bin table.
Returns:
boolean indocating success of
Throws:
java.io.IOException
 
   private void processComplexFile(boolean useTable1int charTable,
                                      int charPlcSizeint parTableint parPlcSizethrows IOException
   {
 
       //get the location of the piece table
       int complexOffset = LittleEndian.getInt(, 0x1a2);
 
       String tablename=null;
       DocumentEntry tableEntry = null;
       if(useTable1)
       {
           tablename="1Table";
       }
       else
       {
           tablename="0Table";
       }
       tableEntry = (DocumentEntry).getRoot().getEntry(tablename);
 
       //load the table stream into a buffer
       int size = tableEntry.getSize();
       byte[] tableStream = new byte[size];
       .createDocumentInputStream(tablename).read(tableStream);
 
       //init the DOP for this document
       initDocProperties(tableStream);
       //load the header/footer raw data for this document
       initPclfHdd(tableStream);
       //parse out the text locations
       findText(tableStreamcomplexOffset);
       //parse out text formatting
       findFormatting(tableStreamcharTablecharPlcSizeparTableparPlcSize);
 
   }
  
Goes through the piece table and parses out the info regarding the text blocks. For Word 97 and greater all text is stored in the "complex" way because of unicode.

Parameters:
tableStream buffer containing the main table stream.
beginning of the complex data.
Throws:
java.io.IOException
 
   private void findText(byte[] tableStreamint complexOffsetthrows IOException
   {
     //actual text
     int pos = complexOffset;
     //skips through the prms before we reach the piece table. These contain data
     //for actual fast saved files
     while(tableStream[pos] == 1)
     {
         pos++;
         int skip = LittleEndian.getShort(tableStreampos);
         pos += 2 + skip;
     }
     if(tableStream[pos] != 2)
     {
         throw new IOException("corrupted Word file");
     }
     //parse out the text pieces
     int pieceTableSize = LittleEndian.getInt(tableStream, ++pos);
     pos += 4;
     int pieces = (pieceTableSize - 4) / 12;
     for (int x = 0; x < piecesx++)
     {
         int filePos = LittleEndian.getInt(tableStreampos + ((pieces + 1) * 4) + (x * 8) + 2);
         boolean unicode = false;
         if ((filePos & 0x40000000) == 0)
         {
             unicode = true;
         }
         else
         {
             unicode = false;
             filePos &= ~(0x40000000);//gives me FC in doc stream
             filePos /= 2;
         }
         int totLength = LittleEndian.getInt(tableStreampos + (x + 1) * 4) -
                         LittleEndian.getInt(tableStreampos + (x * 4));
 
         TextPiece piece = new TextPiece(filePostotLengthunicode);
         .add(piece);
     }
   }

  
Does all of the formatting parsing

Parameters:
tableStream Main table stream buffer.
charOffset beginning of the character bin table.
chrPlcSize size of the char bin table.
parOffset offset of the paragraph bin table.
size of the paragraph bin table.
 
   private void findFormatting(byte[] tableStreamint charOffset,
                               int charPlcSizeint parOffsetint parPlcSize) {
       openDoc();
       createStyleSheet(tableStream);
       createListTables(tableStream);
       createFontTable(tableStream);
 
       //find character runs
       //Get all the chpx info and store it
 
       int arraySize = (charPlcSize - 4)/8;
 
       //first we must go through the bin table and find the fkps
       for(int x = 0; x < arraySizex++)
       {
 
 
           //get page number(has nothing to do with document page)
           //containing the chpx for the paragraph
           int PN = LittleEndian.getInt(tableStreamcharOffset + (4 * (arraySize + 1) + (4 * x)));
 
           byte[] fkp = new byte[512];
           System.arraycopy(, (PN * 512), fkp, 0, 512);
           //take each fkp and get the chpxs
           int crun = Utils.convertUnsignedByteToInt(fkp[511]);
           for(int y = 0; y < cruny++)
           {
               //get the beginning fc of each paragraph text run
               int fcStart = LittleEndian.getInt(fkpy * 4);
               int fcEnd = LittleEndian.getInt(fkp, (y+1) * 4);
               //get the offset in fkp of the papx for this paragraph
               int chpxOffset = 2 * Utils.convertUnsignedByteToInt(fkp[((crun + 1) * 4) + y]);
 
               //optimization if offset == 0 use "Normal" style
               if(chpxOffset == 0)
 
               {
                 .add(new ChpxNode(fcStartfcEndnew byte[0]));
                 continue;
               }
 
               int size = Utils.convertUnsignedByteToInt(fkp[chpxOffset]);
 
               byte[] chpx = new byte[size];
               System.arraycopy(fkp, ++chpxOffsetchpx, 0, size);
               //_papTable.put(Integer.valueOf(fcStart), papx);
               .add(new ChpxNode(fcStartfcEndchpx));
           }
 
       }
 
       //find paragraphs
       arraySize = (parPlcSize - 4)/8;
       //first we must go through the bin table and find the fkps
       for(int x = 0; x < arraySizex++)
       {
           int PN = LittleEndian.getInt(tableStreamparOffset + (4 * (arraySize + 1) + (4 * x)));
 
           byte[] fkp = new byte[512];
           System.arraycopy(, (PN * 512), fkp, 0, 512);
           //take each fkp and get the paps
           int crun = Utils.convertUnsignedByteToInt(fkp[511]);
           for(int y = 0; y < cruny++)
           {
               //get the beginning fc of each paragraph text run
               int fcStart = LittleEndian.getInt(fkpy * 4);
               int fcEnd = LittleEndian.getInt(fkp, (y+1) * 4);
               //get the offset in fkp of the papx for this paragraph
               int papxOffset = 2 * Utils.convertUnsignedByteToInt(fkp[((crun + 1) * 4) + (y * 13)]);
               int size = 2 * Utils.convertUnsignedByteToInt(fkp[papxOffset]);
               if(size == 0)
               {
                   size = 2 * Utils.convertUnsignedByteToInt(fkp[++papxOffset]);
               }
               else
               {
                   size--;
               }
 
               byte[] papx = new byte[size];
               System.arraycopy(fkp, ++papxOffsetpapx, 0, size);
               .add(new PapxNode(fcStartfcEndpapx));
 
           }
 
       }
 
       //find sections
       int fcMin = Utils.convertBytesToInt(, 0x18);
       int plcfsedFC = Utils.convertBytesToInt(, 0xca);
       int plcfsedSize = Utils.convertBytesToInt(, 0xce);
       byte[] plcfsed = new byte[plcfsedSize];
       System.arraycopy(tableStreamplcfsedFCplcfsed, 0, plcfsedSize);
 
       arraySize = (plcfsedSize - 4)/16;
 
       //openDoc();
 
       for(int x = 0; x < arraySizex++)
       {
           int sectionStart = Utils.convertBytesToInt(plcfsedx * 4) + fcMin;
           int sectionEnd = Utils.convertBytesToInt(plcfsed, (x+1) * 4) + fcMin;
           int sepxStart = Utils.convertBytesToInt(plcfsed, 4 * (arraySize + 1) + (x * 12) + 2);
           int sepxSize = Utils.convertBytesToShort(sepxStart);
           byte[] sepx = new byte[sepxSize];
           System.arraycopy(sepxStart + 2, sepx, 0, sepxSize);
           SepxNode node = new SepxNode(x + 1, sectionStartsectionEndsepx);
           .add(node);
       }
 
 
   }
 
   public void openDoc()
   {
     .append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\r\n");
     .append("<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\r\n");
     .append("<fo:layout-master-set>\r\n");
 
   }
   private HeaderFooter findSectionHdrFtr(int typeint index)
   {
     if(. < 50)
     {
       return new HeaderFooter(0,0,0);
     }
     int start =  +  + ;
     int end = start;
     int arrayIndex = 0;
 
     switch(type)
     {
       case .:
            arrayIndex = ( + (index * 6));
            break;
       case .:
            arrayIndex = ( + (index * 6));
            break;
       case .:
            arrayIndex = ( + (index * 6));
            break;
       case .:
            arrayIndex = ( + (index * 6));
            break;
       case .:
            arrayIndex = ( + (index * 6));
            break;
       case .:
            arrayIndex = ( + (index * 6));
            break;
     }
     start += Utils.convertBytesToInt(, (arrayIndex * 4));
     end += Utils.convertBytesToInt(, (arrayIndex + 1) * 4);
 
     HeaderFooter retValue = new HeaderFooter(typestartend);
 
     if((end - start) == 0 && index > 1)
     {
       retValue = findSectionHdrFtr(typeindex - 1);
     }
     return retValue;
   }
  
inits this document DOP structure.

Parameters:
tableStream The documents table stream.
 
   private void initDocProperties(byte[] tableStream)
   {
     int pos = LittleEndian.getInt(, 0x192);
     int size = LittleEndian.getInt(, 0x196);
     byte[] dop = new byte[size];
 
     System.arraycopy(tableStreamposdop, 0, size);
 
     . = (dop[0] & 0x1) > 0;
     . = (dop[0] & 0x60) >> 5;
 
     short num = LittleEndian.getShort(dop, 2);
     . = (num & 0x3);
     . = (short)(num & 0xfffc) >> 2;
     num = LittleEndian.getShort(dop, 52);
     . = num & 0x3;
     . = (short)(num & 0xfffc) >> 2;
     num = LittleEndian.getShort(dop, 54);
     . = num & 0x3;
   }
 
   public void writeSection(int startint endSEP sepBTreeSet text,
                            BTreeSet paragraphTableBTreeSet characterTable,
                            StyleSheet stylesheet)
   {
 
 
     String titlePage = null;
     String evenPage = null;
     String oddPage = null;
     String regPage = null;
 
     String sequenceName = null;
 
     /*if(sep._fTitlePage)
     {
       titlePage = createPageMaster(sep, "first", _sectionCounter, createRegion("before", "title-header"), createRegion("after", "title-footer"));
 
       if(!titleHeader.isEmpty())
       {
         addStaticContent("title-header" + _sectionCounter, titleHeader);
       }
       if(!titleFooter.isEmpty())
       {
         addStaticContent("title-footer" + _sectionCounter, titleFooter);
       }
     }*/
 
     {
       if(sep._fTitlePage)
       {
         String before = createRegion(truetitleHeadersep"title-header" + );
         String after = createRegion(falsetitleFootersep"title-footer" + );
         titlePage = createPageMaster(sep"first"beforeafter);
       }
       String before = createRegion(trueevenHeadersep"even-header" + );
       String after = createRegion(falseevenFootersep"even-footer" + );
       evenPage = createPageMaster(sep"even"beforeafter);
       before = createRegion(trueoddHeadersep"odd-header" + );
       after = createRegion(falseoddFootersep"odd-footer" + );
       oddPage = createPageMaster(sep"odd"beforeafter);
       sequenceName = createEvenOddPageSequence(titlePageevenPageoddPage);
 
       openPage(sequenceName"reference");
 
       if(sep._fTitlePage)
       {
 
 
         if(!titleHeader.isEmpty())
         {
           addStaticContent("title-header" + titleHeader);
         }
         if(!titleFooter.isEmpty())
         {
           addStaticContent("title-footer" + titleFooter);
         }
       }
 
       //handle the headers and footers for odd and even pages
       if(!oddHeader.isEmpty())
       {
         addStaticContent("odd-header" + oddHeader);
       }
       if(!oddFooter.isEmpty())
       {
         addStaticContent("odd-footer" + oddFooter);
       }
       if(!evenHeader.isEmpty())
       {
         addStaticContent("even-header" + evenHeader);
       }
       if(!evenFooter.isEmpty())
       {
         addStaticContent("even-footer" + evenFooter);
       }
       openFlow();
       addBlockContent(startendtextparagraphTablecharacterTable);
       closeFlow();
       closePage();
     }
     else
     {
       /*if(sep._fTitlePage)
       {
         String before = createRegion(true, titleHeader, sep);
         String after = createRegion(false, titleFooter, sep);
         titlePage = createPageMaster(sep, "first", _sectionCounter, before, after);
       }*/
       String before = createRegion(trueoddHeadersepnull);
       String after = createRegion(falseoddFootersepnull);
       regPage = createPageMaster(sep"page"beforeafter);
 
       if(sep._fTitlePage)
       {
         before = createRegion(truetitleHeadersep"title-header" + );
         after = createRegion(falsetitleFootersep"title-footer" + );
         titlePage = createPageMaster(sep"first"beforeafter);
         sequenceName = createPageSequence(titlePageregPage);
         openPage(sequenceName"reference");
 
         if(!titleHeader.isEmpty())
         {
           addStaticContent("title-header" + titleHeader);
         }
         if(!titleFooter.isEmpty())
         {
           addStaticContent("title-footer" + titleFooter);
         }
       }
       else
       {
         openPage(regPage"name");
       }
       if(!oddHeader.isEmpty())
       {
         addStaticContent("xsl-region-before"oddHeader);
       }
       if(!oddFooter.isEmpty())
       {
         addStaticContent("xsl-region-after"oddFooter);
       }
       openFlow();
       addBlockContent(startendtextparagraphTablecharacterTable);
       closeFlow();
       closePage();
     }
     ++;
   }
 
   private int calculateHeaderHeight(int startint endint pageWidth)
   {
     ArrayList paragraphs = findProperties(startend.);
     int size = paragraphs.size();
     ArrayList lineHeights = new ArrayList();
     //StyleContext context = StyleContext.getDefaultStyleContext();
 
     for(int x = 0; x < sizex++)
     {
       PapxNode node = (PapxNode)paragraphs.get(x);
       int parStart = Math.max(node.getStart(), start);
       int parEnd = Math.min(node.getEnd(), end);
 
       int lineWidth = 0;
       int maxHeight = 0;
 
       ArrayList textRuns = findProperties(parStartparEnd.);
       int charSize = textRuns.size();
 
       //StringBuffer lineBuffer = new StringBuffer();
       for(int y = 0; y < charSizey++)
       {
         ChpxNode charNode = (ChpxNode)textRuns.get(y);
         int istd = Utils.convertBytesToShort(node.getPapx(), 0);
         StyleDescription sd = .getStyleDescription(istd);
         CHP chp = (CHP)StyleSheet.uncompressProperty(charNode.getChpx(), sd.getCHP(), );
 
         //get Font info
         //FontMetrics metrics = getFontMetrics(chp, context);
 
         int height = 10;//metrics.getHeight();
         maxHeight = Math.max(maxHeightheight);
 
         int charStart = Math.max(parStartcharNode.getStart());
         int charEnd = Math.min(parEndcharNode.getEnd());
 
         ArrayList text = findProperties(charStartcharEnd.);
 
         int textSize = text.size();
         StringBuffer buf = new StringBuffer();
         for(int z = 0; z < textSizez++)
         {
 
           TextPiece piece = (TextPiece)text.get(z);
           int textStart = Math.max(piece.getStart(), charStart);
           int textEnd = Math.min(piece.getEnd(), charEnd);
 
           if(piece.usesUnicode())
           {
             addUnicodeText(textStarttextEndbuf);
           }
           else
           {
             addText(textStarttextEndbuf);
           }
         }
 
         String tempString = buf.toString();
         lineWidth += 10 * tempString.length();//metrics.stringWidth(tempString);
         if(lineWidth > pageWidth)
         {
           lineHeights.add(Integer.valueOf(maxHeight));
           maxHeight = 0;
           lineWidth = 0;
         }
       }
       lineHeights.add(Integer.valueOf(maxHeight));
     }
     int sum = 0;
     size = lineHeights.size();
     for(int x = 0; x < sizex++)
     {
       Integer height = (Integer)lineHeights.get(x);
       sum += height.intValue();
     }
 
     return sum;
   }
 /*  private FontMetrics getFontMetrics(CHP chp, StyleContext context)
   {
     String fontName = _fonts.getFont(chp._ftcAscii);
     int style = 0;
     if(chp._bold)
     {
       style |= Font.BOLD;
     }
     if(chp._italic)
     {
       style |= Font.ITALIC;
     }
 
     Font font = new Font(fontName, style, chp._hps/2);
 
 
     return context.getFontMetrics(font);
   }*/
   private String createRegion(boolean beforeHeaderFooter headerSEP sepString name)
   {
     if(header.isEmpty())
     {
       return "";
     }
     String region = "region-name=\"" + name + "\"";
     if(name == null)
     {
       region = "";
     }
     int height = calculateHeaderHeight(header.getStart(), header.getEnd(), sep._xaPage/20);
     int marginTop = 0;
     int marginBottom = 0;
     int extent = 0;
     String where = null;
     String align = null;
 
     if(before)
     {
       where = "before";
       align = "before";
       marginTop = sep._dyaHdrTop/20;
       extent = height + marginTop;
       sep._dyaTop = Math.max(extent*20, sep._dyaTop);
     }
     else
     {
       where = "after";
       align = "after";
       marginBottom = sep._dyaHdrBottom/20;
       extent = height + marginBottom;
       sep._dyaBottom = Math.max(extent*20, sep._dyaBottom);
     }
 
     int marginLeft = sep._dxaLeft/20;
     int marginRight = sep._dxaRight/20;
 
     return "<fo:region-" + where + " display-align=\"" + align + "\" extent=\""
              + extent + "pt\" "+region+"/>";
 // org.apache.fop.fo.expr.PropertyException:
 // Border and padding for region "xsl-region-before" must be '0'
 // (See 6.4.13 in XSL 1.0).
 //             extent + "pt\" padding-left=\"" + marginLeft + "pt\" padding-right=\"" +
 //             marginRight + "pt\" padding-top=\"" + marginTop + "pt\" padding-bottom=\"" +
 //             marginBottom + "pt\" " + region + "/>";
 
   }
   private String createRegion(String whereString name)
   {
     return "<fo:region-" + where + " overflow=\"scroll\" region-name=\"" + name + "\"/>";
   }
   private String createEvenOddPageSequence(String titlePageString evenPageString oddPageint counter)
   {
     String name = "my-sequence" + counter;
     .append("<fo:page-sequence-master master-name=\"" + name + "\"> ");
     .append("<fo:repeatable-page-master-alternatives>");
     if(titlePage != null)
     {
       .append("<fo:conditional-page-master-reference " +
                            "page-position=\"first\" master-reference=\"" +
                             titlePage + "\"/>");
     }
     .append("<fo:conditional-page-master-reference odd-or-even=\"odd\" ");
     .append("master-reference=\""oddPage + "\"/> ");
     .append("<fo:conditional-page-master-reference odd-or-even=\"even\" ");
     .append("master-reference=\"" + evenPage + "\"/> ");
     .append("</fo:repeatable-page-master-alternatives>");
     .append("</fo:page-sequence-master>");
     return name;
   }
   private String createPageSequence(String titlePageString regPageint counter)
   {
     String name = null;
     if(titlePage != null)
     {
       name = "my-sequence" + counter;
       .append("<fo:page-sequence-master master-name=\"" + name + "\"> ");
       .append("<fo:single-page-master-reference master-reference=\"" + titlePage + "\"/>");
       .append("<fo:repeatable-page-master-reference master-reference=\"" + regPage + "\"/>");
       .append("</fo:page-sequence-master>");
     }
     return name;
   }
   private void addBlockContent(int startint endBTreeSet text,
                               BTreeSet paragraphTableBTreeSet characterTable)
   {
 
     BTreeSet.BTreeNode root = paragraphTable.root;
     ArrayList pars = findProperties(startendroot);
     //root = characterTable.root;
     int size = pars.size();
 
     for(int c = 0; c < sizec++)
     {
       PapxNode currentNode = (PapxNode)pars.get(c);
       createParagraph(startendcurrentNodecharacterTabletext);
     }
     //closePage();
   }
   private String getTextAlignment(byte jc)
   {
     switch(jc)
     {
       case 0:
         return "start";
       case 1:
         return "center";
       case 2:
         return "end";
       case 3:
         return "justify";
       default:
         return "left";
     }
   }
   private void createParagraph(int startint endPapxNode currentNode,
                                BTreeSet characterTableBTreeSet text)
   {
     StringBuffer blockBuffer = ;
     byte[] papx = currentNode.getPapx();
     int istd = Utils.convertBytesToShort(papx, 0);
     PAP pap = (PAP)StyleSheet.uncompressProperty(papxstd.getPAP(), );
 
     //handle table cells
     if(pap._fInTable > 0)
     {
       if(pap._fTtp == 0)
       {
         if( == null)
         {
            = new StringBuffer();
         }
         blockBuffer = ;
       }
       else
       {
         if( == null)
         {
            = new ArrayList();
         }
         TAP tap = (TAP)StyleSheet.uncompressProperty(papxnew TAP(), );
         TableRow nextRow = new TableRow(tap);
         .add(nextRow);
          = null;
         return;
       }
     }
     else
     {
       //just prints out any table that is stored in _table
       printTable();
     }
 
     if(pap._ilfo > 0)
     {
       LVL lvl = .getLevel(pap._ilfopap._ilvl);
       addListParagraphContent(lvlblockBufferpapcurrentNodestartendstd);
     }
     else
     {
       addParagraphContent(blockBufferpapcurrentNodestartendstd);
     }
 
   }
 
   private void addListParagraphContent(LVL lvlStringBuffer blockBufferPAP pap,
                                        PapxNode currentNodeint startint end,
                                        StyleDescription std)
   {
     pap = (PAP)StyleSheet.uncompressProperty(lvl._papxpapfalse);
 
     addParagraphProperties(papblockBuffer);
 
     ArrayList charRuns = findProperties(Math.max(currentNode.getStart(), start),
                                      Math.min(currentNode.getEnd(), end),
                                      .);
     int len = charRuns.size();
 
     CHP numChp = (CHP)StyleSheet.uncompressProperty(((ChpxNode)charRuns.get(len-1)).getChpx(), std.getCHP(), );
 
     numChp = (CHP)StyleSheet.uncompressProperty(lvl._chpxnumChp);
 
     //StyleContext context = StyleContext.getDefaultStyleContext();
     //FontMetrics metrics = getFontMetrics(numChp, context);
     int indent = -1 * pap._dxaLeft1;
     String bulletText = getBulletText(lvlpap);
 
     indent = indent - (bulletText.length() * 10) * 20;//(metrics.stringWidth(bulletText) * 20);
 
     if(indent > 0)
     {
       numChp._paddingEnd = (short)indent;
     }
 
     addCharacterProperties(numChpblockBuffer);
     int listNum = 0;
 
     //if(number != null)
     //{
     blockBuffer.append(bulletText);
       //listNum = 1;
     //}
 
     //for(;listNum < lvl._xst.length; listNum++)
     //{
     //  addText(lvl._xst[listNum], blockBuffer);
     //}
 
 
     switch (lvl._ixchFollow)
     {
       case 0:
         addText('\u0009'blockBuffer);
         break;
       case 1:
         addText(' 'blockBuffer);
         break;
     }
 
     closeLine(blockBuffer);
     for(int x = 0; x < lenx++)
     {
       ChpxNode charNode = (ChpxNode)charRuns.get(x);
       byte[] chpx = charNode.getChpx();
       CHP chp = (CHP)StyleSheet.uncompressProperty(chpxstd.getCHP(), );
      addCharacterProperties(chpblockBuffer);
      int charStart = Math.max(charNode.getStart(), currentNode.getStart());
      int charEnd = Math.min(charNode.getEnd(), currentNode.getEnd());
      ArrayList textRuns = findProperties(charStartcharEnd.);
      int textRunLen = textRuns.size();
      for(int y = 0; y < textRunLeny++)
      {
        TextPiece piece = (TextPiece)textRuns.get(y);
        charStart = Math.max(charStartpiece.getStart());
        charEnd = Math.min(charEndpiece.getEnd());
        if(piece.usesUnicode())
        {
          addUnicodeText(charStartcharEndblockBuffer);
        }
        else
        {
          addText(charStartcharEndblockBuffer);
        }
        closeLine(blockBuffer);
      }
    }
    closeBlock(blockBuffer);
  }
  private void addParagraphContent(StringBuffer blockBufferPAP pap,
                                   PapxNode currentNodeint startint end,
                                   StyleDescription std)
  {
    addParagraphProperties(papblockBuffer);
    ArrayList charRuns = findProperties(Math.max(currentNode.getStart(), start),
                                     Math.min(currentNode.getEnd(), end),
                                     .);
    int len = charRuns.size();
    for(int x = 0; x < lenx++)
    {
      ChpxNode charNode = (ChpxNode)charRuns.get(x);
      byte[] chpx = charNode.getChpx();
      CHP chp = (CHP)StyleSheet.uncompressProperty(chpxstd.getCHP(), );
      addCharacterProperties(chpblockBuffer);
      int charStart = Math.max(charNode.getStart(), currentNode.getStart());
      int charEnd = Math.min(charNode.getEnd(), currentNode.getEnd());
      ArrayList textRuns = findProperties(charStartcharEnd.);
      int textRunLen = textRuns.size();
      for(int y = 0; y < textRunLeny++)
      {
        TextPiece piece = (TextPiece)textRuns.get(y);
        charStart = Math.max(charStartpiece.getStart());
        charEnd = Math.min(charEndpiece.getEnd());
        if(piece.usesUnicode())
        {
          addUnicodeText(charStartcharEndblockBuffer);
        }
        else
        {
          addText(charStartcharEndblockBuffer);
        }
        closeLine(blockBuffer);
      }
    }
    closeBlock(blockBuffer);
  }
  private void addText(int startint endStringBuffer buf)
  {
    for(int x = startx < endx++)
    {
      char ch = '?';
      ch = (char)[x];
      addText(chbuf);
    }
  }
  private void addText(char chStringBuffer buf)
  {
    int num = 0xffff & ch;
    if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
      (ch >= '0' && ch <= '9') || ch == '_' || ch == ' ' || ch == '-' || ch == '.' || ch == '$')
    {
      buf.append(ch);
    }
    else if(num == 0x07 &&  != null)
    {
      if( == null)
      {
         = new ArrayList();
      }
       = null;
    }
    else
    {
      

Todo:
handle special characters
      if(num < 0x20)
      num=0x20;
      buf.append("&#");
      buf.append(num);
      buf.append(';');
    }
  }
  private void addUnicodeText(int startint endStringBuffer buf)
  {
    for(int x = startx < endx += 2)
    {
      char ch = Utils.getUnicodeCharacter(