KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > poi > hwpf > model > PAPFormattedDiskPage


1
2 /* ====================================================================
3    Copyright 2002-2004 Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16 ==================================================================== */

17         
18 package org.apache.poi.hwpf.model;
19
20 import org.apache.poi.poifs.common.POIFSConstants;
21 import org.apache.poi.util.LittleEndian;
22
23 import java.util.ArrayList JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Arrays JavaDoc;
26
27 /**
28  * Represents a PAP FKP. The style properties for paragraph and character runs
29  * are stored in fkps. There are PAP fkps for paragraph properties and CHP fkps
30  * for character run properties. The first part of the fkp for both CHP and PAP
31  * fkps consists of an array of 4 byte int offsets in the main stream for that
32  * Paragraph's or Character run's text. The ending offset is the next
33  * value in the array. For example, if an fkp has X number of Paragraph's
34  * stored in it then there are (x + 1) 4 byte ints in the beginning array. The
35  * number X is determined by the last byte in a 512 byte fkp.
36  *
37  * CHP and PAP fkps also store the compressed styles(grpprl) that correspond to
38  * the offsets on the front of the fkp. The offset of the grpprls is determined
39  * differently for CHP fkps and PAP fkps.
40  *
41  * @author Ryan Ackley
42  */

43 public class PAPFormattedDiskPage extends FormattedDiskPage
44 {
45
46     private static final int BX_SIZE = 13;
47     private static final int FC_SIZE = 4;
48
49     private ArrayList JavaDoc _papxList = new ArrayList JavaDoc();
50     private ArrayList JavaDoc _overFlow;
51     private byte[] _dataStream;
52
53
54     public PAPFormattedDiskPage(byte[] dataStream)
55     {
56       _dataStream = dataStream;
57     }
58
59     /**
60      * Creates a PAPFormattedDiskPage from a 512 byte array
61      */

62     public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin)
63     {
64       super(documentStream, offset);
65
66       for (int x = 0; x < _crun; x++)
67       {
68         _papxList.add(new PAPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), getParagraphHeight(x), dataStream));
69       }
70       _fkp = null;
71       _dataStream = dataStream;
72     }
73
74     /**
75      * Fills the queue for writing.
76      *
77      * @param filler a List of PAPXs
78      */

79     public void fill(List JavaDoc filler)
80     {
81       _papxList.addAll(filler);
82     }
83
84     /**
85      * Used when writing out a Word docunment. This method is part of a sequence
86      * that is necessary because there is no easy and efficient way to
87      * determine the number PAPX's that will fit into one FKP. THe sequence is
88      * as follows:
89      *
90      * fill()
91      * toByteArray()
92      * getOverflow()
93      *
94      * @return The remaining PAPXs that didn't fit into this FKP.
95      */

96     ArrayList JavaDoc getOverflow()
97     {
98       return _overFlow;
99     }
100
101     /**
102      * Gets the PAPX at index.
103      * @param index The index to get the PAPX for.
104      * @return The PAPX at index.
105      */

106     public PAPX getPAPX(int index)
107     {
108       return (PAPX)_papxList.get(index);
109     }
110
111     /**
112      * Gets the papx for the paragraph at index in this fkp.
113      *
114      * @param index The index of the papx to get.
115      * @return a papx grpprl.
116      */

117     protected byte[] getGrpprl(int index)
118     {
119         int papxOffset = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + (((_crun + 1) * FC_SIZE) + (index * BX_SIZE)));
120         int size = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + papxOffset);
121         if(size == 0)
122         {
123             size = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + ++papxOffset);
124         }
125         else
126         {
127             size--;
128         }
129
130         byte[] papx = new byte[size];
131         System.arraycopy(_fkp, _offset + ++papxOffset, papx, 0, size);
132         return papx;
133     }
134
135     /**
136      * Creates a byte array representation of this data structure. Suitable for
137      * writing to a Word document.
138      *
139      * @param fcMin The file offset in the main stream where text begins.
140      * @return A byte array representing this data structure.
141      */

