View | Details | Raw Unified | Return to bug 51351
Collapse All | Expand All

(-)src/org/apache/poi/hwpf/extractor/NumberFormatter.java (+43 lines)
Line 0 Link Here
1
package org.apache.poi.hwpf.extractor;
2
3
/**
4
 * Comment me
5
 *
6
 * @author Ryan Ackley
7
 */
8
public final class NumberFormatter {
9
10
    private static String[] C_LETTERS = new String[] { "a", "b", "c", "d", "e", "f", "g", "h", "i",
11
            "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "x", "y", "z" };
12
13
    private static String[] C_ROMAN = new String[] { "i", "ii", "iii", "iv", "v", "vi", "vii",
14
            "viii", "ix", "x", "xi", "xii", "xiii", "xiv", "xv", "xvi", "xvii", "xviii", "xix",
15
            "xx", "xxi", "xxii", "xxiii", "xxiv", "xxv", "xxvi", "xxvii", "xxviii", "xxix", "xxx",
16
            "xxxi", "xxxii", "xxxiii", "xxxiv", "xxxv", "xxxvi", "xxxvii", "xxxvii", "xxxviii",
17
            "xxxix", "xl", "xli", "xlii", "xliii", "xliv", "xlv", "xlvi", "xlvii", "xlviii",
18
            "xlix", "l" };
19
20
    private final static int T_ARABIC = 0;
21
    private final static int T_LOWER_LETTER = 4;
22
    private final static int T_LOWER_ROMAN = 2;
23
    private final static int T_ORDINAL = 5;
24
    private final static int T_UPPER_LETTER = 3;
25
    private final static int T_UPPER_ROMAN = 1;
26
27
    public static String getNumber(int num, int style) {
28
        switch (style) {
29
        case T_UPPER_ROMAN:
30
            return C_ROMAN[num - 1].toUpperCase();
31
        case T_LOWER_ROMAN:
32
            return C_ROMAN[num - 1];
33
        case T_UPPER_LETTER:
34
            return C_LETTERS[num - 1].toUpperCase();
35
        case T_LOWER_LETTER:
36
            return C_LETTERS[num - 1];
37
        case T_ARABIC:
38
        case T_ORDINAL:
39
        default:
40
            return String.valueOf(num);
41
        }
42
    }
43
}
(-)src/org/apache/poi/hwpf/extractor/WordToFoUtils.java (+412 lines)
Line 0 Link Here
1
package org.apache.poi.hwpf.extractor;
2
3
import java.lang.reflect.Constructor;
4
import java.lang.reflect.Field;
5
6
import org.apache.poi.hwpf.model.ListLevel;
7
import org.apache.poi.hwpf.model.ListTables;
8
import org.apache.poi.hwpf.usermodel.BorderCode;
9
import org.apache.poi.hwpf.usermodel.CharacterProperties;
10
import org.apache.poi.hwpf.usermodel.CharacterRun;
11
import org.apache.poi.hwpf.usermodel.Paragraph;
12
import org.apache.poi.hwpf.usermodel.Range;
13
import org.apache.poi.hwpf.usermodel.Section;
14
import org.apache.poi.hwpf.usermodel.SectionProperties;
15
import org.apache.poi.hwpf.usermodel.TableCell;
16
import org.apache.poi.hwpf.usermodel.TableIterator;
17
import org.apache.poi.hwpf.usermodel.TableRow;
18
import org.w3c.dom.Element;
19
20
public class WordToFoUtils {
21
    static final String EMPTY = "";
22
23
    public static final float TWIPS_PER_INCH = 1440.0f;
24
25
    public static final int TWIPS_PER_PT = 20;
26
27
    static boolean equals(String str1, String str2) {
28
        return str1 == null ? str2 == null : str1.equals(str2);
29
    }
30
31
    public static String getBorderType(BorderCode borderCode) {
32
        if (borderCode == null)
33
            throw new IllegalArgumentException("borderCode is null");
34
35
        switch (borderCode.getBorderType()) {
36
        case 1:
37
        case 2:
38
            return "solid";
39
        case 3:
40
            return "double";
41
        case 5:
42
            return "solid";
43
        case 6:
44
            return "dotted";
45
        case 7:
46
        case 8:
47
            return "dashed";
48
        case 9:
49
            return "dotted";
50
        case 10:
51
        case 11:
52
        case 12:
53
        case 13:
54
        case 14:
55
        case 15:
56
        case 16:
57
        case 17:
58
        case 18:
59
        case 19:
60
            return "double";
61
        case 20:
62
            return "solid";
63
        case 21:
64
            return "double";
65
        case 22:
66
            return "dashed";
67
        case 23:
68
            return "dashed";
69
        case 24:
70
            return "ridge";
71
        case 25:
72
            return "grooved";
73
        default:
74
            return "solid";
75
        }
76
    }
77
78
    public static String getBorderWidth(BorderCode borderCode) {
79
        int lineWidth = borderCode.getLineWidth();
80
        int pt = lineWidth / 8;
81
        int pte = lineWidth - pt * 8;
82
83
        StringBuilder stringBuilder = new StringBuilder();
84
        stringBuilder.append(pt);
85
        stringBuilder.append(".");
86
        stringBuilder.append(1000 / 8 * pte);
87
        stringBuilder.append("pt");
88
        return stringBuilder.toString();
89
    }
90
91
    public static String getBulletText(ListTables listTables, Paragraph paragraph, int listId) {
92
        final ListLevel listLevel = listTables.getLevel(listId, paragraph.getIlvl());
93
94
        if (listLevel.getNumberText() == null)
95
            return EMPTY;
96
97
        StringBuffer bulletBuffer = new StringBuffer();
98
        char[] xst = listLevel.getNumberText().toCharArray();
99
        for (char element : xst) {
100
            if (element < 9) {
101
                ListLevel numLevel = listTables.getLevel(listId, element);
102
103
                int num = numLevel.getStartAt();
104
                bulletBuffer.append(NumberFormatter.getNumber(num, listLevel.getNumberFormat()));
105
106
                if (numLevel == listLevel) {
107
                    numLevel.setStartAt(numLevel.getStartAt() + 1);
108
                }
109
110
            } else {
111
                bulletBuffer.append(element);
112
            }
113
        }
114
115
        byte follow = getIxchFollow(listLevel);
116
        switch (follow) {
117
        case 0:
118
            bulletBuffer.append("\t");
119
            break;
120
        case 1:
121
            bulletBuffer.append(" ");
122
            break;
123
        default:
124
            break;
125
        }
126
127
        return bulletBuffer.toString();
128
    }
129
130
    public static String getColor(int ico) {
131
        switch (ico) {
132
        case 1:
133
            return "black";
134
        case 2:
135
            return "blue";
136
        case 3:
137
            return "cyan";
138
        case 4:
139
            return "green";
140
        case 5:
141
            return "magenta";
142
        case 6:
143
            return "red";
144
        case 7:
145
            return "yellow";
146
        case 8:
147
            return "white";
148
        case 9:
149
            return "darkblue";
150
        case 10:
151
            return "darkcyan";
152
        case 11:
153
            return "darkgreen";
154
        case 12:
155
            return "darkmagenta";
156
        case 13:
157
            return "darkred";
158
        case 14:
159
            return "darkyellow";
160
        case 15:
161
            return "darkgray";
162
        case 16:
163
            return "lightgray";
164
        default:
165
            return "black";
166
        }
167
    }
168
169
    public static byte getIxchFollow(ListLevel listLevel) {
170
        try {
171
            Field field = ListLevel.class.getDeclaredField("_ixchFollow");
172
            field.setAccessible(true);
173
            return ((Byte) field.get(listLevel)).byteValue();
174
        } catch (Exception exc) {
175
            throw new Error(exc);
176
        }
177
    }
178
179
    public static String getListItemNumberLabel(int number, int format) {
180
181
        if (format != 0)
182
            System.err.println("NYI: toListItemNumberLabel(): " + format);
183
184
        return String.valueOf(number);
185
    }
186
187
    public static SectionProperties getSectionProperties(Section section) {
188
        try {
189
            Field field = Section.class.getDeclaredField("_props");
190
            field.setAccessible(true);
191
            return (SectionProperties) field.get(section);
192
        } catch (Exception exc) {
193
            throw new Error(exc);
194
        }
195
    }
196
197
    static boolean isEmpty(String str) {
198
        return str == null || str.length() == 0;
199
    }
200
201
    static boolean isNotEmpty(String str) {
202
        return !isEmpty(str);
203
    }
204
205
    public static TableIterator newTableIterator(Range range, int level) {
206
        try {
207
            Constructor<TableIterator> constructor = TableIterator.class.getDeclaredConstructor(
208
                    Range.class, int.class);
209
            constructor.setAccessible(true);
210
            return constructor.newInstance(range, Integer.valueOf(level));
211
        } catch (Exception exc) {
212
            throw new Error(exc);
213
        }
214
    }
215
216
    public static void setBold(final Element element, final boolean bold) {
217
        element.setAttribute("font-weight", bold ? "bold" : "normal");
218
    }
219
220
    public static void setBorder(Element element, BorderCode borderCode, String where) {
221
        if (element == null)
222
            throw new IllegalArgumentException("element is null");
223
224
        if (borderCode == null)
225
            return;
226
227
        if (isEmpty(where)) {
228
            element.setAttribute("border-style", getBorderType(borderCode));
229
            element.setAttribute("border-color", getColor(borderCode.getColor()));
230
            element.setAttribute("border-width", getBorderWidth(borderCode));
231
        } else {
232
            element.setAttribute("border-" + where + "-style", getBorderType(borderCode));
233
            element.setAttribute("border-" + where + "-color", getColor(borderCode.getColor()));
234
            element.setAttribute("border-" + where + "-width", getBorderWidth(borderCode));
235
        }
236
    }
237
238
    public static void
239
            setCharactersProperties(final CharacterRun characterRun, final Element inline)
240
    {
241
        final CharacterProperties clonedProperties = characterRun.cloneProperties();
242
        StringBuilder textDecorations = new StringBuilder();
243
244
        setBorder(inline, clonedProperties.getBrc(), EMPTY);
245
246
        if (characterRun.isCapitalized()) {
247
            inline.setAttribute("font-variant", "uppercase");
248
        }
249
        if (characterRun.isHighlighted()) {
250
            inline.setAttribute("background-color", getColor(clonedProperties.getIcoHighlight()));
251
        }
252
        if (characterRun.isStrikeThrough()) {
253
            if (textDecorations.length() > 0)
254
                textDecorations.append(" ");
255
            textDecorations.append("line-through");
256
        }
257
        if (characterRun.isShadowed()) {
258
            inline.setAttribute("text-shadow", characterRun.getFontSize() / 24 + "pt");
259
        }
260
        if (characterRun.isSmallCaps()) {
261
            inline.setAttribute("font-variant", "small-caps");
262
        }
263
        if (characterRun.getSubSuperScriptIndex() == 1) {
264
            inline.setAttribute("baseline-shift", "super");
265
            inline.setAttribute("font-size", "smaller");
266
        }
267
        if (characterRun.getSubSuperScriptIndex() == 2) {
268
            inline.setAttribute("baseline-shift", "sub");
269
            inline.setAttribute("font-size", "smaller");
270
        }
271
        if (characterRun.getUnderlineCode() > 0) {
272
            if (textDecorations.length() > 0)
273
                textDecorations.append(" ");
274
            textDecorations.append("underline");
275
        }
276
        if (textDecorations.length() > 0) {
277
            inline.setAttribute("text-decoration", textDecorations.toString());
278
        }
279
    }
280
281
    public static void setFontFamily(final Element element, final String fontFamily) {
282
        element.setAttribute("font-family", fontFamily);
283
    }
284
285
    public static void setFontSize(final Element element, final int fontSize) {
286
        element.setAttribute("font-size", String.valueOf(fontSize));
287
    }
288
289
    public static void setIndent(Paragraph paragraph, Element block) {
290
        if (paragraph.getFirstLineIndent() != 0) {
291
            block.setAttribute("text-indent",
292
                    String.valueOf(paragraph.getFirstLineIndent() / TWIPS_PER_PT));
293
        }
294
        if (paragraph.getIndentFromLeft() != 0) {
295
            block.setAttribute("start-indent",
296
                    String.valueOf(paragraph.getIndentFromLeft() / TWIPS_PER_PT));
297
        }
298
        if (paragraph.getIndentFromRight() != 0) {
299
            block.setAttribute("end-indent",
300
                    String.valueOf(paragraph.getIndentFromRight() / TWIPS_PER_PT));
301
        }
302
        if (paragraph.getSpacingBefore() != 0) {
303
            block.setAttribute("space-before",
304
                    String.valueOf(paragraph.getSpacingBefore() / TWIPS_PER_PT));
305
        }
306
        if (paragraph.getSpacingAfter() != 0) {
307
            block.setAttribute("space-after",
308
                    String.valueOf(paragraph.getSpacingAfter() / TWIPS_PER_PT));
309
        }
310
    }
311
312
    public static void setItalic(final Element element, final boolean italic) {
313
        element.setAttribute("font-style", italic ? "italic" : "normal");
314
    }
315
316
    public static void setJustification(Paragraph paragraph, final Element element) {
317
        final int justification = paragraph.getJustification();
318
        switch (justification) {
319
        case 0:
320
            element.setAttribute("text-align", "start");
321
            break;
322
        case 1:
323
            element.setAttribute("text-align", "center");
324
            break;
325
        case 2:
326
            element.setAttribute("text-align", "end");
327
            break;
328
        case 3:
329
            element.setAttribute("text-align", "justify");
330
            break;
331
        case 4:
332
            element.setAttribute("text-align", "justify");
333
            break;
334
        case 5:
335
            element.setAttribute("text-align", "center");
336
            break;
337
        case 6:
338
            element.setAttribute("text-align", "left");
339
            break;
340
        case 7:
341
            element.setAttribute("text-align", "start");
342
            break;
343
        case 8:
344
            element.setAttribute("text-align", "end");
345
            break;
346
        case 9:
347
            element.setAttribute("text-align", "justify");
348
            break;
349
        }
350
    }
351
352
    public static void setParagraphProperties(Paragraph paragraph, Element block) {
353
        setIndent(paragraph, block);
354
        setJustification(paragraph, block);
355
356
        setBorder(block, paragraph.getBottomBorder(), "bottom");
357
        setBorder(block, paragraph.getLeftBorder(), "left");
358
        setBorder(block, paragraph.getRightBorder(), "right");
359
        setBorder(block, paragraph.getTopBorder(), "top");
360
361
        if (paragraph.pageBreakBefore()) {
362
            block.setAttribute("break-before", "page");
363
        }
364
365
        block.setAttribute("hyphenate", String.valueOf(paragraph.isAutoHyphenated()));
366
367
        if (paragraph.keepOnPage()) {
368
            block.setAttribute("keep-together.within-page", "true");
369
        }
370
371
        if (paragraph.keepWithNext()) {
372
            block.setAttribute("keep-with-next.within-page", "true");
373
        }
374
375
        block.setAttribute("linefeed-treatment", "false");
376
        block.setAttribute("white-space-collapse", "false");
377
    }
378
379
    public static void setTableCellProperties(TableRow tableRow, TableCell tableCell,
380
            Element element, boolean toppest, boolean bottomest, boolean leftest, boolean rightest)
381
    {
382
        element.setAttribute("width", (tableCell.getWidth() / TWIPS_PER_INCH) + "in");
383
        element.setAttribute("padding-start", (tableRow.getGapHalf() / TWIPS_PER_INCH) + "in");
384
        element.setAttribute("padding-end", (tableRow.getGapHalf() / TWIPS_PER_INCH) + "in");
385
386
        BorderCode top = tableCell.getBrcTop() != null ? tableCell.getBrcTop() : toppest ? tableRow
387
                .getTopBorder() : tableRow.getHorizontalBorder();
388
        BorderCode bottom = tableCell.getBrcBottom() != null ? tableCell.getBrcBottom()
389
                : bottomest ? tableRow.getBottomBorder() : tableRow.getHorizontalBorder();
390
391
        BorderCode left = tableCell.getBrcLeft() != null ? tableCell.getBrcLeft()
392
                : leftest ? tableRow.getLeftBorder() : tableRow.getVerticalBorder();
393
        BorderCode right = tableCell.getBrcRight() != null ? tableCell.getBrcRight()
394
                : rightest ? tableRow.getRightBorder() : tableRow.getVerticalBorder();
395
396
        setBorder(element, bottom, "bottom");
397
        setBorder(element, left, "left");
398
        setBorder(element, right, "right");
399
        setBorder(element, top, "top");
400
    }
401
402
    public static void setTableRowProperties(TableRow tableRow, Element tableRowElement) {
403
        if (tableRow.getRowHeight() > 0) {
404
            tableRowElement.setAttribute("height", (tableRow.getRowHeight() / TWIPS_PER_INCH)
405
                    + "in");
406
        }
407
        if (!tableRow.cantSplit()) {
408
            tableRowElement.setAttribute("keep-together", "always");
409
        }
410
    }
411
412
}
(-)src/org/apache/poi/hwpf/extractor/WordToFoExtractor.java (+589 lines)
Line 0 Link Here
1
package org.apache.poi.hwpf.extractor;
2
3
import java.io.File;
4
import java.io.FileInputStream;
5
import java.io.IOException;
6
import java.util.HashMap;
7
import java.util.Map;
8
9
import javax.xml.parsers.DocumentBuilderFactory;
10
11
import org.apache.poi.hwpf.HWPFDocument;
12
import org.apache.poi.hwpf.model.ListFormatOverride;
13
import org.apache.poi.hwpf.model.ListTables;
14
import org.apache.poi.hwpf.usermodel.CharacterRun;
15
import org.apache.poi.hwpf.usermodel.Paragraph;
16
import org.apache.poi.hwpf.usermodel.Picture;
17
import org.apache.poi.hwpf.usermodel.Range;
18
import org.apache.poi.hwpf.usermodel.Section;
19
import org.apache.poi.hwpf.usermodel.SectionProperties;
20
import org.apache.poi.hwpf.usermodel.Table;
21
import org.apache.poi.hwpf.usermodel.TableCell;
22
import org.apache.poi.hwpf.usermodel.TableIterator;
23
import org.apache.poi.hwpf.usermodel.TableRow;
24
import org.w3c.dom.Document;
25
import org.w3c.dom.Element;
26
import org.w3c.dom.Text;
27
28
import static org.apache.poi.hwpf.extractor.WordToFoUtils.TWIPS_PER_INCH;
29
30
/**
31
 * @author Sergey Vladimirov (vlsergey {at} gmail {dot} com)
32
 */
33
public class WordToFoExtractor {
34
35
    public interface ImageHandler {
36
	public void onImage(Element parentBlock, byte[] imageData);
37
    }
38
39
    private static final byte BEL_MARK = 7;
40
41
    private static final byte FIELD_BEGIN_MARK = 19;
42
43
    private static final byte FIELD_END_MARK = 21;
44
45
    private static final byte FIELD_SEPARATOR_MARK = 20;
46
47
    private static final String NS_XSLFO = "http://www.w3.org/1999/XSL/Format";
48
49
    private static HWPFDocument loadDoc(File docFile) throws IOException {
50
	final FileInputStream istream = new FileInputStream(docFile);
51
	try {
52
	    return new HWPFDocument(istream);
53
	} finally {
54
	    try {
55
		istream.close();
56
	    } catch (Exception exc) {
57
		// no op
58
	    }
59
	}
60
    }
61
62
    static Document process(File docFile) throws Exception {
63
	final HWPFDocument hwpfDocument = loadDoc(docFile);
64
	WordToFoExtractor wordToFoExtractor = new WordToFoExtractor(
65
		DocumentBuilderFactory.newInstance().newDocumentBuilder()
66
			.newDocument());
67
	wordToFoExtractor.processDocument(hwpfDocument);
68
	return wordToFoExtractor.getDocument();
69
    }
70
71
    private final Document document;
72
73
    private ImageHandler imageHandler;
74
75
    private final Element layoutMasterSet;
76
77
    private final Element root;
78
79
    public WordToFoExtractor(Document document) throws Exception {
80
	this.document = document;
81
82
	root = document.createElementNS(NS_XSLFO, "fo:root");
83
	document.appendChild(root);
84
85
	layoutMasterSet = document.createElementNS(NS_XSLFO,
86
		"fo:layout-master-set");
87
	root.appendChild(layoutMasterSet);
88
    }
89
90
    protected Element addFlowToPageSequence(final Element pageSequence,
91
	    String flowName) {
92
	final Element flow = document.createElementNS(NS_XSLFO, "fo:flow");
93
	flow.setAttribute("flow-name", flowName);
94
	pageSequence.appendChild(flow);
95
96
	return flow;
97
    }
98
99
    protected Element addListItem(Element listBlock) {
100
	Element result = createListItem();
101
	listBlock.appendChild(result);
102
	return result;
103
    }
104
105
    protected Element addListItemBody(Element listItem) {
106
	Element result = createListItemBody();
107
	listItem.appendChild(result);
108
	return result;
109
    }
110
111
    protected Element addListItemLabel(Element listItem, String text) {
112
	Element result = createListItemLabel(text);
113
	listItem.appendChild(result);
114
	return result;
115
    }
116
117
    protected Element addPageSequence(String pageMaster) {
118
	final Element pageSequence = document.createElementNS(NS_XSLFO,
119
		"fo:page-sequence");
120
	pageSequence.setAttribute("master-reference", pageMaster);
121
	root.appendChild(pageSequence);
122
	return pageSequence;
123
    }
124
125
    protected Element addRegionBody(Element pageMaster) {
126
	final Element regionBody = document.createElementNS(NS_XSLFO,
127
		"fo:region-body");
128
	pageMaster.appendChild(regionBody);
129
130
	return regionBody;
131
    }
132
133
    protected Element addSimplePageMaster(String masterName) {
134
	final Element simplePageMaster = document.createElementNS(NS_XSLFO,
135
		"fo:simple-page-master");
136
	simplePageMaster.setAttribute("master-name", masterName);
137
	layoutMasterSet.appendChild(simplePageMaster);
138
139
	return simplePageMaster;
140
    }
141
142
    protected Element addTable(Element flow) {
143
	final Element table = document.createElementNS(NS_XSLFO, "fo:table");
144
	flow.appendChild(table);
145
	return table;
146
    }
147
148
    protected Element createBlock() {
149
	return document.createElementNS(NS_XSLFO, "fo:block");
150
    }
151
152
    protected Element createExternalGraphic(String source) {
153
	Element result = document.createElementNS(NS_XSLFO,
154
		"fo:external-graphic");
155
	result.setAttribute("src", "url('" + source + "')");
156
	return result;
157
    }
158
159
    protected Element createInline() {
160
	return document.createElementNS(NS_XSLFO, "fo:inline");
161
    }
162
163
    protected Element createLeader() {
164
	return document.createElementNS(NS_XSLFO, "fo:leader");
165
    }
166
167
    protected Element createListBlock() {
168
	return document.createElementNS(NS_XSLFO, "fo:list-block");
169
    }
170
171
    protected Element createListItem() {
172
	return document.createElementNS(NS_XSLFO, "fo:list-item");
173
    }
174
175
    protected Element createListItemBody() {
176
	return document.createElementNS(NS_XSLFO, "fo:list-item-body");
177
    }
178
179
    protected Element createListItemLabel(String text) {
180
	Element result = document.createElementNS(NS_XSLFO,
181
		"fo:list-item-label");
182
	Element block = createBlock();
183
	block.appendChild(document.createTextNode(text));
184
	result.appendChild(block);
185
	return result;
186
    }
187
188
    protected String createPageMaster(SectionProperties sep, String type,
189
	    int section) {
190
	float height = sep.getYaPage() / TWIPS_PER_INCH;
191
	float width = sep.getXaPage() / TWIPS_PER_INCH;
192
	float leftMargin = sep.getDxaLeft() / TWIPS_PER_INCH;
193
	float rightMargin = sep.getDxaRight() / TWIPS_PER_INCH;
194
	float topMargin = sep.getDyaTop() / TWIPS_PER_INCH;
195
	float bottomMargin = sep.getDyaBottom() / TWIPS_PER_INCH;
196
197
	// add these to the header
198
	String pageMasterName = type + "-page" + section;
199
200
	Element pageMaster = addSimplePageMaster(pageMasterName);
201
	pageMaster.setAttribute("page-height", height + "in");
202
	pageMaster.setAttribute("page-width", width + "in");
203
204
	Element regionBody = addRegionBody(pageMaster);
205
	regionBody.setAttribute("margin", topMargin + "in " + rightMargin
206
		+ "in " + bottomMargin + "in " + leftMargin + "in");
207
208
	WordToFoUtils.setBorder(regionBody, sep.getBrcTop(), "top");
209
	WordToFoUtils.setBorder(regionBody, sep.getBrcBottom(), "bottom");
210
	WordToFoUtils.setBorder(regionBody, sep.getBrcLeft(), "left");
211
	WordToFoUtils.setBorder(regionBody, sep.getBrcRight(), "right");
212
213
	if (sep.getCcolM1() > 0) {
214
	    regionBody.setAttribute("column-count", "" + (sep.getCcolM1() + 1));
215
	    if (sep.getFEvenlySpaced()) {
216
		regionBody.setAttribute("column-gap",
217
			(sep.getDxaColumns() / TWIPS_PER_INCH) + "in");
218
	    } else {
219
		regionBody.setAttribute("column-gap", "0.25in");
220
	    }
221
	}
222
223
	return pageMasterName;
224
    }
225
226
    protected Element createTableBody() {
227
	return document.createElementNS(NS_XSLFO, "fo:table-body");
228
    }
229
230
    protected Element createTableCell() {
231
	return document.createElementNS(NS_XSLFO, "fo:table-cell");
232
    }
233
234
    protected Element createTableHeader() {
235
	return document.createElementNS(NS_XSLFO, "fo:table-header");
236
    }
237
238
    protected Element createTableRow() {
239
	return document.createElementNS(NS_XSLFO, "fo:table-row");
240
    }
241
242
    protected Text createText(String data) {
243
	return document.createTextNode(data);
244
    }
245
246
    public Document getDocument() {
247
	return document;
248
    }
249
250
    public ImageHandler getImageHandler() {
251
	return imageHandler;
252
    }
253
254
    protected void processDocument(HWPFDocument hwpfDocument) {
255
	final Range range = hwpfDocument.getRange();
256
257
	for (int s = 0; s < range.numSections(); s++) {
258
	    processSection(hwpfDocument, range.getSection(s), s);
259
	}
260
    }
261
262
    protected void processParagraph(HWPFDocument hwpfDocument,
263
	    Element parentFopElement, int currentTableLevel,
264
	    Paragraph paragraph, String bulletText) {
265
	final Element block = createBlock();
266
	parentFopElement.appendChild(block);
267
268
	WordToFoUtils.setParagraphProperties(paragraph, block);
269
270
	final int charRuns = paragraph.numCharacterRuns();
271
272
	if (charRuns == 0) {
273
	    return;
274
	}
275
276
	final String pFontName;
277
	final int pFontSize;
278
	final boolean pBold;
279
	final boolean pItalic;
280
	{
281
	    CharacterRun characterRun = paragraph.getCharacterRun(0);
282
	    pFontSize = characterRun.getFontSize() / 2;
283
	    pFontName = characterRun.getFontName();
284
	    pBold = characterRun.isBold();
285
	    pItalic = characterRun.isItalic();
286
	}
287
	WordToFoUtils.setFontFamily(block, pFontName);
288
	WordToFoUtils.setFontSize(block, pFontSize);
289
	WordToFoUtils.setBold(block, pBold);
290
	WordToFoUtils.setItalic(block, pItalic);
291
292
	StringBuilder lineText = new StringBuilder();
293
294
	if (WordToFoUtils.isNotEmpty(bulletText)) {
295
	    Element inline = createInline();
296
	    block.appendChild(inline);
297
298
	    Text textNode = createText(bulletText);
299
	    inline.appendChild(textNode);
300
301
	    lineText.append(bulletText);
302
	}
303
304
	for (int c = 0; c < charRuns; c++) {
305
	    CharacterRun characterRun = paragraph.getCharacterRun(c);
306
307
	    String text = characterRun.text();
308
	    if (text.getBytes().length == 0)
309
		continue;
310
311
	    if (text.getBytes()[0] == FIELD_BEGIN_MARK) {
312
		int skipTo = tryImage(hwpfDocument, paragraph, c, block);
313
314
		if (skipTo != c) {
315
		    c = skipTo;
316
		    continue;
317
		}
318
		continue;
319
	    }
320
	    if (text.getBytes()[0] == FIELD_SEPARATOR_MARK) {
321
		continue;
322
	    }
323
	    if (text.getBytes()[0] == FIELD_END_MARK) {
324
		continue;
325
	    }
326
327
	    if (characterRun.isSpecialCharacter() || characterRun.isObj()
328
		    || characterRun.isOle2()) {
329
		continue;
330
	    }
331
332
	    Element inline = createInline();
333
	    if (characterRun.isBold() != pBold) {
334
		WordToFoUtils.setBold(inline, characterRun.isBold());
335
	    }
336
	    if (characterRun.isItalic() != pItalic) {
337
		WordToFoUtils.setItalic(inline, characterRun.isItalic());
338
	    }
339
	    if (!WordToFoUtils.equals(characterRun.getFontName(), pFontName)) {
340
		WordToFoUtils.setFontFamily(inline, characterRun.getFontName());
341
	    }
342
	    if (characterRun.getFontSize() / 2 != pFontSize) {
343
		WordToFoUtils
344
			.setFontSize(inline, characterRun.getFontSize() / 2);
345
	    }
346
	    WordToFoUtils.setCharactersProperties(characterRun, inline);
347
	    block.appendChild(inline);
348
349
	    if (text.endsWith("\r")
350
		    || (text.charAt(text.length() - 1) == BEL_MARK && currentTableLevel != 0))
351
		text = text.substring(0, text.length() - 1);
352
353
	    Text textNode = createText(text);
354
	    inline.appendChild(textNode);
355
356
	    lineText.append(text);
357
	}
358
359
	if (lineText.toString().trim().length() == 0) {
360
	    Element leader = createLeader();
361
	    block.appendChild(leader);
362
	}
363
364
	return;
365
    }
366
367
    protected void processSection(HWPFDocument hwpfDocument, Section section,
368
	    int sectionCounter) {
369
	String regularPage = createPageMaster(
370
		WordToFoUtils.getSectionProperties(section), "page",
371
		sectionCounter);
372
373
	Element pageSequence = addPageSequence(regularPage);
374
	Element flow = addFlowToPageSequence(pageSequence, "xsl-region-body");
375
376
	processSectionParagraphes(hwpfDocument, flow, section, 0);
377
    }
378
379
    protected void processSectionParagraphes(HWPFDocument hwpfDocument,
380
	    Element flow, Range range, int currentTableLevel) {
381
	final Map<Integer, Table> allTables = new HashMap<Integer, Table>();
382
	for (TableIterator tableIterator = WordToFoUtils.newTableIterator(range,
383
		currentTableLevel + 1); tableIterator.hasNext();) {
384
	    Table next = tableIterator.next();
385
	    allTables.put(Integer.valueOf(next.getStartOffset()), next);
386
	}
387
388
	final ListTables listTables = hwpfDocument.getListTables();
389
	int currentListInfo = 0;
390
391
	final int paragraphs = range.numParagraphs();
392
	for (int p = 0; p < paragraphs; p++) {
393
	    Paragraph paragraph = range.getParagraph(p);
394
395
	    if (allTables.containsKey(Integer.valueOf(paragraph
396
		    .getStartOffset()))) {
397
		Table table = allTables.get(Integer.valueOf(paragraph
398
			.getStartOffset()));
399
		processTable(hwpfDocument, flow, table, currentTableLevel + 1);
400
		continue;
401
	    }
402
403
	    if (paragraph.isInTable()
404
		    && paragraph.getTableLevel() != currentTableLevel) {
405
		continue;
406
	    }
407
408
	    if (paragraph.getIlfo() != currentListInfo) {
409
		currentListInfo = paragraph.getIlfo();
410
	    }
411
412
	    if (currentListInfo != 0) {
413
		final ListFormatOverride listFormatOverride = listTables
414
			.getOverride(paragraph.getIlfo());
415
416
		String label = WordToFoUtils.getBulletText(listTables,
417
			paragraph, listFormatOverride.getLsid());
418
419
		processParagraph(hwpfDocument, flow, currentTableLevel,
420
			paragraph, label);
421
	    } else {
422
		processParagraph(hwpfDocument, flow, currentTableLevel,
423
			paragraph, WordToFoUtils.EMPTY);
424
	    }
425
	}
426
427
    }
428
429
    protected void processTable(HWPFDocument hwpfDocument, Element flow,
430
	    Table table, int thisTableLevel) {
431
	Element tableElement = addTable(flow);
432
433
	Element tableHeader = createTableHeader();
434
	Element tableBody = createTableBody();
435
436
	final int tableRows = table.numRows();
437
438
	int maxColumns = Integer.MIN_VALUE;
439
	for (int r = 0; r < tableRows; r++) {
440
	    maxColumns = Math.max(maxColumns, table.getRow(r).numCells());
441
	}
442
443
	for (int r = 0; r < tableRows; r++) {
444
	    TableRow tableRow = table.getRow(r);
445
446
	    Element tableRowElement = createTableRow();
447
	    WordToFoUtils.setTableRowProperties(tableRow, tableRowElement);
448
449
	    final int rowCells = tableRow.numCells();
450
	    for (int c = 0; c < rowCells; c++) {
451
		TableCell tableCell = tableRow.getCell(c);
452
453
		if (tableCell.isMerged() && !tableCell.isFirstMerged())
454
		    continue;
455
456
		if (tableCell.isVerticallyMerged()
457
			&& !tableCell.isFirstVerticallyMerged())
458
		    continue;
459
460
		Element tableCellElement = createTableCell();
461
		WordToFoUtils.setTableCellProperties(tableRow, tableCell,
462
			tableCellElement, r == 0, r == tableRows - 1, c == 0,
463
			c == rowCells - 1);
464
465
		if (tableCell.isFirstMerged()) {
466
		    int count = 0;
467
		    for (int c1 = c; c1 < rowCells; c1++) {
468
			TableCell nextCell = tableRow.getCell(c1);
469
			if (nextCell.isMerged())
470
			    count++;
471
			if (!nextCell.isMerged())
472
			    break;
473
		    }
474
		    tableCellElement.setAttribute("number-columns-spanned", ""
475
			    + count);
476
		} else {
477
		    if (c == rowCells - 1 && c != maxColumns - 1) {
478
			tableCellElement.setAttribute("number-columns-spanned",
479
				"" + (maxColumns - c));
480
		    }
481
		}
482
483
		if (tableCell.isFirstVerticallyMerged()) {
484
		    int count = 0;
485
		    for (int r1 = r; r1 < tableRows; r1++) {
486
			TableRow nextRow = table.getRow(r1);
487
			if (nextRow.numCells() < c)
488
			    break;
489
			TableCell nextCell = nextRow.getCell(c);
490
			if (nextCell.isVerticallyMerged())
491
			    count++;
492
			if (!nextCell.isVerticallyMerged())
493
			    break;
494
		    }
495
		    tableCellElement.setAttribute("number-rows-spanned", ""
496
			    + count);
497
		}
498
499
		processSectionParagraphes(hwpfDocument, tableCellElement,
500
			tableCell, thisTableLevel);
501
502
		if (!tableCellElement.hasChildNodes()) {
503
		    tableCellElement.appendChild(createBlock());
504
		}
505
506
		tableRowElement.appendChild(tableCellElement);
507
	    }
508
509
	    if (tableRow.isTableHeader()) {
510
		tableHeader.appendChild(tableRowElement);
511
	    } else {
512
		tableBody.appendChild(tableRowElement);
513
	    }
514
	}
515
516
	if (tableHeader.hasChildNodes()) {
517
	    tableElement.appendChild(tableHeader);
518
	}
519
	if (tableBody.hasChildNodes()) {
520
	    tableElement.appendChild(tableBody);
521
	} else {
522
	    System.err.println("Table without body");
523
	}
524
    }
525
526
    public void setImageHandler(ImageHandler imageHandler) {
527
	this.imageHandler = imageHandler;
528
    }
529
530
    protected int tryImage(HWPFDocument hwpfDocument, Paragraph paragraph,
531
	    int beginMark, Element currentBlock) {
532
	int separatorMark = -1;
533
	int pictureMark = -1;
534
	int endMark = -1;
535
	for (int c = beginMark + 1; c < paragraph.numCharacterRuns(); c++) {
536
	    CharacterRun characterRun = paragraph.getCharacterRun(c);
537
538
	    String text = characterRun.text();
539
	    if (text.getBytes().length == 0)
540
		continue;
541
542
	    if (text.getBytes()[0] == FIELD_SEPARATOR_MARK) {
543
		if (separatorMark != -1) {
544
		    // double;
545
		    return beginMark;
546
		}
547
548
		separatorMark = c;
549
		continue;
550
	    }
551
552
	    if (text.getBytes()[0] == FIELD_END_MARK) {
553
		if (endMark != -1) {
554
		    // double;
555
		    return beginMark;
556
		}
557
558
		endMark = c;
559
		break;
560
	    }
561
562
	    if (hwpfDocument.getPicturesTable().hasPicture(characterRun)) {
563
		if (pictureMark != -1) {
564
		    // double;
565
		    return beginMark;
566
		}
567
568
		pictureMark = c;
569
		continue;
570
	    }
571
	}
572
573
	if (separatorMark == -1 || pictureMark == -1 || endMark == -1)
574
	    return beginMark;
575
576
	if (imageHandler != null) {
577
	    final CharacterRun pictureRun = paragraph
578
		    .getCharacterRun(pictureMark);
579
	    final Picture picture = hwpfDocument.getPicturesTable()
580
		    .extractPicture(pictureRun, true);
581
	    final byte[] content = picture.getContent();
582
583
	    imageHandler.onImage(currentBlock, content);
584
	}
585
586
	return endMark;
587
    }
588
589
}

Return to bug 51351