0001: /* ====================================================================
0002: Licensed to the Apache Software Foundation (ASF) under one or more
0003: contributor license agreements. See the NOTICE file distributed with
0004: this work for additional information regarding copyright ownership.
0005: The ASF licenses this file to You under the Apache License, Version 2.0
0006: (the "License"); you may not use this file except in compliance with
0007: the License. You may obtain a copy of the License at
0008:
0009: http://www.apache.org/licenses/LICENSE-2.0
0010:
0011: Unless required by applicable law or agreed to in writing, software
0012: distributed under the License is distributed on an "AS IS" BASIS,
0013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: See the License for the specific language governing permissions and
0015: limitations under the License.
0016: ==================================================================== */
0017:
0018: package org.apache.poi.hdf.extractor;
0019:
0020: import org.apache.poi.hdf.extractor.util.*;
0021: import org.apache.poi.hdf.extractor.data.*;
0022: import java.util.*;
0023: import java.io.*;
0024:
0025: import org.apache.poi.poifs.filesystem.POIFSFileSystem;
0026: import org.apache.poi.poifs.filesystem.DocumentEntry;
0027:
0028: import org.apache.poi.util.LittleEndian;
0029:
0030: /**
0031: * This class contains the main functionality for the Word file "reader". Much
0032: * of the code in this class is based on the Word 97 document file format. Only
0033: * works for non-complex files
0034: *
0035: * @author Ryan Ackley
0036: */
0037:
0038: public class WordDocument {
0039: /** byte buffer containing the main Document stream*/
0040: byte[] _header;
0041: /** contains all style information for this document see Word 97 Doc spec*/
0042: StyleSheet _styleSheet;
0043: /** contains All list information for this document*/
0044: ListTables _listTables;
0045: /** contains global Document properties for this document*/
0046: DOP _docProps = new DOP();
0047:
0048: int _currentList = -1;
0049: int _tableSize;
0050: int _sectionCounter = 1;
0051: /** fonts available for this document*/
0052: FontTable _fonts;
0053:
0054: /** document's text blocks*/
0055: BTreeSet _text = new BTreeSet();
0056: /** document's character runs */
0057: BTreeSet _characterTable = new BTreeSet();
0058: /** document's paragraphs*/
0059: BTreeSet _paragraphTable = new BTreeSet();
0060: /** doucment's sections*/
0061: BTreeSet _sectionTable = new BTreeSet();
0062:
0063: /** used for XSL-FO conversion*/
0064: StringBuffer _headerBuffer = new StringBuffer();
0065: /** used for XSL-FO conversion*/
0066: StringBuffer _bodyBuffer = new StringBuffer();
0067: /** used for XSL-FO table conversion*/
0068: StringBuffer _cellBuffer;
0069: /** used for XSL-FO table conversion*/
0070: ArrayList _cells;
0071: /** used for XSL-FO table conversion*/
0072: ArrayList _table;
0073:
0074: /** document's header and footer information*/
0075: byte[] _plcfHdd;
0076:
0077: /** starting position of text in main document stream*/
0078: int _fcMin;
0079: /** length of main document text stream*/
0080: int _ccpText;
0081: /** length of footnotes text*/
0082: int _ccpFtn;
0083:
0084: /** The name of the file to write to */
0085: private static String _outName;
0086:
0087: /** OLE stuff*/
0088: private InputStream istream;
0089: /** OLE stuff*/
0090: private POIFSFileSystem filesystem;
0091:
0092: //used internally
0093: private static int HEADER_EVEN_INDEX = 0;
0094: private static int HEADER_ODD_INDEX = 1;
0095: private static int FOOTER_EVEN_INDEX = 2;
0096: private static int FOOTER_ODD_INDEX = 3;
0097: private static int HEADER_FIRST_INDEX = 4;
0098: private static int FOOTER_FIRST_INDEX = 5;
0099:
0100: /**
0101: * right now this function takes one parameter: a Word file, and outputs an
0102: * XSL-FO document at c:\test.xml (this is hardcoded)
0103: */
0104: public static void main(String args[]) {
0105: /*try
0106: {
0107: WordDocument file = new WordDocument(args[0], "r");
0108: Writer out = new BufferedWriter(new FileWriter(args[1]));
0109: file.writeAllText(out);
0110: out.flush();
0111: out.close();
0112: }
0113: catch(Throwable t)
0114: {
0115: t.printStackTrace();
0116: }*/
0117: try {
0118: _outName = args[1];
0119: WordDocument file = new WordDocument(args[0]);
0120: file.closeDoc();
0121: } catch (Exception e) {
0122: e.printStackTrace();
0123: }
0124: System.exit(0);
0125: }
0126:
0127: /**
0128: * Spits out the document text
0129: *
0130: * @param out The Writer to write the text to.
0131: * @throws IOException if there is a problem while reading from the file or
0132: * writing out the text.
0133: */
0134: public void writeAllText(Writer out) throws IOException {
0135: int textStart = Utils.convertBytesToInt(_header, 0x18);
0136: int textEnd = Utils.convertBytesToInt(_header, 0x1c);
0137: ArrayList textPieces = findProperties(textStart, textEnd,
0138: _text.root);
0139: int size = textPieces.size();
0140:
0141: for (int x = 0; x < size; x++) {
0142: TextPiece nextPiece = (TextPiece) textPieces.get(x);
0143: int start = nextPiece.getStart();
0144: int end = nextPiece.getEnd();
0145: boolean unicode = nextPiece.usesUnicode();
0146: int add = 1;
0147:
0148: if (unicode) {
0149: add = 2;
0150: char ch;
0151: for (int y = start; y < end; y += add) {
0152: ch = (char) Utils.convertBytesToShort(_header, y);
0153: out.write(ch);
0154: }
0155: } else {
0156: String sText = new String(_header, start, end - start);
0157: out.write(sText);
0158: }
0159: }
0160: }
0161:
0162: /**
0163: * Constructs a Word document from fileName. Parses the document and places
0164: * all the important stuff into data structures.
0165: *
0166: * @param fileName The name of the file to read.
0167: * @throws IOException if there is a problem while parsing the document.
0168: */
0169: public WordDocument(String fileName) throws IOException {
0170: this (new FileInputStream(fileName));
0171: }
0172:
0173: public WordDocument(InputStream inputStream) throws IOException {
0174: //do Ole stuff
0175: istream = inputStream;
0176: filesystem = new POIFSFileSystem(istream);
0177:
0178: //get important stuff from the Header block and parse all the
0179: //data structures
0180: readFIB();
0181:
0182: //get the SEPS for the main document text
0183: ArrayList sections = findProperties(_fcMin, _fcMin + _ccpText,
0184: _sectionTable.root);
0185:
0186: //iterate through sections, paragraphs, and character runs doing what
0187: //you will with the data.
0188: int size = sections.size();
0189: for (int x = 0; x < size; x++) {
0190: SepxNode node = (SepxNode) sections.get(x);
0191: int start = node.getStart();
0192: int end = node.getEnd();
0193: SEP sep = (SEP) StyleSheet.uncompressProperty(node
0194: .getSepx(), new SEP(), _styleSheet);
0195: writeSection(Math.max(_fcMin, start), Math.min(_fcMin
0196: + _ccpText, end), sep, _text, _paragraphTable,
0197: _characterTable, _styleSheet);
0198: }
0199: //finish
0200: istream.close();
0201:
0202: }
0203:
0204: /**
0205: * Extracts the main document stream from the POI file then hands off to other
0206: * functions that parse other areas.
0207: *
0208: * @throws IOException
0209: */
0210: private void readFIB() throws IOException {
0211: //get the main document stream
0212: DocumentEntry headerProps = (DocumentEntry) filesystem
0213: .getRoot().getEntry("WordDocument");
0214:
0215: //I call it the header but its also the main document stream
0216: _header = new byte[headerProps.getSize()];
0217: filesystem.createDocumentInputStream("WordDocument").read(
0218: _header);
0219:
0220: //Get the information we need from the header
0221: int info = LittleEndian.getShort(_header, 0xa);
0222:
0223: _fcMin = LittleEndian.getInt(_header, 0x18);
0224: _ccpText = LittleEndian.getInt(_header, 0x4c);
0225: _ccpFtn = LittleEndian.getInt(_header, 0x50);
0226:
0227: int charPLC = LittleEndian.getInt(_header, 0xfa);
0228: int charPlcSize = LittleEndian.getInt(_header, 0xfe);
0229: int parPLC = LittleEndian.getInt(_header, 0x102);
0230: int parPlcSize = LittleEndian.getInt(_header, 0x106);
0231: boolean useTable1 = (info & 0x200) != 0;
0232:
0233: //process the text and formatting properties
0234: processComplexFile(useTable1, charPLC, charPlcSize, parPLC,
0235: parPlcSize);
0236: }
0237:
0238: /**
0239: * Extracts the correct Table stream from the POI filesystem then hands off to
0240: * other functions to process text and formatting info. the name is based on
0241: * the fact that in Word 8(97) all text (not character or paragraph formatting)
0242: * is stored in complex format.
0243: *
0244: * @param useTable1 boolean that specifies if we should use table1 or table0
0245: * @param charTable offset in table stream of character property bin table
0246: * @param charPlcSize size of character property bin table
0247: * @param parTable offset in table stream of paragraph property bin table.
0248: * @param parPlcSize size of paragraph property bin table.
0249: * @return boolean indocating success of
0250: * @throws IOException
0251: */
0252: private void processComplexFile(boolean useTable1, int charTable,
0253: int charPlcSize, int parTable, int parPlcSize)
0254: throws IOException {
0255:
0256: //get the location of the piece table
0257: int complexOffset = LittleEndian.getInt(_header, 0x1a2);
0258:
0259: String tablename = null;
0260: DocumentEntry tableEntry = null;
0261: if (useTable1) {
0262: tablename = "1Table";
0263: } else {
0264: tablename = "0Table";
0265: }
0266: tableEntry = (DocumentEntry) filesystem.getRoot().getEntry(
0267: tablename);
0268:
0269: //load the table stream into a buffer
0270: int size = tableEntry.getSize();
0271: byte[] tableStream = new byte[size];
0272: filesystem.createDocumentInputStream(tablename).read(
0273: tableStream);
0274:
0275: //init the DOP for this document
0276: initDocProperties(tableStream);
0277: //load the header/footer raw data for this document
0278: initPclfHdd(tableStream);
0279: //parse out the text locations
0280: findText(tableStream, complexOffset);
0281: //parse out text formatting
0282: findFormatting(tableStream, charTable, charPlcSize, parTable,
0283: parPlcSize);
0284:
0285: }
0286:
0287: /**
0288: * Goes through the piece table and parses out the info regarding the text
0289: * blocks. For Word 97 and greater all text is stored in the "complex" way
0290: * because of unicode.
0291: *
0292: * @param tableStream buffer containing the main table stream.
0293: * @param beginning of the complex data.
0294: * @throws IOException
0295: */
0296: private void findText(byte[] tableStream, int complexOffset)
0297: throws IOException {
0298: //actual text
0299: int pos = complexOffset;
0300: //skips through the prms before we reach the piece table. These contain data
0301: //for actual fast saved files
0302: while (tableStream[pos] == 1) {
0303: pos++;
0304: int skip = LittleEndian.getShort(tableStream, pos);
0305: pos += 2 + skip;
0306: }
0307: if (tableStream[pos] != 2) {
0308: throw new IOException("corrupted Word file");
0309: } else {
0310: //parse out the text pieces
0311: int pieceTableSize = LittleEndian
0312: .getInt(tableStream, ++pos);
0313: pos += 4;
0314: int pieces = (pieceTableSize - 4) / 12;
0315: for (int x = 0; x < pieces; x++) {
0316: int filePos = LittleEndian.getInt(tableStream, pos
0317: + ((pieces + 1) * 4) + (x * 8) + 2);
0318: boolean unicode = false;
0319: if ((filePos & 0x40000000) == 0) {
0320: unicode = true;
0321: } else {
0322: unicode = false;
0323: filePos &= ~(0x40000000);//gives me FC in doc stream
0324: filePos /= 2;
0325: }
0326: int totLength = LittleEndian.getInt(tableStream, pos
0327: + (x + 1) * 4)
0328: - LittleEndian.getInt(tableStream, pos
0329: + (x * 4));
0330:
0331: TextPiece piece = new TextPiece(filePos, totLength,
0332: unicode);
0333: _text.add(piece);
0334:
0335: }
0336:
0337: }
0338: }
0339:
0340: /**
0341: * Does all of the formatting parsing
0342: *
0343: * @param tableStream Main table stream buffer.
0344: * @param charOffset beginning of the character bin table.
0345: * @param chrPlcSize size of the char bin table.
0346: * @param parOffset offset of the paragraph bin table.
0347: * @param size of the paragraph bin table.
0348: */
0349: private void findFormatting(byte[] tableStream, int charOffset,
0350: int charPlcSize, int parOffset, int parPlcSize)
0351: throws IOException {
0352: openDoc();
0353: createStyleSheet(tableStream);
0354: createListTables(tableStream);
0355: createFontTable(tableStream);
0356:
0357: //find character runs
0358: //Get all the chpx info and store it
0359:
0360: int arraySize = (charPlcSize - 4) / 8;
0361:
0362: //first we must go through the bin table and find the fkps
0363: for (int x = 0; x < arraySize; x++) {
0364:
0365: //get page number(has nothing to do with document page)
0366: //containing the chpx for the paragraph
0367: int PN = LittleEndian.getInt(tableStream, charOffset
0368: + (4 * (arraySize + 1) + (4 * x)));
0369:
0370: byte[] fkp = new byte[512];
0371: System.arraycopy(_header, (PN * 512), fkp, 0, 512);
0372: //take each fkp and get the chpxs
0373: int crun = Utils.convertUnsignedByteToInt(fkp[511]);
0374: for (int y = 0; y < crun; y++) {
0375: //get the beginning fc of each paragraph text run
0376: int fcStart = LittleEndian.getInt(fkp, y * 4);
0377: int fcEnd = LittleEndian.getInt(fkp, (y + 1) * 4);
0378: //get the offset in fkp of the papx for this paragraph
0379: int chpxOffset = 2 * Utils
0380: .convertUnsignedByteToInt(fkp[((crun + 1) * 4)
0381: + y]);
0382:
0383: //optimization if offset == 0 use "Normal" style
0384: if (chpxOffset == 0)
0385:
0386: {
0387: _characterTable.add(new ChpxNode(fcStart, fcEnd,
0388: new byte[0]));
0389: continue;
0390: }
0391:
0392: int size = Utils
0393: .convertUnsignedByteToInt(fkp[chpxOffset]);
0394:
0395: byte[] chpx = new byte[size];
0396: System.arraycopy(fkp, ++chpxOffset, chpx, 0, size);
0397: //_papTable.put(new Integer(fcStart), papx);
0398: _characterTable.add(new ChpxNode(fcStart, fcEnd, chpx));
0399: }
0400:
0401: }
0402:
0403: //find paragraphs
0404: arraySize = (parPlcSize - 4) / 8;
0405: //first we must go through the bin table and find the fkps
0406: for (int x = 0; x < arraySize; x++) {
0407: int PN = LittleEndian.getInt(tableStream, parOffset
0408: + (4 * (arraySize + 1) + (4 * x)));
0409:
0410: byte[] fkp = new byte[512];
0411: System.arraycopy(_header, (PN * 512), fkp, 0, 512);
0412: //take each fkp and get the paps
0413: int crun = Utils.convertUnsignedByteToInt(fkp[511]);
0414: for (int y = 0; y < crun; y++) {
0415: //get the beginning fc of each paragraph text run
0416: int fcStart = LittleEndian.getInt(fkp, y * 4);
0417: int fcEnd = LittleEndian.getInt(fkp, (y + 1) * 4);
0418: //get the offset in fkp of the papx for this paragraph
0419: int papxOffset = 2 * Utils
0420: .convertUnsignedByteToInt(fkp[((crun + 1) * 4)
0421: + (y * 13)]);
0422: int size = 2 * Utils
0423: .convertUnsignedByteToInt(fkp[papxOffset]);
0424: if (size == 0) {
0425: size = 2 * Utils
0426: .convertUnsignedByteToInt(fkp[++papxOffset]);
0427: } else {
0428: size--;
0429: }
0430:
0431: byte[] papx = new byte[size];
0432: System.arraycopy(fkp, ++papxOffset, papx, 0, size);
0433: _paragraphTable.add(new PapxNode(fcStart, fcEnd, papx));
0434:
0435: }
0436:
0437: }
0438:
0439: //find sections
0440: int fcMin = Utils.convertBytesToInt(_header, 0x18);
0441: int plcfsedFC = Utils.convertBytesToInt(_header, 0xca);
0442: int plcfsedSize = Utils.convertBytesToInt(_header, 0xce);
0443: byte[] plcfsed = new byte[plcfsedSize];
0444: System.arraycopy(tableStream, plcfsedFC, plcfsed, 0,
0445: plcfsedSize);
0446:
0447: arraySize = (plcfsedSize - 4) / 16;
0448:
0449: //openDoc();
0450:
0451: for (int x = 0; x < arraySize; x++) {
0452: int sectionStart = Utils.convertBytesToInt(plcfsed, x * 4)
0453: + fcMin;
0454: int sectionEnd = Utils.convertBytesToInt(plcfsed,
0455: (x + 1) * 4)
0456: + fcMin;
0457: int sepxStart = Utils.convertBytesToInt(plcfsed, 4
0458: * (arraySize + 1) + (x * 12) + 2);
0459: int sepxSize = Utils
0460: .convertBytesToShort(_header, sepxStart);
0461: byte[] sepx = new byte[sepxSize];
0462: System.arraycopy(_header, sepxStart + 2, sepx, 0, sepxSize);
0463: SepxNode node = new SepxNode(x + 1, sectionStart,
0464: sectionEnd, sepx);
0465: _sectionTable.add(node);
0466: }
0467:
0468: }
0469:
0470: public void openDoc() {
0471: _headerBuffer
0472: .append("<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\r\n");
0473: _headerBuffer
0474: .append("<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\r\n");
0475: _headerBuffer.append("<fo:layout-master-set>\r\n");
0476:
0477: }
0478:
0479: private HeaderFooter findSectionHdrFtr(int type, int index) {
0480: if (_plcfHdd.length < 50) {
0481: return new HeaderFooter(0, 0, 0);
0482: }
0483: int start = _fcMin + _ccpText + _ccpFtn;
0484: int end = start;
0485: int arrayIndex = 0;
0486:
0487: switch (type) {
0488: case HeaderFooter.HEADER_EVEN:
0489: arrayIndex = (HEADER_EVEN_INDEX + (index * 6));
0490: break;
0491: case HeaderFooter.FOOTER_EVEN:
0492: arrayIndex = (FOOTER_EVEN_INDEX + (index * 6));
0493: break;
0494: case HeaderFooter.HEADER_ODD:
0495: arrayIndex = (HEADER_ODD_INDEX + (index * 6));
0496: break;
0497: case HeaderFooter.FOOTER_ODD:
0498: arrayIndex = (FOOTER_ODD_INDEX + (index * 6));
0499: break;
0500: case HeaderFooter.HEADER_FIRST:
0501: arrayIndex = (HEADER_FIRST_INDEX + (index * 6));
0502: break;
0503: case HeaderFooter.FOOTER_FIRST:
0504: arrayIndex = (FOOTER_FIRST_INDEX + (index * 6));
0505: break;
0506: }
0507: start += Utils.convertBytesToInt(_plcfHdd, (arrayIndex * 4));
0508: end += Utils.convertBytesToInt(_plcfHdd, (arrayIndex + 1) * 4);
0509:
0510: HeaderFooter retValue = new HeaderFooter(type, start, end);
0511:
0512: if ((end - start) == 0 && index > 1) {
0513: retValue = findSectionHdrFtr(type, index - 1);
0514: }
0515: return retValue;
0516: }
0517:
0518: /**
0519: * inits this document DOP structure.
0520: *
0521: * @param tableStream The documents table stream.
0522: */
0523: private void initDocProperties(byte[] tableStream) {
0524: int pos = LittleEndian.getInt(_header, 0x192);
0525: int size = LittleEndian.getInt(_header, 0x196);
0526: byte[] dop = new byte[size];
0527:
0528: System.arraycopy(tableStream, pos, dop, 0, size);
0529:
0530: _docProps._fFacingPages = (dop[0] & 0x1) > 0;
0531: _docProps._fpc = (dop[0] & 0x60) >> 5;
0532:
0533: short num = LittleEndian.getShort(dop, 2);
0534: _docProps._rncFtn = (num & 0x3);
0535: _docProps._nFtn = (short) (num & 0xfffc) >> 2;
0536: num = LittleEndian.getShort(dop, 52);
0537: _docProps._rncEdn = num & 0x3;
0538: _docProps._nEdn = (short) (num & 0xfffc) >> 2;
0539: num = LittleEndian.getShort(dop, 54);
0540: _docProps._epc = num & 0x3;
0541: }
0542:
0543: public void writeSection(int start, int end, SEP sep,
0544: BTreeSet text, BTreeSet paragraphTable,
0545: BTreeSet characterTable, StyleSheet stylesheet) {
0546:
0547: HeaderFooter titleHeader = findSectionHdrFtr(
0548: HeaderFooter.HEADER_FIRST, _sectionCounter);
0549: HeaderFooter titleFooter = findSectionHdrFtr(
0550: HeaderFooter.FOOTER_FIRST, _sectionCounter);
0551: HeaderFooter oddHeader = findSectionHdrFtr(
0552: HeaderFooter.HEADER_ODD, _sectionCounter);
0553: HeaderFooter evenHeader = findSectionHdrFtr(
0554: HeaderFooter.HEADER_EVEN, _sectionCounter);
0555: HeaderFooter oddFooter = findSectionHdrFtr(
0556: HeaderFooter.FOOTER_ODD, _sectionCounter);
0557: HeaderFooter evenFooter = findSectionHdrFtr(
0558: HeaderFooter.FOOTER_EVEN, _sectionCounter);
0559:
0560: String titlePage = null;
0561: String evenPage = null;
0562: String oddPage = null;
0563: String regPage = null;
0564:
0565: String sequenceName = null;
0566:
0567: /*if(sep._fTitlePage)
0568: {
0569: titlePage = createPageMaster(sep, "first", _sectionCounter, createRegion("before", "title-header"), createRegion("after", "title-footer"));
0570:
0571: if(!titleHeader.isEmpty())
0572: {
0573: addStaticContent("title-header" + _sectionCounter, titleHeader);
0574: }
0575: if(!titleFooter.isEmpty())
0576: {
0577: addStaticContent("title-footer" + _sectionCounter, titleFooter);
0578: }
0579: }*/
0580:
0581: if (_docProps._fFacingPages) {
0582: if (sep._fTitlePage) {
0583: String before = createRegion(true, titleHeader, sep,
0584: "title-header" + _sectionCounter);
0585: String after = createRegion(false, titleFooter, sep,
0586: "title-footer" + _sectionCounter);
0587: titlePage = createPageMaster(sep, "first",
0588: _sectionCounter, before, after);
0589: }
0590: String before = createRegion(true, evenHeader, sep,
0591: "even-header" + _sectionCounter);
0592: String after = createRegion(false, evenFooter, sep,
0593: "even-footer" + _sectionCounter);
0594: evenPage = createPageMaster(sep, "even", _sectionCounter,
0595: before, after);
0596: before = createRegion(true, oddHeader, sep, "odd-header"
0597: + _sectionCounter);
0598: after = createRegion(false, oddFooter, sep, "odd-footer"
0599: + _sectionCounter);
0600: oddPage = createPageMaster(sep, "odd", _sectionCounter,
0601: before, after);
0602: sequenceName = createEvenOddPageSequence(titlePage,
0603: evenPage, oddPage, _sectionCounter);
0604:
0605: openPage(sequenceName, "reference");
0606:
0607: if (sep._fTitlePage) {
0608:
0609: if (!titleHeader.isEmpty()) {
0610: addStaticContent("title-header" + _sectionCounter,
0611: titleHeader);
0612: }
0613: if (!titleFooter.isEmpty()) {
0614: addStaticContent("title-footer" + _sectionCounter,
0615: titleFooter);
0616: }
0617: }
0618:
0619: //handle the headers and footers for odd and even pages
0620: if (!oddHeader.isEmpty()) {
0621: addStaticContent("odd-header" + _sectionCounter,
0622: oddHeader);
0623: }
0624: if (!oddFooter.isEmpty()) {
0625: addStaticContent("odd-footer" + _sectionCounter,
0626: oddFooter);
0627: }
0628: if (!evenHeader.isEmpty()) {
0629: addStaticContent("even-header" + _sectionCounter,
0630: evenHeader);
0631: }
0632: if (!evenFooter.isEmpty()) {
0633: addStaticContent("even-footer" + _sectionCounter,
0634: evenFooter);
0635: }
0636: openFlow();
0637: addBlockContent(start, end, text, paragraphTable,
0638: characterTable);
0639: closeFlow();
0640: closePage();
0641: } else {
0642: /*if(sep._fTitlePage)
0643: {
0644: String before = createRegion(true, titleHeader, sep);
0645: String after = createRegion(false, titleFooter, sep);
0646: titlePage = createPageMaster(sep, "first", _sectionCounter, before, after);
0647: }*/
0648: String before = createRegion(true, oddHeader, sep, null);
0649: String after = createRegion(false, oddFooter, sep, null);
0650: regPage = createPageMaster(sep, "page", _sectionCounter,
0651: before, after);
0652:
0653: if (sep._fTitlePage) {
0654: before = createRegion(true, titleHeader, sep,
0655: "title-header" + _sectionCounter);
0656: after = createRegion(false, titleFooter, sep,
0657: "title-footer" + _sectionCounter);
0658: titlePage = createPageMaster(sep, "first",
0659: _sectionCounter, before, after);
0660: sequenceName = createPageSequence(titlePage, regPage,
0661: _sectionCounter);
0662: openPage(sequenceName, "reference");
0663:
0664: if (!titleHeader.isEmpty()) {
0665: addStaticContent("title-header" + _sectionCounter,
0666: titleHeader);
0667: }
0668: if (!titleFooter.isEmpty()) {
0669: addStaticContent("title-footer" + _sectionCounter,
0670: titleFooter);
0671: }
0672: } else {
0673: openPage(regPage, "name");
0674: }
0675: if (!oddHeader.isEmpty()) {
0676: addStaticContent("xsl-region-before", oddHeader);
0677: }
0678: if (!oddFooter.isEmpty()) {
0679: addStaticContent("xsl-region-after", oddFooter);
0680: }
0681: openFlow();
0682: addBlockContent(start, end, text, paragraphTable,
0683: characterTable);
0684: closeFlow();
0685: closePage();
0686: }
0687: _sectionCounter++;
0688: }
0689:
0690: private int calculateHeaderHeight(int start, int end, int pageWidth) {
0691: ArrayList paragraphs = findProperties(start, end,
0692: _paragraphTable.root);
0693: int size = paragraphs.size();
0694: ArrayList lineHeights = new ArrayList();
0695: //StyleContext context = StyleContext.getDefaultStyleContext();
0696:
0697: for (int x = 0; x < size; x++) {
0698: PapxNode node = (PapxNode) paragraphs.get(x);
0699: int parStart = Math.max(node.getStart(), start);
0700: int parEnd = Math.min(node.getEnd(), end);
0701:
0702: int lineWidth = 0;
0703: int maxHeight = 0;
0704:
0705: ArrayList textRuns = findProperties(parStart, parEnd,
0706: _characterTable.root);
0707: int charSize = textRuns.size();
0708:
0709: //StringBuffer lineBuffer = new StringBuffer();
0710: for (int y = 0; y < charSize; y++) {
0711: ChpxNode charNode = (ChpxNode) textRuns.get(y);
0712: int istd = Utils.convertBytesToShort(node.getPapx(), 0);
0713: StyleDescription sd = _styleSheet
0714: .getStyleDescription(istd);
0715: CHP chp = (CHP) StyleSheet.uncompressProperty(charNode
0716: .getChpx(), sd.getCHP(), _styleSheet);
0717:
0718: //get Font info
0719: //FontMetrics metrics = getFontMetrics(chp, context);
0720:
0721: int height = 10;//metrics.getHeight();
0722: maxHeight = Math.max(maxHeight, height);
0723:
0724: int charStart = Math.max(parStart, charNode.getStart());
0725: int charEnd = Math.min(parEnd, charNode.getEnd());
0726:
0727: ArrayList text = findProperties(charStart, charEnd,
0728: _text.root);
0729:
0730: int textSize = text.size();
0731: StringBuffer buf = new StringBuffer();
0732: for (int z = 0; z < textSize; z++) {
0733:
0734: TextPiece piece = (TextPiece) text.get(z);
0735: int textStart = Math.max(piece.getStart(),
0736: charStart);
0737: int textEnd = Math.min(piece.getEnd(), charEnd);
0738:
0739: if (piece.usesUnicode()) {
0740: addUnicodeText(textStart, textEnd, buf);
0741: } else {
0742: addText(textStart, textEnd, buf);
0743: }
0744: }
0745:
0746: String tempString = buf.toString();
0747: lineWidth += 10 * tempString.length();//metrics.stringWidth(tempString);
0748: if (lineWidth > pageWidth) {
0749: lineHeights.add(new Integer(maxHeight));
0750: maxHeight = 0;
0751: lineWidth = 0;
0752: }
0753: }
0754: lineHeights.add(new Integer(maxHeight));
0755: }
0756: int sum = 0;
0757: size = lineHeights.size();
0758: for (int x = 0; x < size; x++) {
0759: Integer height = (Integer) lineHeights.get(x);
0760: sum += height.intValue();
0761: }
0762:
0763: return sum;
0764: }
0765:
0766: /* private FontMetrics getFontMetrics(CHP chp, StyleContext context)
0767: {
0768: String fontName = _fonts.getFont(chp._ftcAscii);
0769: int style = 0;
0770: if(chp._bold)
0771: {
0772: style |= Font.BOLD;
0773: }
0774: if(chp._italic)
0775: {
0776: style |= Font.ITALIC;
0777: }
0778:
0779: Font font = new Font(fontName, style, chp._hps/2);
0780:
0781:
0782: return context.getFontMetrics(font);
0783: }*/
0784: private String createRegion(boolean before, HeaderFooter header,
0785: SEP sep, String name) {
0786: if (header.isEmpty()) {
0787: return "";
0788: }
0789: String region = "region-name=\"" + name + "\"";
0790: if (name == null) {
0791: region = "";
0792: }
0793: int height = calculateHeaderHeight(header.getStart(), header
0794: .getEnd(), sep._xaPage / 20);
0795: int marginTop = 0;
0796: int marginBottom = 0;
0797: int extent = 0;
0798: String where = null;
0799: String align = null;
0800:
0801: if (before) {
0802: where = "before";
0803: align = "before";
0804: marginTop = sep._dyaHdrTop / 20;
0805: extent = height + marginTop;
0806: sep._dyaTop = Math.max(extent * 20, sep._dyaTop);
0807: } else {
0808: where = "after";
0809: align = "after";
0810: marginBottom = sep._dyaHdrBottom / 20;
0811: extent = height + marginBottom;
0812: sep._dyaBottom = Math.max(extent * 20, sep._dyaBottom);
0813: }
0814:
0815: int marginLeft = sep._dxaLeft / 20;
0816: int marginRight = sep._dxaRight / 20;
0817:
0818: return "<fo:region-" + where + " display-align=\"" + align
0819: + "\" extent=\"" + extent + "pt\" " + region + "/>";
0820: // org.apache.fop.fo.expr.PropertyException:
0821: // Border and padding for region "xsl-region-before" must be '0'
0822: // (See 6.4.13 in XSL 1.0).
0823: // extent + "pt\" padding-left=\"" + marginLeft + "pt\" padding-right=\"" +
0824: // marginRight + "pt\" padding-top=\"" + marginTop + "pt\" padding-bottom=\"" +
0825: // marginBottom + "pt\" " + region + "/>";
0826:
0827: }
0828:
0829: private String createRegion(String where, String name) {
0830: return "<fo:region-" + where
0831: + " overflow=\"scroll\" region-name=\"" + name + "\"/>";
0832: }
0833:
0834: private String createEvenOddPageSequence(String titlePage,
0835: String evenPage, String oddPage, int counter) {
0836: String name = "my-sequence" + counter;
0837: _headerBuffer.append("<fo:page-sequence-master master-name=\""
0838: + name + "\"> ");
0839: _headerBuffer
0840: .append("<fo:repeatable-page-master-alternatives>");
0841: if (titlePage != null) {
0842: _headerBuffer
0843: .append("<fo:conditional-page-master-reference "
0844: + "page-position=\"first\" master-reference=\""
0845: + titlePage + "\"/>");
0846: }
0847: _headerBuffer
0848: .append("<fo:conditional-page-master-reference odd-or-even=\"odd\" ");
0849: _headerBuffer.append("master-reference=\"" + oddPage + "\"/> ");
0850: _headerBuffer
0851: .append("<fo:conditional-page-master-reference odd-or-even=\"even\" ");
0852: _headerBuffer
0853: .append("master-reference=\"" + evenPage + "\"/> ");
0854: _headerBuffer
0855: .append("</fo:repeatable-page-master-alternatives>");
0856: _headerBuffer.append("</fo:page-sequence-master>");
0857: return name;
0858: }
0859:
0860: private String createPageSequence(String titlePage, String regPage,
0861: int counter) {
0862: String name = null;
0863: if (titlePage != null) {
0864: name = "my-sequence" + counter;
0865: _headerBuffer
0866: .append("<fo:page-sequence-master master-name=\""
0867: + name + "\"> ");
0868: _headerBuffer
0869: .append("<fo:single-page-master-reference master-reference=\""
0870: + titlePage + "\"/>");
0871: _headerBuffer
0872: .append("<fo:repeatable-page-master-reference master-reference=\""
0873: + regPage + "\"/>");
0874: _headerBuffer.append("</fo:page-sequence-master>");
0875: }
0876: return name;
0877: }
0878:
0879: private void addBlockContent(int start, int end, BTreeSet text,
0880: BTreeSet paragraphTable, BTreeSet characterTable) {
0881:
0882: BTreeSet.BTreeNode root = paragraphTable.root;
0883: ArrayList pars = findProperties(start, end, root);
0884: //root = characterTable.root;
0885: int size = pars.size();
0886:
0887: for (int c = 0; c < size; c++) {
0888: PapxNode currentNode = (PapxNode) pars.get(c);
0889: createParagraph(start, end, currentNode, characterTable,
0890: text);
0891: }
0892: //closePage();
0893: }
0894:
0895: private String getTextAlignment(byte jc) {
0896: switch (jc) {
0897: case 0:
0898: return "start";
0899: case 1:
0900: return "center";
0901: case 2:
0902: return "end";
0903: case 3:
0904: return "justify";
0905: default:
0906: return "left";
0907: }
0908: }
0909:
0910: private void createParagraph(int start, int end,
0911: PapxNode currentNode, BTreeSet characterTable, BTreeSet text) {
0912: StringBuffer blockBuffer = _bodyBuffer;
0913: byte[] papx = currentNode.getPapx();
0914: int istd = Utils.convertBytesToShort(papx, 0);
0915: StyleDescription std = _styleSheet.getStyleDescription(istd);
0916: PAP pap = (PAP) StyleSheet.uncompressProperty(papx, std
0917: .getPAP(), _styleSheet);
0918:
0919: //handle table cells
0920: if (pap._fInTable > 0) {
0921: if (pap._fTtp == 0) {
0922: if (_cellBuffer == null) {
0923: _cellBuffer = new StringBuffer();
0924: }
0925: blockBuffer = _cellBuffer;
0926: } else {
0927: if (_table == null) {
0928: _table = new ArrayList();
0929: }
0930: TAP tap = (TAP) StyleSheet.uncompressProperty(papx,
0931: new TAP(), _styleSheet);
0932: TableRow nextRow = new TableRow(_cells, tap);
0933: _table.add(nextRow);
0934: _cells = null;
0935: return;
0936: }
0937: } else {
0938: //just prints out any table that is stored in _table
0939: printTable();
0940: }
0941:
0942: if (pap._ilfo > 0) {
0943: LVL lvl = _listTables.getLevel(pap._ilfo, pap._ilvl);
0944: addListParagraphContent(lvl, blockBuffer, pap, currentNode,
0945: start, end, std);
0946: } else {
0947: addParagraphContent(blockBuffer, pap, currentNode, start,
0948: end, std);
0949: }
0950:
0951: }
0952:
0953: private void addListParagraphContent(LVL lvl,
0954: StringBuffer blockBuffer, PAP pap, PapxNode currentNode,
0955: int start, int end, StyleDescription std) {
0956: pap = (PAP) StyleSheet.uncompressProperty(lvl._papx, pap,
0957: _styleSheet, false);
0958:
0959: addParagraphProperties(pap, blockBuffer);
0960:
0961: ArrayList charRuns = findProperties(Math.max(currentNode
0962: .getStart(), start), Math
0963: .min(currentNode.getEnd(), end), _characterTable.root);
0964: int len = charRuns.size();
0965:
0966: CHP numChp = (CHP) StyleSheet.uncompressProperty(
0967: ((ChpxNode) charRuns.get(len - 1)).getChpx(), std
0968: .getCHP(), _styleSheet);
0969:
0970: numChp = (CHP) StyleSheet.uncompressProperty(lvl._chpx, numChp,
0971: _styleSheet);
0972:
0973: //StyleContext context = StyleContext.getDefaultStyleContext();
0974: //FontMetrics metrics = getFontMetrics(numChp, context);
0975: int indent = -1 * pap._dxaLeft1;
0976: String bulletText = getBulletText(lvl, pap);
0977:
0978: indent = indent - (bulletText.length() * 10) * 20;//(metrics.stringWidth(bulletText) * 20);
0979:
0980: if (indent > 0) {
0981: numChp._paddingEnd = (short) indent;
0982: }
0983:
0984: addCharacterProperties(numChp, blockBuffer);
0985: int listNum = 0;
0986:
0987: //if(number != null)
0988: //{
0989: blockBuffer.append(bulletText);
0990: //listNum = 1;
0991: //}
0992:
0993: //for(;listNum < lvl._xst.length; listNum++)
0994: //{
0995: // addText(lvl._xst[listNum], blockBuffer);
0996: //}
0997:
0998: switch (lvl._ixchFollow) {
0999: case 0:
1000: addText('\u0009', blockBuffer);
1001: break;
1002: case 1:
1003: addText(' ', blockBuffer);
1004: break;
1005: }
1006:
1007: closeLine(blockBuffer);
1008: for (int x = 0; x < len; x++) {
1009: ChpxNode charNode = (ChpxNode) charRuns.get(x);
1010: byte[] chpx = charNode.getChpx();
1011: CHP chp = (CHP) StyleSheet.uncompressProperty(chpx, std
1012: .getCHP(), _styleSheet);
1013:
1014: addCharacterProperties(chp, blockBuffer);
1015:
1016: int charStart = Math.max(charNode.getStart(), currentNode
1017: .getStart());
1018: int charEnd = Math.min(charNode.getEnd(), currentNode
1019: .getEnd());
1020: ArrayList textRuns = findProperties(charStart, charEnd,
1021: _text.root);
1022: int textRunLen = textRuns.size();
1023: for (int y = 0; y < textRunLen; y++) {
1024: TextPiece piece = (TextPiece) textRuns.get(y);
1025: charStart = Math.max(charStart, piece.getStart());
1026: charEnd = Math.min(charEnd, piece.getEnd());
1027:
1028: if (piece.usesUnicode()) {
1029: addUnicodeText(charStart, charEnd, blockBuffer);
1030: } else {
1031: addText(charStart, charEnd, blockBuffer);
1032: }
1033: closeLine(blockBuffer);
1034: }
1035: }
1036: closeBlock(blockBuffer);
1037: }
1038:
1039: private void addParagraphContent(StringBuffer blockBuffer, PAP pap,
1040: PapxNode currentNode, int start, int end,
1041: StyleDescription std) {
1042: addParagraphProperties(pap, blockBuffer);
1043:
1044: ArrayList charRuns = findProperties(Math.max(currentNode
1045: .getStart(), start), Math
1046: .min(currentNode.getEnd(), end), _characterTable.root);
1047: int len = charRuns.size();
1048:
1049: for (int x = 0; x < len; x++) {
1050: ChpxNode charNode = (ChpxNode) charRuns.get(x);
1051: byte[] chpx = charNode.getChpx();
1052: CHP chp = (CHP) StyleSheet.uncompressProperty(chpx, std
1053: .getCHP(), _styleSheet);
1054:
1055: addCharacterProperties(chp, blockBuffer);
1056:
1057: int charStart = Math.max(charNode.getStart(), currentNode
1058: .getStart());
1059: int charEnd = Math.min(charNode.getEnd(), currentNode
1060: .getEnd());
1061: ArrayList textRuns = findProperties(charStart, charEnd,
1062: _text.root);
1063: int textRunLen = textRuns.size();
1064: for (int y = 0; y < textRunLen; y++) {
1065: TextPiece piece = (TextPiece) textRuns.get(y);
1066: charStart = Math.max(charStart, piece.getStart());
1067: charEnd = Math.min(charEnd, piece.getEnd());
1068:
1069: if (piece.usesUnicode()) {
1070: addUnicodeText(charStart, charEnd, blockBuffer);
1071: } else {
1072: addText(charStart, charEnd, blockBuffer);
1073: }
1074: closeLine(blockBuffer);
1075: }
1076: }
1077: closeBlock(blockBuffer);
1078: }
1079:
1080: private void addText(int start, int end, StringBuffer buf) {
1081: for (int x = start; x < end; x++) {
1082: char ch = '?';
1083:
1084: ch = (char) _header[x];
1085:
1086: addText(ch, buf);
1087: }
1088: }
1089:
1090: private void addText(char ch, StringBuffer buf) {
1091: int num = 0xffff & ch;
1092: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
1093: || (ch >= '0' && ch <= '9') || ch == '_' || ch == ' '
1094: || ch == '-' || ch == '.' || ch == '$') {
1095: buf.append(ch);
1096: } else if (num == 0x07 && _cellBuffer != null) {
1097:
1098: if (_cells == null) {
1099: _cells = new ArrayList();
1100: }
1101: closeLine(_cellBuffer);
1102: closeBlock(_cellBuffer);
1103: _cells.add(_cellBuffer.toString());
1104: _cellBuffer = null;
1105:
1106: }
1107:
1108: else {
1109: /** @todo handle special characters */
1110: if (num < 0x20)
1111: num = 0x20;
1112: buf.append("&#");
1113: buf.append(num);
1114: buf.append(';');
1115: }
1116: }
1117:
1118: private void addUnicodeText(int start, int end, StringBuffer buf) {
1119: for (int x = start; x < end; x += 2) {
1120: char ch = Utils.getUnicodeCharacter(_header, x);
1121: //if(ch < 0x0020)
1122: //{
1123: // _bodyBuffer.append('?');
1124: //}
1125: //else
1126: //{
1127: addText(ch, buf);
1128: //}
1129: }
1130: }
1131:
1132: private void addParagraphProperties(PAP pap, StringBuffer buf) {
1133: buf.append("<fo:block ");
1134: buf.append("text-align=\"" + getTextAlignment(pap._jc)
1135: + "\"\r\n");
1136: buf.append("linefeed-treatment=\"preserve\" ");
1137: buf.append("white-space-collapse=\"false\" ");
1138:
1139: if (pap._fKeep > 0) {
1140: buf.append("keep-together.within-page=\"always\"\r\n");
1141: }
1142: if (pap._fKeepFollow > 0) {
1143: buf.append("keep-with-next.within-page=\"always\"\r\n");
1144: }
1145: if (pap._fPageBreakBefore > 0) {
1146: buf.append("break-before=\"page\"\r\n");
1147: }
1148: if (pap._fNoAutoHyph == 0) {
1149: buf.append("hyphenate=\"true\"\r\n");
1150: } else {
1151: buf.append("hyphenate=\"false\"\r\n");
1152: }
1153: if (pap._dxaLeft > 0) {
1154: buf.append("start-indent=\"" + ((float) pap._dxaLeft)
1155: / 1440.0f + "in\"\r\n");
1156: }
1157: if (pap._dxaRight > 0) {
1158: buf.append("end-indent=\"" + ((float) pap._dxaRight)
1159: / 1440.0f + "in\"\r\n");
1160: }
1161: if (pap._dxaLeft1 != 0) {
1162: buf.append("text-indent=\"" + ((float) pap._dxaLeft1)
1163: / 1440.0f + "in\"\r\n");
1164: }
1165: if (pap._lspd[1] == 0) {
1166: //buf.append("line-height=\"" + ((float)pap._lspd[0])/1440.0f + "in\"\r\n");
1167: }
1168: addBorder(buf, pap._brcTop, "top");
1169: addBorder(buf, pap._brcBottom, "bottom");
1170: addBorder(buf, pap._brcLeft, "left");
1171: addBorder(buf, pap._brcRight, "right");
1172:
1173: buf.append(">");
1174:
1175: }
1176:
1177: private void addCharacterProperties(CHP chp, StringBuffer buf) {
1178: buf.append("<fo:inline ");
1179: buf.append("font-family=\"" + _fonts.getFont(chp._ftcAscii)
1180: + "\" ");
1181: buf.append("font-size=\"" + (chp._hps / 2) + "pt\" ");
1182: buf.append("color=\"" + getColor(chp._ico) + "\" ");
1183: //not supported by fop
1184: //buf.append("letter-spacing=\"" + ((double)chp._dxaSpace)/1440.0f + "in\" ");
1185:
1186: addBorder(buf, chp._brc, "top");
1187: addBorder(buf, chp._brc, "bottom");
1188: addBorder(buf, chp._brc, "left");
1189: addBorder(buf, chp._brc, "right");
1190:
1191: if (chp._italic) {
1192: buf.append("font-style=\"italic\" ");
1193: }
1194: if (chp._bold) {
1195: buf.append("font-weight=\"bold\" ");
1196: }
1197: if (chp._fSmallCaps) {
1198: buf.append("font-variant=\"small-caps\" ");
1199: }
1200: if (chp._fCaps) {
1201: buf.append("text-transform=\"uppercase\" ");
1202: }
1203: if (chp._fStrike || chp._fDStrike) {
1204: buf.append("text-decoration=\"line-through\" ");
1205: }
1206: if (chp._fShadow) {
1207: int size = chp._hps / 24;
1208: buf.append("text-shadow=\"" + size + "pt\"");
1209: }
1210: if (chp._fLowerCase) {
1211: buf.append("text-transform=\"lowercase\" ");
1212: }
1213: if (chp._kul > 0) {
1214: buf.append("text-decoration=\"underline\" ");
1215: }
1216: if (chp._highlighted) {
1217: buf.append("background-color=\""
1218: + getColor(chp._icoHighlight) + "\" ");
1219: }
1220: if (chp._paddingStart != 0) {
1221: buf.append("padding-start=\"" + (float) chp._paddingStart
1222: / 1440.0f + "in\" ");
1223: }
1224: if (chp._paddingEnd != 0) {
1225: buf.append("padding-end=\"" + (float) chp._paddingEnd
1226: / 1440.0f + "in\" ");
1227: }
1228: buf.append(">");
1229: }
1230:
1231: private void addStaticContent(String flowName, HeaderFooter content) {
1232: _bodyBuffer.append("<fo:static-content flow-name=\"" + flowName
1233: + "\">");
1234: //_bodyBuffer.append("<fo:float float=\"before\">");
1235: addBlockContent(content.getStart(), content.getEnd(), _text,
1236: _paragraphTable, _characterTable);
1237: //_bodyBuffer.append("</fo:float>");
1238: _bodyBuffer.append("</fo:static-content>");
1239:
1240: }
1241:
1242: private String getBulletText(LVL lvl, PAP pap) {
1243: StringBuffer bulletBuffer = new StringBuffer();
1244: for (int x = 0; x < lvl._xst.length; x++) {
1245: if (lvl._xst[x] < 9) {
1246: LVL numLevel = _listTables.getLevel(pap._ilfo,
1247: lvl._xst[x]);
1248: int num = numLevel._iStartAt;
1249: if (lvl == numLevel) {
1250: numLevel._iStartAt++;
1251: } else if (num > 1) {
1252: num--;
1253: }
1254: bulletBuffer.append(NumberFormatter.getNumber(num,
1255: lvl._nfc));
1256:
1257: } else {
1258: bulletBuffer.append(lvl._xst[x]);
1259: }
1260:
1261: }
1262: return bulletBuffer.toString();
1263: }
1264:
1265: /**
1266: * finds all chpx's that are between start and end
1267: */
1268: private ArrayList findProperties(int start, int end,
1269: BTreeSet.BTreeNode root) {
1270: ArrayList results = new ArrayList();
1271: BTreeSet.Entry[] entries = root.entries;
1272:
1273: for (int x = 0; x < entries.length; x++) {
1274: if (entries[x] != null) {
1275: BTreeSet.BTreeNode child = entries[x].child;
1276: PropertyNode xNode = (PropertyNode) entries[x].element;
1277: if (xNode != null) {
1278: int xStart = xNode.getStart();
1279: int xEnd = xNode.getEnd();
1280: if (xStart < end) {
1281: if (xStart >= start) {
1282: if (child != null) {
1283: ArrayList beforeItems = findProperties(
1284: start, end, child);
1285: results.addAll(beforeItems);
1286: }
1287: results.add(xNode);
1288: } else if (start < xEnd) {
1289: results.add(xNode);
1290: //break;
1291: }
1292: } else {
1293: if (child != null) {
1294: ArrayList beforeItems = findProperties(
1295: start, end, child);
1296: results.addAll(beforeItems);
1297: }
1298: break;
1299: }
1300: } else if (child != null) {
1301: ArrayList afterItems = findProperties(start, end,
1302: child);
1303: results.addAll(afterItems);
1304: }
1305: } else {
1306: break;
1307: }
1308: }
1309: return results;
1310: }
1311:
1312: private void openPage(String page, String type) {
1313: _bodyBuffer.append("<fo:page-sequence master-reference=\""
1314: + page + "\">\r\n");
1315: }
1316:
1317: private void openFlow() {
1318: _bodyBuffer
1319: .append("<fo:flow flow-name=\"xsl-region-body\">\r\n");
1320: }
1321:
1322: private void closeFlow() {
1323: _bodyBuffer.append("</fo:flow>\r\n");
1324: }
1325:
1326: private void closePage() {
1327: _bodyBuffer.append("</fo:page-sequence>\r\n");
1328: }
1329:
1330: private void closeLine(StringBuffer buf) {
1331: buf.append("</fo:inline>");
1332: }
1333:
1334: private void closeBlock(StringBuffer buf) {
1335: buf.append("</fo:block>\r\n");
1336: }
1337:
1338: private ArrayList findPAPProperties(int start, int end,
1339: BTreeSet.BTreeNode root) {
1340: ArrayList results = new ArrayList();
1341: BTreeSet.Entry[] entries = root.entries;
1342:
1343: for (int x = 0; x < entries.length; x++) {
1344: if (entries[x] != null) {
1345: BTreeSet.BTreeNode child = entries[x].child;
1346: PapxNode papxNode = (PapxNode) entries[x].element;
1347: if (papxNode != null) {
1348: int papxStart = papxNode.getStart();
1349: if (papxStart < end) {
1350: if (papxStart >= start) {
1351: if (child != null) {
1352: ArrayList beforeItems = findPAPProperties(
1353: start, end, child);
1354: results.addAll(beforeItems);
1355: }
1356: results.add(papxNode);
1357: }
1358: } else {
1359: if (child != null) {
1360: ArrayList beforeItems = findPAPProperties(
1361: start, end, child);
1362: results.addAll(beforeItems);
1363: }
1364: break;
1365: }
1366: } else if (child != null) {
1367: ArrayList afterItems = findPAPProperties(start,
1368: end, child);
1369: results.addAll(afterItems);
1370: }
1371: } else {
1372: break;
1373: }
1374: }
1375: return results;
1376: }
1377:
1378: private String createPageMaster(SEP sep, String type, int section,
1379: String regionBefore, String regionAfter) {
1380: float height = ((float) sep._yaPage) / 1440.0f;
1381: float width = ((float) sep._xaPage) / 1440.0f;
1382: float leftMargin = ((float) sep._dxaLeft) / 1440.0f;
1383: float rightMargin = ((float) sep._dxaRight) / 1440.0f;
1384: float topMargin = ((float) sep._dyaTop) / 1440.0f;
1385: float bottomMargin = ((float) sep._dyaBottom) / 1440.0f;
1386:
1387: //add these to the header
1388: String this Page = type + "-page" + section;
1389:
1390: _headerBuffer.append("<fo:simple-page-master master-name=\""
1391: + this Page + "\"\r\n");
1392: _headerBuffer.append("page-height=\"" + height + "in\"\r\n");
1393: _headerBuffer.append("page-width=\"" + width + "in\"\r\n");
1394: _headerBuffer.append(">\r\n");
1395:
1396: _headerBuffer.append("<fo:region-body ");
1397: //top right bottom left
1398:
1399: _headerBuffer.append("margin=\"" + topMargin + "in "
1400: + rightMargin + "in " + bottomMargin + "in "
1401: + leftMargin + "in\"\r\n");
1402:
1403: //String style = null;
1404: //String color = null;
1405: addBorder(_headerBuffer, sep._brcTop, "top");
1406: addBorder(_headerBuffer, sep._brcBottom, "bottom");
1407: addBorder(_headerBuffer, sep._brcLeft, "left");
1408: addBorder(_headerBuffer, sep._brcRight, "right");
1409:
1410: if (sep._ccolM1 > 0) {
1411: _headerBuffer.append("column-count=\"" + (sep._ccolM1 + 1)
1412: + "\" ");
1413: if (sep._fEvenlySpaced) {
1414: _headerBuffer.append("column-gap=\""
1415: + ((float) (sep._dxaColumns)) / 1440.0f
1416: + "in\"");
1417: } else {
1418: _headerBuffer.append("column-gap=\"0.25in\"");
1419: }
1420: }
1421: _headerBuffer.append("/>\r\n");
1422:
1423: if (regionBefore != null) {
1424: _headerBuffer.append(regionBefore);
1425: }
1426: if (regionAfter != null) {
1427: _headerBuffer.append(regionAfter);
1428: }
1429:
1430: _headerBuffer.append("</fo:simple-page-master>\r\n");
1431: return this Page;
1432: }
1433:
1434: private void addBorder(StringBuffer buf, short[] brc, String where) {
1435: if ((brc[0] & 0xff00) != 0 && brc[0] != -1) {
1436: int type = (brc[0] & 0xff00) >> 8;
1437: float width = ((float) (brc[0] & 0x00ff)) / 8.0f;
1438: String style = getBorderStyle(brc[0]);
1439: String color = getColor(brc[1] & 0x00ff);
1440: String thickness = getBorderThickness(brc[0]);
1441: buf.append("border-" + where + "-style=\"" + style
1442: + "\"\r\n");
1443: buf.append("border-" + where + "-color=\"" + color
1444: + "\"\r\n");
1445: buf.append("border-" + where + "-width=\"" + width
1446: + "pt\"\r\n");
1447: }
1448: }
1449:
1450: public void closeDoc() {
1451: _headerBuffer.append("</fo:layout-master-set>");
1452: _bodyBuffer.append("</fo:root>");
1453: //_headerBuffer.append();
1454:
1455: //test code
1456: try {
1457: OutputStreamWriter test = new OutputStreamWriter(
1458: new FileOutputStream(_outName), "8859_1");
1459: test.write(_headerBuffer.toString());
1460: test.write(_bodyBuffer.toString());
1461: test.flush();
1462: test.close();
1463: } catch (Throwable t) {
1464: t.printStackTrace();
1465: }
1466: }
1467:
1468: private String getBorderThickness(int style) {
1469: switch (style) {
1470: case 1:
1471: return "medium";
1472: case 2:
1473: return "thick";
1474: case 3:
1475: return "medium";
1476: case 5:
1477: return "thin";
1478: default:
1479: return "medium";
1480: }
1481: }
1482:
1483: private String getColor(int ico) {
1484: switch (ico) {
1485: case 1:
1486: return "black";
1487: case 2:
1488: return "blue";
1489: case 3:
1490: return "cyan";
1491: case 4:
1492: return "green";
1493: case 5:
1494: return "magenta";
1495: case 6:
1496: return "red";
1497: case 7:
1498: return "yellow";
1499: case 8:
1500: return "white";
1501: case 9:
1502: return "darkblue";
1503: case 10:
1504: return "darkcyan";
1505: case 11:
1506: return "darkgreen";
1507: case 12:
1508: return "darkmagenta";
1509: case 13:
1510: return "darkred";
1511: case 14:
1512: return "darkyellow";
1513: case 15:
1514: return "darkgray";
1515: case 16:
1516: return "lightgray";
1517: default:
1518: return "black";
1519: }
1520: }
1521:
1522: private String getBorderStyle(int type) {
1523:
1524: switch (type) {
1525: case 1:
1526: case 2:
1527: return "solid";
1528: case 3:
1529: return "double";
1530: case 5:
1531: return "solid";
1532: case 6:
1533: return "dotted";
1534: case 7:
1535: case 8:
1536: return "dashed";
1537: case 9:
1538: return "dotted";
1539: case 10:
1540: case 11:
1541: case 12:
1542: case 13:
1543: case 14:
1544: case 15:
1545: case 16:
1546: case 17:
1547: case 18:
1548: case 19:
1549: return "double";
1550: case 20:
1551: return "solid";
1552: case 21:
1553: return "double";
1554: case 22:
1555: return "dashed";
1556: case 23:
1557: return "dashed";
1558: case 24:
1559: return "ridge";
1560: case 25:
1561: return "grooved";
1562: default:
1563: return "solid";
1564: }
1565: }
1566:
1567: /**
1568: * creates the List data
1569: *
1570: * @param tableStream Main table stream buffer.
1571: */
1572: private void createListTables(byte[] tableStream) {
1573:
1574: int lfoOffset = LittleEndian.getInt(_header, 0x2ea);
1575: int lfoSize = LittleEndian.getInt(_header, 0x2ee);
1576: byte[] plflfo = new byte[lfoSize];
1577:
1578: System.arraycopy(tableStream, lfoOffset, plflfo, 0, lfoSize);
1579:
1580: int lstOffset = LittleEndian.getInt(_header, 0x2e2);
1581: int lstSize = LittleEndian.getInt(_header, 0x2e2);
1582: if (lstOffset > 0 && lstSize > 0) {
1583: lstSize = lfoOffset - lstOffset;
1584: byte[] plcflst = new byte[lstSize];
1585: System.arraycopy(tableStream, lstOffset, plcflst, 0,
1586: lstSize);
1587: _listTables = new ListTables(plcflst, plflfo);
1588: }
1589:
1590: }
1591:
1592: /**
1593: * Creates the documents StyleSheet
1594: *
1595: * @param tableStream Main table stream buffer.
1596: *
1597: */
1598: private void createStyleSheet(byte[] tableStream) {
1599: int stshIndex = LittleEndian.getInt(_header, 0xa2);
1600: int stshSize = LittleEndian.getInt(_header, 0xa6);
1601: byte[] stsh = new byte[stshSize];
1602: System.arraycopy(tableStream, stshIndex, stsh, 0, stshSize);
1603:
1604: _styleSheet = new StyleSheet(stsh);
1605:
1606: }
1607:
1608: /**
1609: * creates the Font table
1610: *
1611: * @param tableStream Main table stream buffer.
1612: */
1613: private void createFontTable(byte[] tableStream) {
1614: int fontTableIndex = LittleEndian.getInt(_header, 0x112);
1615: int fontTableSize = LittleEndian.getInt(_header, 0x116);
1616: byte[] fontTable = new byte[fontTableSize];
1617: System.arraycopy(tableStream, fontTableIndex, fontTable, 0,
1618: fontTableSize);
1619: _fonts = new FontTable(fontTable);
1620: }
1621:
1622: private void overrideCellBorder(int row, int col, int height,
1623: int width, TC tc, TAP tap) {
1624:
1625: if (row == 0) {
1626: if (tc._brcTop[0] == 0 || tc._brcTop[0] == -1) {
1627: tc._brcTop = tap._brcTop;
1628: }
1629: if (tc._brcBottom[0] == 0 || tc._brcBottom[0] == -1) {
1630: tc._brcBottom = tap._brcHorizontal;
1631: }
1632: } else if (row == (height - 1)) {
1633: if (tc._brcTop[0] == 0 || tc._brcTop[0] == -1) {
1634: tc._brcTop = tap._brcHorizontal;
1635: }
1636: if (tc._brcBottom[0] == 0 || tc._brcBottom[0] == -1) {
1637: tc._brcBottom = tap._brcBottom;
1638: }
1639: } else {
1640: if (tc._brcTop[0] == 0 || tc._brcTop[0] == -1) {
1641: tc._brcTop = tap._brcHorizontal;
1642: }
1643: if (tc._brcBottom[0] == 0 || tc._brcBottom[0] == -1) {
1644: tc._brcBottom = tap._brcHorizontal;
1645: }
1646: }
1647: if (col == 0) {
1648: if (tc._brcLeft[0] == 0 || tc._brcLeft[0] == -1) {
1649: tc._brcLeft = tap._brcLeft;
1650: }
1651: if (tc._brcRight[0] == 0 || tc._brcRight[0] == -1) {
1652: tc._brcRight = tap._brcVertical;
1653: }
1654: } else if (col == (width - 1)) {
1655: if (tc._brcLeft[0] == 0 || tc._brcLeft[0] == -1) {
1656: tc._brcLeft = tap._brcVertical;
1657: }
1658: if (tc._brcRight[0] == 0 || tc._brcRight[0] == -1) {
1659: tc._brcRight = tap._brcRight;
1660: }
1661: } else {
1662: if (tc._brcLeft[0] == 0 || tc._brcLeft[0] == -1) {
1663: tc._brcLeft = tap._brcVertical;
1664: }
1665: if (tc._brcRight[0] == 0 || tc._brcRight[0] == -1) {
1666: tc._brcRight = tap._brcVertical;
1667: }
1668: }
1669: }
1670:
1671: private void printTable() {
1672: if (_table != null) {
1673: int size = _table.size();
1674:
1675: //local buffers for the table
1676: StringBuffer tableHeaderBuffer = new StringBuffer();
1677: StringBuffer tableBodyBuffer = new StringBuffer();
1678:
1679: for (int x = 0; x < size; x++) {
1680: StringBuffer rowBuffer = tableBodyBuffer;
1681: TableRow row = (TableRow) _table.get(x);
1682: TAP tap = row.getTAP();
1683: ArrayList cells = row.getCells();
1684:
1685: if (tap._fTableHeader) {
1686: rowBuffer = tableHeaderBuffer;
1687: }
1688: rowBuffer.append("<fo:table-row ");
1689: if (tap._dyaRowHeight > 0) {
1690: rowBuffer.append("height=\""
1691: + ((float) tap._dyaRowHeight) / 1440.0f
1692: + "in\" ");
1693: }
1694: if (tap._fCantSplit) {
1695: rowBuffer.append("keep-together=\"always\" ");
1696: }
1697: rowBuffer.append(">");
1698: //add cells
1699: for (int y = 0; y < tap._itcMac; y++) {
1700: TC tc = tap._rgtc[y];
1701: overrideCellBorder(x, y, size, tap._itcMac, tc, tap);
1702: rowBuffer.append("<fo:table-cell ");
1703: rowBuffer
1704: .append("width=\""
1705: + ((float) (tap._rgdxaCenter[y + 1] - tap._rgdxaCenter[y]))
1706: / 1440.0f + "in\" ");
1707: rowBuffer.append("padding-start=\""
1708: + ((float) tap._dxaGapHalf) / 1440.0f
1709: + "in\" ");
1710: rowBuffer.append("padding-end=\""
1711: + ((float) tap._dxaGapHalf) / 1440.0f
1712: + "in\" ");
1713: addBorder(rowBuffer, tc._brcTop, "top");
1714: addBorder(rowBuffer, tc._brcLeft, "left");
1715: addBorder(rowBuffer, tc._brcBottom, "bottom");
1716: addBorder(rowBuffer, tc._brcRight, "right");
1717: rowBuffer.append(">");
1718: rowBuffer.append((String) cells.get(y));
1719: rowBuffer.append("</fo:table-cell>");
1720: }
1721: rowBuffer.append("</fo:table-row>");
1722: }
1723: StringBuffer tableBuffer = new StringBuffer();
1724: tableBuffer.append("<fo:table>");
1725: if (tableHeaderBuffer.length() > 0) {
1726: tableBuffer.append("<fo:table-header>");
1727: tableBuffer.append(tableHeaderBuffer.toString());
1728: tableBuffer.append("</fo:table-header>");
1729: }
1730: tableBuffer.append("<fo:table-body>");
1731: tableBuffer.append(tableBodyBuffer.toString());
1732: tableBuffer.append("</fo:table-body>");
1733: tableBuffer.append("</fo:table>");
1734: _bodyBuffer.append(tableBuffer.toString());
1735: _table = null;
1736: }
1737: }
1738:
1739: private void initPclfHdd(byte[] tableStream) {
1740: int size = Utils.convertBytesToInt(_header, 0xf6);
1741: int pos = Utils.convertBytesToInt(_header, 0xf2);
1742:
1743: _plcfHdd = new byte[size];
1744:
1745: System.arraycopy(tableStream, pos, _plcfHdd, 0, size);
1746: }
1747:
1748: }
|