/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache POI" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache POI", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* .
*/
package org.apache.poi.hwpf.model.hdftypes;
//import java.io.UnsupportedEncodingException;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.hwpf.model.hdftypes.definitions.*;
//import org.apache.poi.util.BitField;
/**
* This class acts as a virtual machine that does the decompression of SPRMS related to
* PAPX, CHPX, SEPX, TAPX
*
* @author Ryan Ackley
* @author Praveen Mathew
*/
public class SprmOperationsVm
{
private static final int NIL_STYLE = 4095;
private static final int PAP_TYPE = 1;
private static final int CHP_TYPE = 2;
private static final int SEP_TYPE = 4;
private static final int TAP_TYPE = 5;
private static final byte ITBDMAX = 64;
public SprmOperationsVm()
{
}
/**
* Used to uncompress a property stored in a grpprl. These include
* CharacterProperties, ParagraphProperties, TableProperties, and
* SectionProperties.
*
* @param grpprl The compressed form of the property.
* @param parent The base property of the property.
* @param styleSheet The document's stylesheet.
*
* @return An object that should be casted to the appropriate property.
*/
public static Object unCompressProperty(byte[] grpprl, Object parent, StyleSheet styleSheet)
{
return unCompressProperty(grpprl, parent, styleSheet, true);
}
/**
* Used to uncompress a property stored in a grpprl. These include
* CharacterProperties, ParagraphProperties, TableProperties, and
* SectionProperties.
*
* @param grpprl The compressed form of the property.
* @param parent The base property of the property.
* @param styleSheet The document's stylesheet.
*
* @return An object that should be casted to the appropriate property.
*/
static Object unCompressProperty(byte[] grpprl, Object parent, StyleSheet styleSheet, boolean doIstd)
{
Object newProperty = null;
int offset = 0;
int propertyType = PAP_TYPE;
if(parent instanceof ParagraphProperties)
{
try
{
newProperty = ((ParagraphProperties)parent).clone();
}
catch(Exception e){}
if(doIstd)
{
((ParagraphProperties)newProperty).setIstd(LittleEndian.getShort(grpprl, 0));
offset = 2;
}
}
else if(parent instanceof CharacterProperties)
{
try
{
newProperty = ((CharacterProperties)parent).clone();
((CharacterProperties)newProperty).setBaseIstd(((CharacterProperties)parent).getIstd());
}
catch(Exception e){}
propertyType = CHP_TYPE;
}
else if(parent instanceof SectionProperties)
{
newProperty = parent;
propertyType = SEP_TYPE;
}
else if(parent instanceof TableProperties)
{
newProperty = parent;
propertyType = TAP_TYPE;
offset = 2;//because this is really just a papx
}
else
{
return null;
}
while(offset < grpprl.length)
{
short sprm = LittleEndian.getShort(grpprl, offset);
offset += 2;
byte spra = (byte)((sprm & 0xe000) >> 13);
int opSize = 0;
int param = 0;
byte[] varParam = null;
switch(spra)
{
case 0:
case 1:
opSize = 1;
param = grpprl[offset];
break;
case 2:
opSize = 2;
param = LittleEndian.getShort(grpprl, offset);
break;
case 3:
opSize = 4;
param = LittleEndian.getInt(grpprl, offset);
break;
case 4:
case 5:
opSize = 2;
param = LittleEndian.getShort(grpprl, offset);
break;
case 6://variable size
//there is one sprm that is a very special case
if(sprm != (short)0xd608)
{
opSize = LittleEndian.getUnsignedByte(grpprl, offset);
offset++;
}
else
{
opSize = LittleEndian.getShort(grpprl, offset) - 1;
offset += 2;
}
varParam = new byte[opSize];
System.arraycopy(grpprl, offset, varParam, 0, opSize);
break;
case 7:
opSize = 3;
byte threeByteInt[] = new byte[4];
threeByteInt[0] = grpprl[offset];
threeByteInt[1] = grpprl[offset + 1];
threeByteInt[2] = grpprl[offset + 2];
threeByteInt[3] = (byte)0;
param = LittleEndian.getInt(threeByteInt, 0);
break;
default:
throw new RuntimeException("unrecognized pap opcode");
}
offset += opSize;
short operand = (short)(sprm & 0x1ff);
byte type = (byte)((sprm & 0x1c00) >> 10);
switch(propertyType)
{
case PAP_TYPE:
if(type == 1)//papx stores TAP sprms along with PAP sprms
{
unCompressPAPOperation((ParagraphProperties)newProperty, operand,
param, varParam, spra,opSize);
}
break;
case CHP_TYPE:
unCompressCHPOperation((CharacterProperties)parent,
(CharacterProperties)newProperty,
operand, param, varParam,
styleSheet,opSize);
break;
case SEP_TYPE:
unCompressSEPOperation((SectionProperties)newProperty, operand, param, varParam,opSize);
break;
case TAP_TYPE:
if(type == 5)
{
unCompressTAPOperation((TableProperties)newProperty, operand, param, varParam,opSize);
}
break;
}
}
return newProperty;
}
/**
* Used in decompression of a chpx. This performs an operation defined by
* a single sprm.
*
* @param oldCHP The base CharacterProperties.
* @param newCHP The current CharacterProperties.
* @param operand The operand defined by the sprm (See Word file format spec)
* @param param The parameter defined by the sprm (See Word file format spec)
* @param varParam The variable length parameter defined by the sprm. (See
* Word file format spec)
* @param grpprl The entire chpx that this operation is a part of.
* @param offset The offset in the grpprl of the next sprm
* @param styleSheet The StyleSheet for this document.
*/
static void unCompressCHPOperation(CharacterProperties oldCHP, CharacterProperties newCHP,
int operand, int param,
byte[] varParam,
StyleSheet styleSheet,int opSize)
{
switch(operand)
{
case 0:
newCHP.setFRMarkDel(getFlag(param));
break;
case 0x1:
newCHP.setFRMark(getFlag(param));
break;
case 0x2:
newCHP.setFFldVanish(getFlag(param));
break;
case 0x3:
newCHP.setFcPic(param);
newCHP.setFSpec(true);
break;
case 0x4:
newCHP.setIbstRMark((short)param);
break;
case 0x5:
short[] dttmRMark = new short[2];
//dttmRMark[0] = LittleEndian.getShort(grpprl, (offset - 4));
//dttmRMark[1] = LittleEndian.getShort(grpprl, (offset - 2));
dttmRMark[0] = (short)(param & 0x0000ffff);
dttmRMark[1] = (short)((param >> 16) & 0x0000ffff);
newCHP.setDttmRMark(dttmRMark);
break;
case 0x6:
newCHP.setFData(getFlag(param));
break;
case 0x7:
//don't care about this
break;
case 0x8:
//short chsDiff = (short)((param & 0xff0000) >>> 16);
short chsDiff = (short)(param & 0x0000ff);
newCHP.setFChsDiff(getFlag(chsDiff));
newCHP.setChse((short)(param & 0xffff));
break;
case 0x9:
newCHP.setFSpec(true);
newCHP.setFtcSym((short)LittleEndian.getShort(varParam, 0));
newCHP.setXchSym((short)LittleEndian.getShort(varParam, 2));
break;
case 0xa:
newCHP.setFOle2(getFlag(param));
break;
case 0xb:
// Obsolete
break;
case 0xc:
newCHP.setIcoHighlight((byte)param);
newCHP.setFHighlight(getFlag(param));
break;
case 0xd:
// undocumented
break;
case 0xe:
newCHP.setFcObj(param);
break;
case 0xf:
// undocumented
break;
case 0x10:
// undocumented
break;
// undocumented till 0x30
case 0x11:
break;
case 0x12:
break;
case 0x13:
break;
case 0x14:
break;
case 0x15:
break;
case 0x16:
break;
case 0x17:
break;
case 0x18:
break;
case 0x19:
break;
case 0x1a:
break;
case 0x1b:
break;
case 0x1c:
break;
case 0x1d:
break;
case 0x1e:
break;
case 0x1f:
break;
case 0x20:
break;
case 0x21:
break;
case 0x22:
break;
case 0x23:
break;
case 0x24:
break;
case 0x25:
break;
case 0x26:
break;
case 0x27:
break;
case 0x28:
break;
case 0x29:
break;
case 0x2a:
break;
case 0x2b:
break;
case 0x2c:
break;
case 0x2d:
break;
case 0x2e:
break;
case 0x2f:
break;
case 0x30:
newCHP.setIstd(param);
break;
case 0x31:
//permutation vector for fast saves, who cares!
break;
case 0x32:
newCHP.setFBold(false);
newCHP.setFItalic(false);
newCHP.setFOutline(false);
newCHP.setFStrike(false);
newCHP.setFShadow(false);
newCHP.setFSmallCaps(false);
newCHP.setFCaps(false);
newCHP.setFVanish(false);
newCHP.setKul((byte)0);
newCHP.setIco((byte)0);
break;
case 0x33:
try
{
// preserve the fSpec setting from the original CHP
boolean fSpec = newCHP.isFSpec();
newCHP = (CharacterProperties)oldCHP.clone();
newCHP.setFSpec(fSpec);
}
catch(CloneNotSupportedException e)
{
//do nothing
}
return;
case 0x34:
// undocumented
break;
case 0x35:
newCHP.setFBold(getCHPFlag((byte)param, oldCHP.isFBold()));
break;
case 0x36:
newCHP.setFItalic(getCHPFlag((byte)param, oldCHP.isFItalic()));
break;
case 0x37:
newCHP.setFStrike(getCHPFlag((byte)param, oldCHP.isFStrike()));
break;
case 0x38:
newCHP.setFOutline(getCHPFlag((byte)param, oldCHP.isFOutline()));
break;
case 0x39:
newCHP.setFShadow(getCHPFlag((byte)param, oldCHP.isFShadow()));
break;
case 0x3a:
newCHP.setFSmallCaps(getCHPFlag((byte)param, oldCHP.isFSmallCaps()));
break;
case 0x3b:
newCHP.setFCaps(getCHPFlag((byte)param, oldCHP.isFCaps()));
break;
case 0x3c:
newCHP.setFVanish(getCHPFlag((byte)param, oldCHP.isFVanish()));
break;
case 0x3d:
newCHP.setFtcAscii((short)param);
break;
case 0x3e:
newCHP.setKul((byte)param);
break;
case 0x3f:
int hps = param & 0xff;
if(hps != 0)
{
newCHP.setHps(hps);
}
//byte cInc = (byte)(((byte)(param & 0xfe00) >>> 4) >> 1);
byte cInc = (byte)((param & 0xff00) >>> 8);
cInc = (byte)(cInc >>> 1);
if(cInc != 0)
{
newCHP.setHps(Math.max(newCHP.getHps() + (cInc * 2), 2));
}
//byte hpsPos = (byte)((param & 0xff0000) >>> 8);
byte hpsPos = (byte)((param & 0xff0000) >>> 16);
if(hpsPos != 0x80)
{
newCHP.setHpsPos(hpsPos);
}
boolean fAdjust = (param & 0x0100) > 0;
if(fAdjust && hpsPos != 128 && hpsPos != 0 && oldCHP.getHpsPos() == 0)
{
newCHP.setHps(Math.max(newCHP.getHps() + (-2), 2));
}
if(fAdjust && hpsPos == 0 && oldCHP.getHpsPos() != 0)
{
newCHP.setHps(Math.max(newCHP.getHps() + 2, 2));
}
break;
case 0x40:
newCHP.setDxaSpace(param);
break;
case 0x41:
newCHP.setLidDefault((short)param);
break;
case 0x42:
newCHP.setIco((byte)param);
break;
case 0x43:
newCHP.setHps(param);
break;
case 0x44:
byte hpsLvl = (byte)param;
newCHP.setHps(Math.max(newCHP.getHps() + (hpsLvl * 2), 2));
break;
case 0x45:
newCHP.setHpsPos((short)param);
break;
case 0x46:
if(param != 0)
{
if(oldCHP.getHpsPos() == 0)
{
newCHP.setHps(Math.max(newCHP.getHps() + (-2), 2));
}
}
else
{
if(oldCHP.getHpsPos() != 0)
{
newCHP.setHps(Math.max(newCHP.getHps() + 2, 2));
}
}
break;
case 0x47:
CharacterProperties genCHP = new CharacterProperties();
genCHP.setFtcAscii(4);
genCHP = (CharacterProperties)unCompressProperty(varParam, genCHP, styleSheet);
CharacterProperties styleCHP = styleSheet.getStyleDescription(oldCHP.getBaseIstd()).getCHP();
if(genCHP.isFBold() == newCHP.isFBold())
{
newCHP.setFBold(styleCHP.isFBold());
}
if(genCHP.isFItalic() == newCHP.isFItalic())
{
newCHP.setFItalic(styleCHP.isFItalic());
}
if(genCHP.isFSmallCaps() == newCHP.isFSmallCaps())
{
newCHP.setFSmallCaps(styleCHP.isFSmallCaps());
}
if(genCHP.isFVanish() == newCHP.isFVanish())
{
newCHP.setFVanish(styleCHP.isFVanish());
}
if(genCHP.isFStrike() == newCHP.isFStrike())
{
newCHP.setFStrike(styleCHP.isFStrike());
}
if(genCHP.isFCaps() == newCHP.isFCaps())
{
newCHP.setFCaps(styleCHP.isFCaps());
}
if(genCHP.getFtcAscii() == newCHP.getFtcAscii())
{
newCHP.setFtcAscii(styleCHP.getFtcAscii());
}
if(genCHP.getFtcFE() == newCHP.getFtcFE())
{
newCHP.setFtcFE(styleCHP.getFtcFE());
}
if(genCHP.getFtcOther() == newCHP.getFtcOther())
{
newCHP.setFtcOther(styleCHP.getFtcOther());
}
if(genCHP.getHps() == newCHP.getHps())
{
newCHP.setHps(styleCHP.getHps());
}
if(genCHP.getHpsPos() == newCHP.getHpsPos())
{
newCHP.setHpsPos(styleCHP.getHpsPos());
}
if(genCHP.getKul() == newCHP.getKul())
{
newCHP.setKul(styleCHP.getKul());
}
if(genCHP.getDxaSpace() == newCHP.getDxaSpace())
{
newCHP.setDxaSpace(styleCHP.getDxaSpace());
}
if(genCHP.getIco() == newCHP.getIco())
{
newCHP.setIco(styleCHP.getIco());
}
if(genCHP.getLidDefault() == newCHP.getLidDefault())
{
newCHP.setLidDefault(styleCHP.getLidDefault());
}
if(genCHP.getLidFE() == newCHP.getLidFE())
{
newCHP.setLidFE(styleCHP.getLidFE());
}
break;
case 0x48:
newCHP.setIss((byte)param);
break;
case 0x49:
newCHP.setHps(LittleEndian.getShort(varParam, 0));
break;
case 0x4a:
int increment = LittleEndian.getShort(varParam, 0);
newCHP.setHps(Math.max(newCHP.getHps() + increment, 8));
break;
case 0x4b:
newCHP.setHpsKern(param);
break;
case 0x4c:
unCompressCHPOperation(oldCHP, newCHP, 0x47, param, varParam, styleSheet,opSize);
break;
case 0x4d:
float percentage = (float)param/100.0f;
int add = (int)((float)percentage * (float)newCHP.getHps());
newCHP.setHps(newCHP.getHps() + add);
break;
case 0x4e:
newCHP.setYsr((byte)param);
break;
case 0x4f:
newCHP.setFtcAscii((short)param);
break;
case 0x50:
newCHP.setFtcFE((short)param);
break;
case 0x51:
newCHP.setFtcOther((short)param);
break;
case 0x52:
// undocumented
break;
case 0x53:
newCHP.setFDStrike(getFlag(param));
break;
case 0x54:
newCHP.setFImprint(getFlag(param));
break;
case 0x55:
newCHP.setFSpec(getFlag(param));
break;
case 0x56:
newCHP.setFObj(getFlag(param));
break;
case 0x57:
newCHP.setFPropMark(varParam[0]);
newCHP.setIbstPropRMark((short)LittleEndian.getShort(varParam, 1));
newCHP.setDttmPropRMark(LittleEndian.getInt(varParam, 3));
break;
case 0x58:
newCHP.setFEmboss(getFlag(param));
break;
case 0x59:
newCHP.setSfxtText((byte)param);
break;
// undocumented till 0x61
case 0x5a:
break;
case 0x5b:
break;
case 0x5c:
break;
case 0x5d:
break;
case 0x5e:
break;
case 0x5f:
break;
case 0x60:
break;
case 0x61:
break;
case 0x62:
byte[] xstDispFldRMark = new byte[32];
newCHP.setFDispFldRMark(varParam[0]);
newCHP.setIbstDispFldRMark((short)LittleEndian.getShort(varParam, 1));
newCHP.setDttmDispFldRMark(LittleEndian.getInt(varParam, 3));
System.arraycopy(varParam, 7, xstDispFldRMark, 0, 32);
newCHP.setXstDispFldRMark(xstDispFldRMark);
break;
case 0x63:
newCHP.setIbstRMarkDel((short)param);
break;
case 0x64:
short[] dttmRMarkDel = new short[2];
//dttmRMarkDel[0] = LittleEndian.getShort(grpprl, offset - 4);
//dttmRMarkDel[1] = LittleEndian.getShort(grpprl, offset - 2);
dttmRMarkDel[0] = (short)(param & 0x0000ffff);
dttmRMarkDel[1] = (short)((param >> 16) & 0x0000ffff);
newCHP.setDttmRMarkDel(dttmRMarkDel);
break;
case 0x65:
short[] brc = new short[2];
//brc[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brc[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brc[0] = (short)(param & 0x0000ffff);
brc[1] = (short)((param >> 16) & 0x0000ffff);
newCHP.setBrc(brc);
break;
case 0x66:
newCHP.setShd((short)param);
break;
case 0x67:
// Obsolete
break;
case 0x68:
break;
// undocumented till 0x6c
case 0x69:
break;
case 0x6a:
break;
case 0x6b:
break;
case 0x6c:
break;
case 0x6d:
newCHP.setLidDefault((short)param);
break;
case 0x6e:
newCHP.setLidFE((short)param);
break;
case 0x6f:
newCHP.setIdctHint((byte)param);
break;
}
}
/**
* Performs an operation on a ParagraphProperties object. Used to uncompress
* from a papx.
*
* @param newPAP The ParagraphProperties object to perform the operation on.
* @param operand The operand that defines the operation.
* @param param The operation's parameter.
* @param varParam The operation's variable length parameter.
* @param grpprl The original papx.
* @param offset The current offset in the papx.
* @param spra A part of the sprm that defined this operation.
*/
static void unCompressPAPOperation(ParagraphProperties newPAP, int operand, int param,
byte[] varParam,
int spra,int opSize)
{
switch(operand)
{
case 0:
newPAP.setIstd(param);
break;
case 0x1:
// Used only for piece table grpprl's not for PAPX
int istdFirst = LittleEndian.getShort(varParam, 2);
int istdLast = LittleEndian.getShort(varParam, 4);
if((newPAP.getIstd() > istdFirst) || (newPAP.getIstd() <= istdLast))
{
permuteIstd(newPAP, varParam,opSize);
}
break;
case 0x2:
if(newPAP.getIstd() <=9 || newPAP.getIstd() >=1)
{
byte paramTmp = (byte)param;
newPAP.setIstd(newPAP.getIstd() + paramTmp);
newPAP.setLvl((byte)(newPAP.getLvl() + paramTmp));
if(((paramTmp >> 7) & 0x01) == 1)
{
newPAP.setIstd(Math.max(newPAP.getIstd(), 1));
}
else
{
newPAP.setIstd(Math.min(newPAP.getIstd(), 9));
}
}
break;
case 0x3:
newPAP.setJc((byte)param);
break;
case 0x4:
newPAP.setFSideBySide((byte)param);
break;
case 0x5:
newPAP.setFKeep((byte)param);
break;
case 0x6:
newPAP.setFKeepFollow((byte)param);
break;
case 0x7:
newPAP.setFPageBreakBefore((byte)param);
break;
case 0x8:
newPAP.setBrcl((byte)param);
break;
case 0x9:
newPAP.setBrcp((byte)param);
break;
case 0xa:
newPAP.setIlvl((byte)param);
break;
case 0xb:
newPAP.setIlfo(param);
break;
case 0xc:
newPAP.setFNoLnn((byte)param);
break;
case 0xd:
/**handle tabs . variable parameter. seperate processing needed*/
applySprmPChgTabsPapx(newPAP, varParam,opSize);
break;
case 0xe:
newPAP.setDxaRight(param);
break;
case 0xf:
newPAP.setDxaLeft(param);
break;
case 0x10:
// sprmPNest is only stored in grpprls linked to a piece table.
newPAP.setDxaLeft(newPAP.getDxaLeft() + param);
newPAP.setDxaLeft(Math.max(0, newPAP.getDxaLeft()));
break;
case 0x11:
newPAP.setDxaLeft1(param);
break;
case 0x12:
short[] lspd = newPAP.getLspd();
//lspd[0] = LittleEndian.getShort(grpprl, offset - 4);
//lspd[1] = LittleEndian.getShort(grpprl, offset - 2);
lspd[0] = (short)(param & 0x0000ffff);
lspd[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setLspd(lspd);
break;
case 0x13:
newPAP.setDyaBefore(param);
break;
case 0x14:
newPAP.setDyaAfter(param);
break;
case 0x15:
/**handle tabs for grpprls. variable parameter. seperate processing needed*/
applySprmPChgTabs(newPAP, varParam,opSize);
break;
case 0x16:
newPAP.setFInTable((byte)param);
break;
case 0x17:
newPAP.setFTtp((byte)param);
break;
case 0x18:
newPAP.setDxaAbs(param);
break;
case 0x19:
newPAP.setDyaAbs(param);
break;
case 0x1a:
newPAP.setDxaWidth(param);
break;
case 0x1b:
/** @todo handle paragraph postioning*/
byte pcVert = (byte)((param & 0x0c) >> 2);
byte pcHorz = (byte)(param & 0x03);
if(pcVert != 3)
{
newPAP.setPcVert(pcVert);
}
if(pcHorz != 3)
{
newPAP.setPcHorz(pcHorz);
}
break;
// BrcXXX1 is older Version. Brc is used
case 0x1c:
//newPAP.setBrcTop1((short)param);
break;
case 0x1d:
//newPAP.setBrcLeft1((short)param);
break;
case 0x1e:
//newPAP.setBrcBottom1((short)param);
break;
case 0x1f:
//newPAP.setBrcRight1((short)param);
break;
case 0x20:
//newPAP.setBrcBetween1((short)param);
break;
case 0x21:
//newPAP.setBrcBar1((byte)param);
break;
case 0x22:
newPAP.setDxaFromText(param);
break;
case 0x23:
newPAP.setWr((byte)param);
break;
case 0x24:
short[] brcTop = newPAP.getBrcTop();
//brcTop[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brcTop[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brcTop[0] = (short)(param & 0x0000ffff);
brcTop[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setBrcTop(brcTop);
break;
case 0x25:
short[] brcLeft = newPAP.getBrcLeft();
//brcLeft[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brcLeft[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brcLeft[0] = (short)(param & 0x0000ffff);
brcLeft[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setBrcLeft(brcLeft);
break;
case 0x26:
short[] brcBottom = newPAP.getBrcBottom();
//brcBottom[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brcBottom[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brcBottom[0] = (short)(param & 0x0000ffff);
brcBottom[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setBrcBottom(brcBottom);
break;
case 0x27:
short[] brcRight = newPAP.getBrcRight();
//brcRight[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brcRight[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brcRight[0] = (short)(param & 0x0000ffff);
brcRight[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setBrcRight(brcRight);
break;
case 0x28:
short[] brcBetween = newPAP.getBrcBetween();
//brcBetween[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brcBetween[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brcBetween[0] = (short)(param & 0x0000ffff);
brcBetween[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setBrcBetween(brcBetween);
break;
case 0x29:
short[] brcBar = newPAP.getBrcBar();
//brcBar[0] = (short)LittleEndian.getShort(grpprl, offset - 4);
//brcBar[1] = (short)LittleEndian.getShort(grpprl, offset - 2);
brcBar[0] = (short)(param & 0x0000ffff);
brcBar[1] = (short)((param >> 16) & 0x0000ffff);
newPAP.setBrcBar(brcBar);
break;
case 0x2a:
newPAP.setFNoAutoHyph((byte)param);
break;
case 0x2b:
newPAP.setDyaHeight(param);
break;
case 0x2c:
newPAP.setDcs((short)param);
break;
case 0x2d:
newPAP.setShd((short)param);
break;
case 0x2e:
newPAP.setDyaFromText(param);
break;
case 0x2f:
newPAP.setDxaFromText(param);
break;
case 0x30:
newPAP.setFLocked((byte)param);
break;
case 0x31:
newPAP.setFWidowControl((byte)param);
break;
case 0x32:
//undocumented
break;
case 0x33:
newPAP.setFKinsoku((byte)param);
break;
case 0x34:
newPAP.setFWordWrap((byte)param);
break;
case 0x35:
newPAP.setFOverflowPunct((byte)param);
break;
case 0x36:
newPAP.setFTopLinePunct((byte)param);
break;
case 0x37:
newPAP.setFAutoSpaceDE((byte)param);
break;
case 0x38:
newPAP.setFAutoSpaceDN((byte)param);
break;
case 0x39:
newPAP.setWAlignFont(param);
break;
case 0x3a:
newPAP.setFontAlign((short)param);
break;
case 0x3b:
//obsolete
break;
case 0x3e:
newPAP.setAnld(varParam);
break;
case 0x3f:
//don't really need this. spec is confusing regarding this
//sprm
try
{
newPAP.setFPropRMark((int)varParam[0]);
newPAP.setIbstPropRMark((int)LittleEndian.getShort(varParam,1));
newPAP.setDttmPropRMark(LittleEndian.getByteArray(varParam,3,4));
}
catch(Exception e)
{
e.printStackTrace();
}
break;
case 0x40:
//newPAP._lvl = param;
if(newPAP.getIstd() >= 1 && newPAP.getIstd() <= 9)
{
newPAP.setIlvl((byte)param);
}
break;
case 0x41:
// undocumented
break;
case 0x43:
//pap.fNumRMIns
newPAP.setFNumRMIns((byte)param);
break;
case 0x44:
//undocumented
break;
case 0x45:
if(spra == 6)
{
newPAP.setNumrm(varParam);
}
else
{
/**@todo handle large PAPX from data stream*/
}
break;
case 0x47:
newPAP.setFUsePgsuSettings((byte)param);
break;
case 0x48:
newPAP.setFAdjustRight((byte)param);
break;
default:
break;
}
}
static void permuteIstd(ParagraphProperties newPAP,byte [] varParam,int opSize)
{
int fLongg = 0,fSpare = 0;
int offset = 0, i = 0;
fLongg = LittleEndian.getUnsignedByte(varParam, offset);
offset = offset + LittleEndian.BYTE_SIZE;
fSpare = LittleEndian.getUnsignedByte(varParam, offset);
offset = offset + LittleEndian.BYTE_SIZE;
int istdFirst = 0,istdLast = 0;
istdFirst = LittleEndian.getShort(varParam, offset);
offset = offset + LittleEndian.SHORT_SIZE;
istdLast = LittleEndian.getShort(varParam, offset);
offset = offset + LittleEndian.SHORT_SIZE;
short rgistdLength = (short)(opSize - (1+1+2+2));
int [] rgistd = new int[rgistdLength];
for(i=0;i < rgistdLength;i++)
{
rgistd[i] = (int)LittleEndian.getShort(varParam, offset);
offset = offset + LittleEndian.SHORT_SIZE;
}
int istd = rgistd[newPAP.getIstd() - istdFirst];
newPAP.setIstd(istd);
}
static void applySprmPChgTabsPapx(ParagraphProperties newPAP,byte [] varParam, int opSize)
{
int i = 0,j = 0;
int offset = 0;
int itbdDelMax = LittleEndian.getUnsignedByte(varParam, offset);
offset = offset + LittleEndian.BYTE_SIZE;
short [] rgdxaDel = new short[itbdDelMax];
for(i=0;i (ITBDMAX - 1)) break;
if(arr2Index >= itbdAddMax)rgdxaTabMerged[index++] = rgdxaTabNew[arr1Index];
else
{
if(rgdxaTabNew[arr1Index] < rgdxaAdd[arr2Index])
{
rgdxaTabMerged[index++] = rgdxaTabNew[arr1Index];
}
else
{
if(rgdxaTabNew[arr1Index] != rgdxaAdd[arr2Index]) arr1Index = arr1Index - 1;
rgdxaTabMerged[index++] = rgdxaAdd[arr2Index++];
}
}
}
while(arr2Index < itbdAddMax)
{
if(index > (ITBDMAX - 1)) break;
rgdxaTabMerged[index++] = rgdxaAdd[arr2Index++];
}
itbdMac = index; // spec specifies is clear only about pap.rgdxaTab
// so itbdMac is calculated based on rgdxaTabMerged
byte [] rgtbdMerged = new byte[ITBDMAX];
arr1Index = 0;
arr2Index = 0;
index = 0;
for(arr1Index = 0 ;arr1Index < itbdMacForRgtbd ;arr1Index++)
{
if(index > (ITBDMAX - 1)) break;
if(arr2Index >= itbdAddMax)rgtbdMerged[index++] = rgtbdNew[arr1Index];
else
{
if(rgtbdNew[arr1Index] < rgtbdAdd[arr2Index])
{
rgtbdMerged[index++] = rgtbdNew[arr1Index];
}
else
{
if(rgtbdNew[arr1Index] != rgtbdAdd[arr2Index]) arr1Index = arr1Index - 1;
rgtbdMerged[index++] = rgtbdAdd[arr2Index++];
}
}
}
while(arr2Index < itbdAddMax)
{
if(index > (ITBDMAX - 1)) break;
rgtbdMerged[index++] = rgtbdAdd[arr2Index++];
}
newPAP.setRgdxaTab(rgdxaTabMerged);
newPAP.setRgtbd(rgtbdMerged);
newPAP.setItbdMac(itbdMac);
}
static void applySprmPChgTabs(ParagraphProperties newPAP,byte [] varParam,int opSize)
{
int i = 0,j = 0;
int offset = 0;
int itbdDelMax = LittleEndian.getUnsignedByte(varParam, offset);
offset = offset + LittleEndian.BYTE_SIZE;
short [] rgdxaDel = new short[itbdDelMax];
for(i=0;i= itbdDelMax)
{
rgdxaTabNew[index] = rgdxaTab[i];
rgtbdNew[index++]= rgtbd[i];
}
else
{
if(rgdxaTab[i] >= (rgdxaDel[i]-rgdxaClose[i]) && rgdxaTab[i] <= (rgdxaDel[i]+rgdxaClose[i]))
{
//addFlag = false;
}
else
{
rgdxaTabNew[index] = rgdxaTab[i];
rgtbdNew[index++]= rgtbd[i];
}
}
}
itbdMac = index;
int itbdMacForRgtbd = itbdMac; // for future use
index = 0;
short [] rgdxaTabMerged = new short[ITBDMAX];
int arr1Index = 0, arr2Index = 0;
for(arr1Index = 0 ;arr1Index < itbdMac ;arr1Index++)
{
if(index > (ITBDMAX - 1)) break;
if(arr2Index >= itbdAddMax)rgdxaTabMerged[index++] = rgdxaTabNew[arr1Index];
else
{
if(rgdxaTabNew[arr1Index] < rgdxaAdd[arr2Index])
{
rgdxaTabMerged[index++] = rgdxaTabNew[arr1Index];
}
else
{
if(rgdxaTabNew[arr1Index] != rgdxaAdd[arr2Index]) arr1Index = arr1Index - 1;
rgdxaTabMerged[index++] = rgdxaAdd[arr2Index++];
}
}
}
while(arr2Index < itbdAddMax)
{
if(index > (ITBDMAX - 1)) break;
rgdxaTabMerged[index++] = rgdxaAdd[arr2Index++];
}
itbdMac = index; // spec specifies is clear only about pap.rgdxaTab
// so itbdMac is calculated based on rgdxaTabMerged
byte [] rgtbdMerged = new byte[ITBDMAX];
arr1Index = 0;
arr2Index = 0;
index = 0;
for(arr1Index = 0 ;arr1Index < itbdMacForRgtbd ;arr1Index++)
{
if(index > (ITBDMAX - 1)) break;
if(arr2Index >= itbdAddMax)rgtbdMerged[index++] = rgtbdNew[arr1Index];
else
{
if(rgtbdNew[arr1Index] < rgtbdAdd[arr2Index])
{
rgtbdMerged[index++] = rgtbdNew[arr1Index];
}
else
{
if(rgtbdNew[arr1Index] != rgtbdAdd[arr2Index]) arr1Index = arr1Index - 1;
rgtbdMerged[index++] = rgtbdAdd[arr2Index++];
}
}
}
while(arr2Index < itbdAddMax)
{
if(index > (ITBDMAX - 1)) break;
rgtbdMerged[index++] = rgtbdAdd[arr2Index++];
}
// Setting the pap.rgdxaTab, pap.rgtbd,pap.itbdMac , after they are rebuilt by
// applying rgdxaDel,rgdxaClose and rgdxaAdd fields of the Sprm
newPAP.setRgdxaTab(rgdxaTabMerged);
newPAP.setRgtbd(rgtbdMerged);
newPAP.setItbdMac(itbdMac);
}
/**
* Used to uncompress a table property. Performs an operation defined
* by a sprm stored in a tapx.
*
* @param newTAP The TableProperties object to perform the operation on.
* @param operand The operand that defines this operation.
* @param param The parameter for this operation.
* @param varParam Variable length parameter for this operation.
*/
static void unCompressTAPOperation(TableProperties newTAP, int operand, int param, byte[] varParam,int opSize)
{
switch(operand)
{
case 0:
newTAP.setJc((short)param);
break;
case 0x01:
{
short[] rgdxaCenter = newTAP.getRgdxaCenter();
short itcMac = newTAP.getItcMac();
int adjust = param - (rgdxaCenter[0] + newTAP.getDxaGapHalf());
for(int x = 0; x < itcMac; x++)
{
rgdxaCenter[x] += adjust;
}
break;
}
case 0x02:
{
short[] rgdxaCenter = newTAP.getRgdxaCenter();
if(rgdxaCenter != null)
{
int adjust = newTAP.getDxaGapHalf() - param;
rgdxaCenter[0] += adjust;
}
newTAP.setDxaGapHalf(param);
break;
}
case 0x03:
newTAP.setFCantSplit(getFlag(param));
break;
case 0x04:
newTAP.setFTableHeader(getFlag(param));
break;
case 0x05:
{
short[] brcTop = newTAP.getBrcTop();
short[] brcLeft = newTAP.getBrcLeft();
short[] brcBottom = newTAP.getBrcBottom();
short[] brcRight = newTAP.getBrcRight();
short[] brcVertical = newTAP.getBrcVertical();
short[] brcHorizontal = newTAP.getBrcHorizontal();
brcTop[0] = LittleEndian.getShort(varParam, 0);
brcTop[1] = LittleEndian.getShort(varParam, 2);
brcLeft[0] = LittleEndian.getShort(varParam, 4);
brcLeft[1] = LittleEndian.getShort(varParam, 6);
brcBottom[0] = LittleEndian.getShort(varParam, 8);
brcBottom[1] = LittleEndian.getShort(varParam, 10);
brcRight[0] = LittleEndian.getShort(varParam, 12);
brcRight[1] = LittleEndian.getShort(varParam, 14);
brcHorizontal[0] = LittleEndian.getShort(varParam, 16);
brcHorizontal[1] = LittleEndian.getShort(varParam, 18);
brcVertical[0] = LittleEndian.getShort(varParam, 20);
brcVertical[1] = LittleEndian.getShort(varParam, 22);
break;
}
case 0x06:
//obsolete, used in word 1.x
break;
case 0x07:
newTAP.setDyaRowHeight(param);
break;
case 0x08:
{
short[] rgdxaCenter = new short[varParam[0] + 1];
TableCellDescriptor[] rgtc = new TableCellDescriptor[varParam[0]];
short itcMac = varParam[0];
//I use varParam[0] and newTAP._itcMac interchangably
newTAP.setItcMac(itcMac);
newTAP.setRgdxaCenter(rgdxaCenter) ;
newTAP.setRgtc(rgtc);
for(int x = 0; x < itcMac; x++)
{
rgdxaCenter[x] = LittleEndian.getShort(varParam , 1 + (x * 2));
rgtc[x] = TableCellDescriptor.convertBytesToTC(varParam, 1 + ((itcMac + 1) * 2) + (x * 20));
}
rgdxaCenter[itcMac] = LittleEndian.getShort(varParam , 1 + (itcMac * 2));
break;
}
case 0x09:
/** @todo handle cell shading*/
break;
case 0x0a:
/** @todo handle word defined table styles*/
break;
case 0x20:
{
TCAbstractType[] rgtc = newTAP.getRgtc();
for(int x = varParam[0]; x < varParam[1]; x++)
{
if((varParam[2] & 0x08) > 0)
{
short[] brcRight = rgtc[x].getBrcRight();
brcRight[0] = LittleEndian.getShort(varParam, 6);
brcRight[1] = LittleEndian.getShort(varParam, 8);
}
else if((varParam[2] & 0x04) > 0)
{
short[] brcBottom = rgtc[x].getBrcBottom();
brcBottom[0] = LittleEndian.getShort(varParam, 6);
brcBottom[1] = LittleEndian.getShort(varParam, 8);
}
else if((varParam[2] & 0x02) > 0)
{
short[] brcLeft = rgtc[x].getBrcLeft();
brcLeft[0] = LittleEndian.getShort(varParam, 6);
brcLeft[1] = LittleEndian.getShort(varParam, 8);
}
else if((varParam[2] & 0x01) > 0)
{
short[] brcTop = rgtc[x].getBrcTop();
brcTop[0] = LittleEndian.getShort(varParam, 6);
brcTop[1] = LittleEndian.getShort(varParam, 8);
}
}
break;
}
case 0x21:
int index = (param & 0xff000000) >> 24;
int count = (param & 0x00ff0000) >> 16;
int width = (param & 0x0000ffff);
int itcMac = newTAP.getItcMac();
short[] rgdxaCenter = new short[itcMac + count + 1];
TableCellDescriptor[] rgtc = new TableCellDescriptor[itcMac + count];
if(index >= itcMac)
{
index = itcMac;
System.arraycopy(newTAP.getRgdxaCenter(), 0, rgdxaCenter, 0, itcMac + 1);
System.arraycopy(newTAP.getRgtc(), 0, rgtc, 0, itcMac);
}
else
{
//copy rgdxaCenter
System.arraycopy(newTAP.getRgdxaCenter(), 0, rgdxaCenter, 0, index + 1);
System.arraycopy(newTAP.getRgdxaCenter(), index + 1, rgdxaCenter, index + count, itcMac - (index));
//copy rgtc
System.arraycopy(newTAP.getRgtc(), 0, rgtc, 0, index);
System.arraycopy(newTAP.getRgtc(), index, rgtc, index + count, itcMac - index);
}
for(int x = index; x < index + count; x++)
{
rgtc[x] = new TableCellDescriptor();
rgdxaCenter[x] = (short)(rgdxaCenter[x-1] + width);
}
rgdxaCenter[index + count] = (short)(rgdxaCenter[(index + count)-1] + width);
break;
/**@todo handle table sprms from complex files*/
case 0x22:
case 0x23:
case 0x24:
case 0x25:
case 0x26:
case 0x27:
case 0x28:
case 0x29:
case 0x2a:
case 0x2b:
case 0x2c:
break;
default:
break;
}
}
/**
* Used in decompression of a sepx. This performs an operation defined by
* a single sprm.
*
* @param newSEP The SectionProperty to perfrom the operation on.
* @param operand The operation to perform.
* @param param The operation's parameter.
* @param varParam The operation variable length parameter.
*/
static void unCompressSEPOperation(SectionProperties newSEP, int operand, int param, byte[] varParam,int opSize)
{
switch(operand)
{
case 0:
newSEP.setCnsPgn((byte)param);
break;
case 0x1:
newSEP.setIHeadingPgn((byte)param);
break;
case 0x2:
newSEP.setOlstAnm(varParam);
break;
case 0x3:
//not quite sure
break;
case 0x4:
//not quite sure
break;
case 0x5:
newSEP.setFEvenlySpaced(getFlag(param));
break;
case 0x6:
newSEP.setFUnlocked(getFlag(param));
break;
case 0x7:
newSEP.setDmBinFirst((short)param);
break;
case 0x8:
newSEP.setDmBinOther((short)param);
break;
case 0x9:
newSEP.setBkc((byte)param);
break;
case 0xa:
newSEP.setFTitlePage(getFlag(param));
break;
case 0xb:
newSEP.setCcolM1((short)param);
break;
case 0xc:
newSEP.setDxaColumns(param);
break;
case 0xd:
newSEP.setFAutoPgn(getFlag(param));
break;
case 0xe:
newSEP.setNfcPgn((byte)param);
break;
case 0xf:
newSEP.setDyaPgn((short)param);
break;
case 0x10:
newSEP.setDxaPgn((short)param);
break;
case 0x11:
newSEP.setFPgnRestart(getFlag(param));
break;
case 0x12:
newSEP.setFEndNote(getFlag(param));
break;
case 0x13:
newSEP.setLnc((byte)param);
break;
case 0x14:
newSEP.setGrpfIhdt((byte)param);
break;
case 0x15:
newSEP.setNLnnMod((short)param);
break;
case 0x16:
newSEP.setDxaLnn(param);
break;
case 0x17:
newSEP.setDyaHdrTop(param);
break;
case 0x18:
newSEP.setDyaHdrBottom(param);
break;
case 0x19:
newSEP.setFLBetween(getFlag(param));
break;
case 0x1a:
newSEP.setVjc((byte)param);
break;
case 0x1b:
newSEP.setLnnMin((short)param);
break;
case 0x1c:
newSEP.setPgnStart((short)param);
break;
case 0x1d:
newSEP.setDmOrientPage((byte)param);
break;
case 0x1e:
//nothing
break;
case 0x1f:
newSEP.setXaPage(param);
break;
case 0x20:
newSEP.setYaPage(param);
break;
case 0x21:
newSEP.setDxaLeft(param);
break;
case 0x22:
newSEP.setDxaRight(param);
break;
case 0x23:
newSEP.setDyaTop(param);
break;
case 0x24:
newSEP.setDyaBottom(param);
break;
case 0x25:
newSEP.setDzaGutter(param);
break;
case 0x26:
newSEP.setDmPaperReq((short)param);
break;
case 0x27:
newSEP.setFPropMark(getFlag(varParam[0]));
break;
case 0x28:
break;
case 0x29:
break;
case 0x2a:
break;
case 0x2b:
short[] brcTop = newSEP.getBrcTop();
brcTop[0] = (short)(param & 0xffff);
brcTop[1] = (short)((param & 0xffff0000) >> 16);
break;
case 0x2c:
short[] brcLeft = newSEP.getBrcLeft();
brcLeft[0] = (short)(param & 0xffff);
brcLeft[1] = (short)((param & 0xffff0000) >> 16);
break;
case 0x2d:
short[] brcBottom = newSEP.getBrcBottom();
brcBottom[0] = (short)(param & 0xffff);
brcBottom[1] = (short)((param & 0xffff0000) >> 16);
break;
case 0x2e:
short[] brcRight = newSEP.getBrcRight();
brcRight[0] = (short)(param & 0xffff);
brcRight[1] = (short)((param & 0xffff0000) >> 16);
break;
case 0x2f:
newSEP.setPgbProp(param);
break;
case 0x30:
newSEP.setDxtCharSpace(param);
break;
case 0x31:
newSEP.setDyaLinePitch(param);
break;
case 0x33:
newSEP.setWTextFlow((short)param);
break;
default:
break;
}
}
/**
* Converts an byte value into a boolean. The byte parameter can be 1,0, 128,
* or 129. if it is 128, this function returns the same value as oldVal. If
* it is 129, this function returns !oldVal. This is used for certain sprms
*
* @param x The byte value to convert.
* @param oldVal The old boolean value.
*
* @return A boolean whose value depends on x and oldVal.
*/
private static boolean getCHPFlag(byte x, boolean oldVal)
{
/*
switch(x)
{
case 0:
return false;
case 1:
return true;
case (byte)0x80:
return oldVal;
case (byte)0x81:
return !oldVal;
default:
return false;
}
*/
if(x == 0)return false;
else if(x == 1)return true;
else if((x & 0x80) == 0x80)return oldVal;
else if((x & 0x81) == 0x81)return !oldVal;
else return false;
}
/**
* Converts an int into a boolean. If the int is non-zero, it returns true.
* Otherwise it returns false.
*
* @param x The int to convert.
*
* @return A boolean whose value depends on x.
*/
public static boolean getFlag(int x)
{
if(x != 0)
{
return true;
}
else
{
return false;
}
}
public static void compressProperty()
{
}
static void compressPAPOperation()
{
}
static void compressCHPOperation()
{
}
static void compressTAPOperation()
{
}
static void compressSEPOperation()
{
}
}