142     protected byte[] toByteArray(int fcMin)
143     {
144       byte[] buf = new byte[512];
145       int size = _papxList.size();
146       int grpprlOffset = 0;
147       int bxOffset = 0;
148       int fcOffset = 0;
149       byte[] lastGrpprl = new byte[0];
150
151       // total size is currently the size of one FC
152
int totalSize = FC_SIZE;
153
154       int index = 0;
155       for (; index < size; index++)
156       {
157         byte[] grpprl = ((PAPX)_papxList.get(index)).getGrpprl();
158         int grpprlLength = grpprl.length;
159
160         // is grpprl huge?
161
if(grpprlLength > 488)
162         {
163           grpprlLength = 8; // set equal to size of sprmPHugePapx grpprl
164
}
165
166         // check to see if we have enough room for an FC, a BX, and the grpprl
167
// and the 1 byte size of the grpprl.
168
int addition = 0;
169         if (!Arrays.equals(grpprl, lastGrpprl))
170         {
171           addition = (FC_SIZE + BX_SIZE + grpprlLength + 1);
172         }
173         else
174         {
175           addition = (FC_SIZE + BX_SIZE);
176         }
177
178         totalSize += addition;
179
180         // if size is uneven we will have to add one so the first grpprl falls
181
// on a word boundary
182
if (totalSize > 511 + (index % 2))
183         {
184           totalSize -= addition;
185           break;
186         }
187
188         // grpprls must fall on word boundaries
189
if (grpprlLength % 2 > 0)
190         {
191           totalSize += 1;
192         }
193         else
194         {
195           totalSize += 2;
196         }
197         lastGrpprl = grpprl;
198       }
199
200       // see if we couldn't fit some
201
if (index != size)
202       {
203         _overFlow = new ArrayList JavaDoc();
204         _overFlow.addAll(_papxList.subList(index, size));
205       }
206
207       // index should equal number of papxs that will be in this fkp now.
208
buf[511] = (byte)index;
209
210       bxOffset = (FC_SIZE * index) + FC_SIZE;
211       grpprlOffset = 511;
212
213       PAPX papx = null;
214       lastGrpprl = new byte[0];
215       for (int x = 0; x < index; x++)
216       {
217         papx = (PAPX)_papxList.get(x);
218         byte[] phe = papx.getParagraphHeight().toByteArray();
219         byte[] grpprl = papx.getGrpprl();
220
221         // is grpprl huge?
222
if(grpprl.length > 488)
223         {
224           // if so do we have storage at getHugeGrpprlOffset()
225
int hugeGrpprlOffset = papx.getHugeGrpprlOffset();
226           if(hugeGrpprlOffset == -1) // then we have no storage...
227
{
228             throw new UnsupportedOperationException JavaDoc(
229                   "This Paragraph has no dataStream storage.");
230           }
231           else // we have some storage...
232
{
233             // get the size of the existing storage
234
int maxHugeGrpprlSize = LittleEndian.getUShort(_dataStream,
235                 hugeGrpprlOffset);
236
237             if (maxHugeGrpprlSize < grpprl.length-2) // grpprl.length-2 because we don't store the istd
238
throw new UnsupportedOperationException JavaDoc(
239                   "This Paragraph's dataStream storage is too small.");
240           }
241
242           // store grpprl at hugeGrpprlOffset
243
System.arraycopy(grpprl, 2, _dataStream, hugeGrpprlOffset + 2,
244                            grpprl.length - 2); // grpprl.length-2 because we don't store the istd
245
LittleEndian.putUShort(_dataStream, hugeGrpprlOffset, grpprl.length - 2);
246
247           // grpprl = grpprl containing only a sprmPHugePapx2
248
int istd = LittleEndian.getUShort(grpprl, 0);
249           grpprl = new byte[8];
250           LittleEndian.putUShort(grpprl, 0, istd);
251           LittleEndian.putUShort(grpprl, 2, 0x6646); // sprmPHugePapx2
252
LittleEndian.putInt(grpprl, 4, hugeGrpprlOffset);
253         }
254
255         boolean same = Arrays.equals(lastGrpprl, grpprl);
256         if (!same)
257         {
258           grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
259           grpprlOffset -= (grpprlOffset % 2);
260         }
261         LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
262         buf[bxOffset] = (byte)(grpprlOffset/2);
263         System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);
264
265         // refer to the section on PAPX in the spec. Places a size on the front
266
// of the PAPX. Has to do with how the grpprl stays on word
267
// boundaries.
268
if (!same)
269         {
270           int copyOffset = grpprlOffset;
271           if ( (grpprl.length % 2) > 0)
272           {
273             buf[copyOffset++] = (byte) ( (grpprl.length + 1) / 2);
274           }
275           else
276           {
277             buf[++copyOffset] = (byte) ( (grpprl.length) / 2);
278             copyOffset++;
279           }
280           System.arraycopy(grpprl, 0, buf, copyOffset, grpprl.length);
281           lastGrpprl = grpprl;
282         }
283
284         bxOffset += BX_SIZE;
285         fcOffset += FC_SIZE;
286
287       }
288
289       LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);
290       return buf;
291     }
292
293     /**
294      * Used to get the ParagraphHeight of a PAPX at a particular index.
295      * @param index
296      * @return The ParagraphHeight
297      */

298     private ParagraphHeight getParagraphHeight(int index)
299     {
300       int pheOffset = _offset + 1 + (((_crun + 1) * 4) + (index * 13));
301
302       ParagraphHeight phe = new ParagraphHeight(_fkp, pheOffset);
303
304       return phe;
305     }
306 }
307
Popular Tags