001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hwpf.model;
019:
020: import java.util.ArrayList;
021: import java.io.IOException;
022: import java.util.List;
023:
024: import org.apache.poi.util.LittleEndian;
025: import org.apache.poi.hwpf.model.io.*;
026:
027: /**
028: * @author Ryan Ackley
029: */
030: public class SectionTable {
031: private static final int SED_SIZE = 12;
032:
033: protected ArrayList _sections = new ArrayList();
034: protected List _text;
035:
036: public SectionTable() {
037: }
038:
039: public SectionTable(byte[] documentStream, byte[] tableStream,
040: int offset, int size, int fcMin, List tpt) {
041: PlexOfCps sedPlex = new PlexOfCps(tableStream, offset, size,
042: SED_SIZE);
043: _text = tpt;
044:
045: int length = sedPlex.length();
046:
047: for (int x = 0; x < length; x++) {
048: GenericPropertyNode node = sedPlex.getProperty(x);
049: SectionDescriptor sed = new SectionDescriptor(node
050: .getBytes(), 0);
051:
052: int fileOffset = sed.getFc();
053:
054: // check for the optimization
055: if (fileOffset == 0xffffffff) {
056: _sections.add(new SEPX(sed, CPtoFC(node.getStart()),
057: CPtoFC(node.getEnd()), new byte[0]));
058: } else {
059: // The first short at the offset is the size of the grpprl.
060: int sepxSize = LittleEndian.getShort(documentStream,
061: fileOffset);
062: byte[] buf = new byte[sepxSize];
063: fileOffset += LittleEndian.SHORT_SIZE;
064: System.arraycopy(documentStream, fileOffset, buf, 0,
065: buf.length);
066: _sections.add(new SEPX(sed, CPtoFC(node.getStart()),
067: CPtoFC(node.getEnd()), buf));
068: }
069: }
070: }
071:
072: public void adjustForInsert(int listIndex, int length) {
073: int size = _sections.size();
074: SEPX sepx = (SEPX) _sections.get(listIndex);
075: sepx.setEnd(sepx.getEnd() + length);
076:
077: for (int x = listIndex + 1; x < size; x++) {
078: sepx = (SEPX) _sections.get(x);
079: sepx.setStart(sepx.getStart() + length);
080: sepx.setEnd(sepx.getEnd() + length);
081: }
082: }
083:
084: // goss version of CPtoFC - this takes into account non-contiguous textpieces
085: // that we have come across in real world documents. Tests against the example
086: // code in HWPFDocument show no variation to Ryan's version of the code in
087: // normal use, but this version works with our non-contiguous test case.
088: // So far unable to get this test case to be written out as well due to
089: // other issues. - piers
090: private int CPtoFC(int CP) {
091: TextPiece TP = null;
092:
093: for (int i = _text.size() - 1; i > -1; i--) {
094: TP = (TextPiece) _text.get(i);
095:
096: if (CP >= TP.getCP())
097: break;
098: }
099: int FC = TP.getPieceDescriptor().getFilePosition();
100: int offset = CP - TP.getCP();
101: if (TP.usesUnicode())
102: offset *= 2;
103: FC = FC
104: + offset
105: - ((TextPiece) _text.get(0)).getPieceDescriptor()
106: .getFilePosition();
107: return FC;
108: }
109:
110: // Ryans code
111: private int FCtoCP(int fc) {
112: int size = _text.size();
113: int cp = 0;
114: for (int x = 0; x < size; x++) {
115: TextPiece piece = (TextPiece) _text.get(x);
116:
117: if (fc <= piece.getEnd()) {
118: cp += ((fc - piece.getStart()) / (piece.usesUnicode() ? 2
119: : 1));
120: break;
121: } else {
122: cp += ((piece.getEnd() - piece.getStart()) / (piece
123: .usesUnicode() ? 2 : 1));
124: }
125: }
126: return cp;
127: }
128:
129: public ArrayList getSections() {
130: return _sections;
131: }
132:
133: public void writeTo(HWPFFileSystem sys, int fcMin)
134: throws IOException {
135: HWPFOutputStream docStream = sys.getStream("WordDocument");
136: HWPFOutputStream tableStream = sys.getStream("1Table");
137:
138: int offset = docStream.getOffset();
139: int len = _sections.size();
140: PlexOfCps plex = new PlexOfCps(SED_SIZE);
141:
142: for (int x = 0; x < len; x++) {
143: SEPX sepx = (SEPX) _sections.get(x);
144: byte[] grpprl = sepx.getGrpprl();
145:
146: // write the sepx to the document stream. starts with a 2 byte size
147: // followed by the grpprl
148: byte[] shortBuf = new byte[2];
149: LittleEndian.putShort(shortBuf, (short) grpprl.length);
150:
151: docStream.write(shortBuf);
152: docStream.write(grpprl);
153:
154: // set the fc in the section descriptor
155: SectionDescriptor sed = sepx.getSectionDescriptor();
156: sed.setFc(offset);
157:
158: // add the section descriptor bytes to the PlexOfCps.
159:
160: // original line -
161: //GenericPropertyNode property = new GenericPropertyNode(sepx.getStart(), sepx.getEnd(), sed.toByteArray());
162:
163: // Line using Ryan's FCtoCP() conversion method -
164: // unable to observe any effect on our testcases when using this code - piers
165: GenericPropertyNode property = new GenericPropertyNode(
166: FCtoCP(sepx.getStart()), FCtoCP(sepx.getEnd()), sed
167: .toByteArray());
168:
169: plex.addProperty(property);
170:
171: offset = docStream.getOffset();
172: }
173: tableStream.write(plex.toByteArray());
174: }
175: }
|