FileDocCategorySizeDatePackage
PAPFormattedDiskPage.javaAPI DocApache Poi 3.0.19798Mon Jan 01 18:55:32 GMT 2007org.apache.poi.hwpf.model

PAPFormattedDiskPage

public class PAPFormattedDiskPage extends FormattedDiskPage
Represents a PAP FKP. The style properties for paragraph and character runs are stored in fkps. There are PAP fkps for paragraph properties and CHP fkps for character run properties. The first part of the fkp for both CHP and PAP fkps consists of an array of 4 byte int offsets in the main stream for that Paragraph's or Character run's text. The ending offset is the next value in the array. For example, if an fkp has X number of Paragraph's stored in it then there are (x + 1) 4 byte ints in the beginning array. The number X is determined by the last byte in a 512 byte fkp. CHP and PAP fkps also store the compressed styles(grpprl) that correspond to the offsets on the front of the fkp. The offset of the grpprls is determined differently for CHP fkps and PAP fkps.
author
Ryan Ackley

Fields Summary
private static final int
BX_SIZE
private static final int
FC_SIZE
private ArrayList
_papxList
private ArrayList
_overFlow
private byte[]
_dataStream
Constructors Summary
public PAPFormattedDiskPage(byte[] dataStream)



      
    
      _dataStream = dataStream;
    
public PAPFormattedDiskPage(byte[] documentStream, byte[] dataStream, int offset, int fcMin)
Creates a PAPFormattedDiskPage from a 512 byte array

      super(documentStream, offset);

      for (int x = 0; x < _crun; x++)
      {
        _papxList.add(new PAPX(getStart(x) - fcMin, getEnd(x) - fcMin, getGrpprl(x), getParagraphHeight(x), dataStream));
      }
      _fkp = null;
      _dataStream = dataStream;
    
Methods Summary
public voidfill(java.util.List filler)
Fills the queue for writing.

param
filler a List of PAPXs

      _papxList.addAll(filler);
    
protected byte[]getGrpprl(int index)
Gets the papx for the paragraph at index in this fkp.

param
index The index of the papx to get.
return
a papx grpprl.

        int papxOffset = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + (((_crun + 1) * FC_SIZE) + (index * BX_SIZE)));
        int size = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + papxOffset);
        if(size == 0)
        {
            size = 2 * LittleEndian.getUnsignedByte(_fkp, _offset + ++papxOffset);
        }
        else
        {
            size--;
        }

        byte[] papx = new byte[size];
        System.arraycopy(_fkp, _offset + ++papxOffset, papx, 0, size);
        return papx;
    
java.util.ArrayListgetOverflow()
Used when writing out a Word docunment. This method is part of a sequence that is necessary because there is no easy and efficient way to determine the number PAPX's that will fit into one FKP. THe sequence is as follows: fill() toByteArray() getOverflow()

return
The remaining PAPXs that didn't fit into this FKP.

      return _overFlow;
    
public org.apache.poi.hwpf.model.PAPXgetPAPX(int index)
Gets the PAPX at index.

param
index The index to get the PAPX for.
return
The PAPX at index.

      return (PAPX)_papxList.get(index);
    
private org.apache.poi.hwpf.model.ParagraphHeightgetParagraphHeight(int index)
Used to get the ParagraphHeight of a PAPX at a particular index.

param
index
return
The ParagraphHeight

      int pheOffset = _offset + 1 + (((_crun + 1) * 4) + (index * 13));

      ParagraphHeight phe = new ParagraphHeight(_fkp, pheOffset);

      return phe;
    
protected byte[]toByteArray(int fcMin)
Creates a byte array representation of this data structure. Suitable for writing to a Word document.

