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.io.OutputStream;
023:
024: import org.apache.poi.hwpf.model.io.*;
025: import org.apache.poi.hwpf.sprm.SprmBuffer;
026:
027: import org.apache.poi.poifs.common.POIFSConstants;
028: import org.apache.poi.util.LittleEndian;
029:
030: /**
031: * This class represents the bin table of Word document but it also serves as a
032: * holder for all of the paragraphs of document that have been loaded into
033: * memory.
034: *
035: * @author Ryan Ackley
036: */
037: public class PAPBinTable {
038: protected ArrayList _paragraphs = new ArrayList();
039: byte[] _dataStream;
040:
041: public PAPBinTable() {
042: }
043:
044: public PAPBinTable(byte[] documentStream, byte[] tableStream,
045: byte[] dataStream, int offset, int size, int fcMin) {
046: PlexOfCps binTable = new PlexOfCps(tableStream, offset, size, 4);
047:
048: int length = binTable.length();
049: for (int x = 0; x < length; x++) {
050: GenericPropertyNode node = binTable.getProperty(x);
051:
052: int pageNum = LittleEndian.getInt(node.getBytes());
053: int pageOffset = POIFSConstants.BIG_BLOCK_SIZE * pageNum;
054:
055: PAPFormattedDiskPage pfkp = new PAPFormattedDiskPage(
056: documentStream, dataStream, pageOffset, fcMin);
057:
058: int fkpSize = pfkp.size();
059:
060: for (int y = 0; y < fkpSize; y++) {
061: _paragraphs.add(pfkp.getPAPX(y));
062: }
063: }
064: _dataStream = dataStream;
065: }
066:
067: public void insert(int listIndex, int cpStart, SprmBuffer buf) {
068: PAPX forInsert = new PAPX(cpStart, cpStart, buf, _dataStream);
069: if (listIndex == _paragraphs.size()) {
070: _paragraphs.add(forInsert);
071: } else {
072: PAPX currentPap = (PAPX) _paragraphs.get(listIndex);
073: if (currentPap != null && currentPap.getStart() < cpStart) {
074: SprmBuffer clonedBuf = null;
075: try {
076: clonedBuf = (SprmBuffer) currentPap.getSprmBuf()
077: .clone();
078: } catch (CloneNotSupportedException exc) {
079: exc.printStackTrace();
080: }
081: currentPap.setEnd(cpStart);
082: PAPX splitPap = new PAPX(cpStart, currentPap.getEnd(),
083: clonedBuf, _dataStream);
084: _paragraphs.add(++listIndex, forInsert);
085: _paragraphs.add(++listIndex, splitPap);
086: } else {
087: _paragraphs.add(listIndex, forInsert);
088: }
089: }
090:
091: }
092:
093: public void adjustForDelete(int listIndex, int offset, int length) {
094: int size = _paragraphs.size();
095: int endMark = offset + length;
096: int endIndex = listIndex;
097:
098: PAPX papx = (PAPX) _paragraphs.get(endIndex);
099: while (papx.getEnd() < endMark) {
100: papx = (PAPX) _paragraphs.get(++endIndex);
101: }
102: if (listIndex == endIndex) {
103: papx = (PAPX) _paragraphs.get(endIndex);
104: papx.setEnd((papx.getEnd() - endMark) + offset);
105: } else {
106: papx = (PAPX) _paragraphs.get(listIndex);
107: papx.setEnd(offset);
108: for (int x = listIndex + 1; x < endIndex; x++) {
109: papx = (PAPX) _paragraphs.get(x);
110: papx.setStart(offset);
111: papx.setEnd(offset);
112: }
113: papx = (PAPX) _paragraphs.get(endIndex);
114: papx.setEnd((papx.getEnd() - endMark) + offset);
115: }
116:
117: for (int x = endIndex + 1; x < size; x++) {
118: papx = (PAPX) _paragraphs.get(x);
119: papx.setStart(papx.getStart() - length);
120: papx.setEnd(papx.getEnd() - length);
121: }
122: }
123:
124: public void adjustForInsert(int listIndex, int length) {
125: int size = _paragraphs.size();
126: PAPX papx = (PAPX) _paragraphs.get(listIndex);
127: papx.setEnd(papx.getEnd() + length);
128:
129: for (int x = listIndex + 1; x < size; x++) {
130: papx = (PAPX) _paragraphs.get(x);
131: papx.setStart(papx.getStart() + length);
132: papx.setEnd(papx.getEnd() + length);
133: }
134: }
135:
136: public ArrayList getParagraphs() {
137: return _paragraphs;
138: }
139:
140: public void writeTo(HWPFFileSystem sys, int fcMin)
141: throws IOException {
142:
143: HWPFOutputStream docStream = sys.getStream("WordDocument");
144: OutputStream tableStream = sys.getStream("1Table");
145:
146: PlexOfCps binTable = new PlexOfCps(4);
147:
148: // each FKP must start on a 512 byte page.
149: int docOffset = docStream.getOffset();
150: int mod = docOffset % POIFSConstants.BIG_BLOCK_SIZE;
151: if (mod != 0) {
152: byte[] padding = new byte[POIFSConstants.BIG_BLOCK_SIZE
153: - mod];
154: docStream.write(padding);
155: }
156:
157: // get the page number for the first fkp
158: docOffset = docStream.getOffset();
159: int pageNum = docOffset / POIFSConstants.BIG_BLOCK_SIZE;
160:
161: // get the ending fc
162: int endingFc = ((PropertyNode) _paragraphs.get(_paragraphs
163: .size() - 1)).getEnd();
164: endingFc += fcMin;
165:
166: ArrayList overflow = _paragraphs;
167: do {
168: PropertyNode startingProp = (PropertyNode) overflow.get(0);
169: int start = startingProp.getStart() + fcMin;
170:
171: PAPFormattedDiskPage pfkp = new PAPFormattedDiskPage(
172: _dataStream);
173: pfkp.fill(overflow);
174:
175: byte[] bufFkp = pfkp.toByteArray(fcMin);
176: docStream.write(bufFkp);
177: overflow = pfkp.getOverflow();
178:
179: int end = endingFc;
180: if (overflow != null) {
181: end = ((PropertyNode) overflow.get(0)).getStart()
182: + fcMin;
183: }
184:
185: byte[] intHolder = new byte[4];
186: LittleEndian.putInt(intHolder, pageNum++);
187: binTable.addProperty(new GenericPropertyNode(start, end,
188: intHolder));
189:
190: } while (overflow != null);
191: tableStream.write(binTable.toByteArray());
192: }
193:
194: }
|