param
fcMin The file offset in the main stream where text begins.
return
A byte array representing this data structure.

      byte[] buf = new byte[512];
      int size = _papxList.size();
      int grpprlOffset = 0;
      int bxOffset = 0;
      int fcOffset = 0;
      byte[] lastGrpprl = new byte[0];

      // total size is currently the size of one FC
      int totalSize = FC_SIZE;

      int index = 0;
      for (; index < size; index++)
      {
        byte[] grpprl = ((PAPX)_papxList.get(index)).getGrpprl();
        int grpprlLength = grpprl.length;

        // is grpprl huge?
        if(grpprlLength > 488)
        {
          grpprlLength = 8; // set equal to size of sprmPHugePapx grpprl
        }

        // check to see if we have enough room for an FC, a BX, and the grpprl
        // and the 1 byte size of the grpprl.
        int addition = 0;
        if (!Arrays.equals(grpprl, lastGrpprl))
        {
          addition = (FC_SIZE + BX_SIZE + grpprlLength + 1);
        }
        else
        {
          addition = (FC_SIZE + BX_SIZE);
        }

        totalSize += addition;

        // if size is uneven we will have to add one so the first grpprl falls
        // on a word boundary
        if (totalSize > 511 + (index % 2))
        {
          totalSize -= addition;
          break;
        }

        // grpprls must fall on word boundaries
        if (grpprlLength % 2 > 0)
        {
          totalSize += 1;
        }
        else
        {
          totalSize += 2;
        }
        lastGrpprl = grpprl;
      }

      // see if we couldn't fit some
      if (index != size)
      {
        _overFlow = new ArrayList();
        _overFlow.addAll(_papxList.subList(index, size));
      }

      // index should equal number of papxs that will be in this fkp now.
      buf[511] = (byte)index;

      bxOffset = (FC_SIZE * index) + FC_SIZE;
      grpprlOffset =  511;

      PAPX papx = null;
      lastGrpprl = new byte[0];
      for (int x = 0; x < index; x++)
      {
        papx = (PAPX)_papxList.get(x);
        byte[] phe = papx.getParagraphHeight().toByteArray();
        byte[] grpprl = papx.getGrpprl();

        // is grpprl huge?
        if(grpprl.length > 488)
        {
          // if so do we have storage at getHugeGrpprlOffset()
          int hugeGrpprlOffset = papx.getHugeGrpprlOffset();
          if(hugeGrpprlOffset == -1) // then we have no storage...
          {
            throw new UnsupportedOperationException(
                  "This Paragraph has no dataStream storage.");
          }
          else // we have some storage...
          {
            // get the size of the existing storage
            int maxHugeGrpprlSize = LittleEndian.getUShort(_dataStream,
                hugeGrpprlOffset);

            if (maxHugeGrpprlSize < grpprl.length-2) // grpprl.length-2 because we don't store the istd
              throw new UnsupportedOperationException(
                  "This Paragraph's dataStream storage is too small.");
          }

          // store grpprl at hugeGrpprlOffset
          System.arraycopy(grpprl, 2, _dataStream, hugeGrpprlOffset + 2,
                           grpprl.length - 2); // grpprl.length-2 because we don't store the istd
          LittleEndian.putUShort(_dataStream, hugeGrpprlOffset, grpprl.length - 2);

          // grpprl = grpprl containing only a sprmPHugePapx2
          int istd = LittleEndian.getUShort(grpprl, 0);
          grpprl = new byte[8];
          LittleEndian.putUShort(grpprl, 0, istd);
          LittleEndian.putUShort(grpprl, 2, 0x6646); // sprmPHugePapx2
          LittleEndian.putInt(grpprl, 4, hugeGrpprlOffset);
        }

        boolean same = Arrays.equals(lastGrpprl, grpprl);
        if (!same)
        {
          grpprlOffset -= (grpprl.length + (2 - grpprl.length % 2));
          grpprlOffset -= (grpprlOffset % 2);
        }
        LittleEndian.putInt(buf, fcOffset, papx.getStart() + fcMin);
        buf[bxOffset] = (byte)(grpprlOffset/2);
        System.arraycopy(phe, 0, buf, bxOffset + 1, phe.length);

        // refer to the section on PAPX in the spec. Places a size on the front
        // of the PAPX. Has to do with how the grpprl stays on word
        // boundaries.
        if (!same)
        {
          int copyOffset = grpprlOffset;
          if ( (grpprl.length % 2) > 0)
          {
            buf[copyOffset++] = (byte) ( (grpprl.length + 1) / 2);
          }
          else
          {
            buf[++copyOffset] = (byte) ( (grpprl.length) / 2);
            copyOffset++;
          }
          System.arraycopy(grpprl, 0, buf, copyOffset, grpprl.length);
          lastGrpprl = grpprl;
        }

        bxOffset += BX_SIZE;
        fcOffset += FC_SIZE;

      }

      LittleEndian.putInt(buf, fcOffset, papx.getEnd() + fcMin);
      return buf;