-
/* ====================================================================
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
-/*
- * ColumnInfoRecord.java
- *
- * Created on December 8, 2001, 8:44 AM
- */
package org.apache.poi.hssf.record;
import org.apache.poi.util.LittleEndian;
import org.apache.poi.util.BitFieldFactory;
/**
- * Title: ColumnInfo Record<P>
- * Description: Defines with width and formatting for a range of columns<P>
- * REFERENCE: PG 293 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
+ * Title: COLINFO Record<p/>
+ * Description: Defines with width and formatting for a range of columns<p/>
+ * REFERENCE: PG 293 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<p/>
* @author Andrew C. Oliver (acoliver at apache dot org)
* @version 2.0-pre
*/
-
-public class ColumnInfoRecord
- extends Record
-{
+public final class ColumnInfoRecord extends Record {
public static final short sid = 0x7d;
private short field_1_first_col;
private short field_2_last_col;
private short field_3_col_width;
private short field_4_xf_index;
private short field_5_options;
- static final private BitField hidden = BitFieldFactory.getInstance(0x01);
- static final private BitField outlevel = BitFieldFactory.getInstance(0x0700);
- static final private BitField collapsed = BitFieldFactory.getInstance(0x1000);
+ private static final BitField hidden = BitFieldFactory.getInstance(0x01);
+ private static final BitField outlevel = BitFieldFactory.getInstance(0x0700);
+ private static final BitField collapsed = BitFieldFactory.getInstance(0x1000);
+ // Excel seems write values 2, 10, and 260, even though spec says "must be zero"
private short field_6_reserved;
public ColumnInfoRecord()
{
+ field_6_reserved = 2; // seems to be the most common value
}
/**
field_3_col_width = in.readShort();
field_4_xf_index = in.readShort();
field_5_options = in.readShort();
- field_6_reserved = in.readShort();
+ switch(in.remaining()) {
+ case 2: // usual case
+ field_6_reserved = in.readShort();
+ break;
+ case 1:
+ // often COLINFO gets encoded 1 byte short
+ // shouldn't matter because this field is unused
+ field_6_reserved = in.readByte();
+ break;
+ default:
+ throw new RuntimeException("Unusual record size remaining=(" + in.remaining() + ")");
+ }
}
protected void validateSid(short id)
See the License for the specific language governing permissions and
limitations under the License.
==================================================================== */
-
package org.apache.poi.hssf.record;
import org.apache.poi.util.LittleEndian;
-import org.apache.poi.util.POILogFactory;
-import org.apache.poi.util.POILogger;
import org.apache.poi.util.StringUtil;
/**
- * Title: FileSharing<P>
+ * Title: FILESHARING<P>
* Description: stores the encrypted readonly for a workbook (write protect)
- * REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
+ * This functionality is accessed from the options dialog box available when performing 'Save As'.<p/>
+ * REFERENCE: PG 314 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<p/>
* @author Andrew C. Oliver (acoliver at apache dot org)
*/
+public final class FileSharingRecord extends Record {
-public class FileSharingRecord extends Record {
- private static POILogger logger = POILogFactory.getLogger(FileSharingRecord.class);
-
public final static short sid = 0x5b;
private short field_1_readonly;
private short field_2_password;
- private byte field_3_username_length;
- private short field_4_unknown; // not documented
- private String field_5_username;
+ private byte field_3_username_unicode_options;
+ private String field_3_username_value;
public FileSharingRecord() {}
protected void fillFields(RecordInputStream in) {
field_1_readonly = in.readShort();
field_2_password = in.readShort();
- field_3_username_length = in.readByte();
- // Is this really correct? The latest docs
- // seem to hint there's nothing between the
- // username length and the username string
- field_4_unknown = in.readShort();
+ int nameLen = in.readShort();
- // Ensure we don't try to read more data than
- // there actually is
- if(field_3_username_length > in.remaining()) {
- logger.log(POILogger.WARN, "FileSharingRecord defined a username of length " + field_3_username_length + ", but only " + in.remaining() + " bytes were left, truncating");
- field_3_username_length = (byte)in.remaining();
- }
- if(field_3_username_length > 0) {
- field_5_username = in.readCompressedUnicode(field_3_username_length);
+ if(nameLen > 0) {
+ // TODO - Current examples(3) from junits only have zero length username.
+ field_3_username_unicode_options = in.readByte();
+ field_3_username_value = in.readCompressedUnicode(nameLen);
} else {
- field_5_username = "";
+ field_3_username_value = "";
}
}
/**
* @returns byte representing the length of the username field
*/
- public byte getUsernameLength() {
- return field_3_username_length ;
- }
-
- /**
- * @param byte representing the length of the username field
- */
- public void setUsernameLength(byte length) {
- this.field_3_username_length = length;
+ public short getUsernameLength() {
+ return (short) field_3_username_value.length();
}
/**
* @returns username of the user that created the file
*/
public String getUsername() {
- return this.field_5_username;
+ return field_3_username_value;
}
/**
* @param username of the user that created the file
*/
public void setUsername(String username) {
- this.field_5_username = username;
- this.field_3_username_length = (byte)username.length();
- }
-
- /**
- * @return short value of a "bonus field" in Excel that was not doc'd
- */
- public short getUnknown() {
- return field_4_unknown;
+ field_3_username_value = username;
}
- /**
- * @param unknown field value to set (bonus field that is not doc'd)
- */
- public void setUnknown(short unk) {
- field_4_unknown = unk;
- }
public String toString() {
StringBuffer buffer = new StringBuffer();
.append(getReadOnly() == 1 ? "true" : "false").append("\n");
buffer.append(" .password = ")
.append(Integer.toHexString(getPassword())).append("\n");
- buffer.append(" .userlen = ")
- .append(Integer.toHexString(getUsernameLength())).append("\n");
- buffer.append(" .unknown = ")
- .append(Integer.toHexString(getUnknown())).append("\n");
buffer.append(" .username = ")
.append(getUsername()).append("\n");
buffer.append("[/FILESHARING]\n");
}
public int serialize(int offset, byte [] data) {
+ // TODO - junit
LittleEndian.putShort(data, 0 + offset, sid);
LittleEndian.putShort(data, 2 + offset, (short)(getRecordSize()-4));
LittleEndian.putShort(data, 4 + offset, getReadOnly());
LittleEndian.putShort(data, 6 + offset, getPassword());
- data[ 8 + offset ] = getUsernameLength();
- LittleEndian.putShort(data, 9 + offset, getUnknown());
- StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
+ LittleEndian.putShort(data, 8 + offset, getUsernameLength());
+ if(getUsernameLength() > 0) {
+ LittleEndian.putByte(data, 10 + offset, field_3_username_unicode_options);
+ StringUtil.putCompressedUnicode( getUsername(), data, 11 + offset );
+ }
return getRecordSize();
}
public int getRecordSize() {
- return 11+getUsernameLength();
+ short nameLen = getUsernameLength();
+ if (nameLen < 1) {
+ return 10;
+ }
+ return 11+nameLen;
}
public short getSid() {
FileSharingRecord clone = new FileSharingRecord();
clone.setReadOnly(field_1_readonly);
clone.setPassword(field_2_password);
- clone.setUsernameLength(field_3_username_length);
- clone.setUnknown(field_4_unknown);
- clone.setUsername(field_5_username);
+ clone.setUsername(field_3_username_value);
return clone;
}
-
}
* @author avik
* @author Jason Height (jheight at chariot dot net dot au)
*/
-
public abstract class Ptg
{
-
+
/* convert infix order ptg list to rpn order ptg list
* @return List ptgs in RPN order
* @param infixPtgs List of ptgs in infix order
*/
-
+
/* DO NOT REMOVE
*we keep this method in case we wish to change the way we parse
*It needs a getPrecedence in OperationsPtg
-
+
public static List ptgsToRpn(List infixPtgs) {
java.util.Stack operands = new java.util.Stack();
java.util.List retval = new java.util.Stack();
-
+
java.util.ListIterator i = infixPtgs.listIterator();
Object p;
OperationPtg o ;
weHaveABracket = true;
} else {
o = (OperationPtg) operands.pop();
- while (!(o instanceof ParenthesisPtg)) {
+ while (!(o instanceof ParenthesisPtg)) {
retval.add(o);
}
weHaveABracket = false;
}
} else {
-
+
while (!operands.isEmpty() && ((OperationPtg) operands.peek()).getPrecedence() >= ((OperationPtg) p).getPrecedence() ) { //TODO handle ^ since it is right associative
retval.add(operands.pop());
}
//throw some error
} else {
retval.add(operands.pop());
- }
+ }
}
return retval;
}
*/
+ /**
+ * Reads <tt>size</tt> bytes of the input stream, to create an array of <tt>Ptg</tt>s.
+ * Extra data (beyond <tt>size</tt>) may be read if and <tt>ArrayPtg</tt>s are present.
+ */
public static Stack createParsedExpressionTokens(short size, RecordInputStream in )
{
Stack stack = new Stack();
{
Ptg ptg = Ptg.createPtg( in );
if (ptg instanceof ArrayPtg) {
- if (arrayPtgs == null)
- arrayPtgs = new ArrayList(5);
- arrayPtgs.add(ptg);
- pos += 8;
+ if (arrayPtgs == null)
+ arrayPtgs = new ArrayList(5);
+ arrayPtgs.add(ptg);
+ pos += 8;
} else pos += ptg.getSize();
stack.push( ptg );
}
+ if(pos != size) {
+ throw new RuntimeException("Ptg array size mismatch");
+ }
if (arrayPtgs != null) {
- for (int i=0;i<arrayPtgs.size();i++) {
- ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
- p.readTokenValues(in);
- }
+ for (int i=0;i<arrayPtgs.size();i++) {
+ ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
+ p.readTokenValues(in);
+ }
}
return stack;
}
-
+
public static Ptg createPtg(RecordInputStream in)
{
byte id = in.readByte();
case ExpPtg.sid : // 0x01
retval = new ExpPtg(in);
break;
-
+
case AddPtg.sid : // 0x03
retval = new AddPtg(in);
break;
-
+
case SubtractPtg.sid : // 0x04
retval = new SubtractPtg(in);
break;
-
+
case MultiplyPtg.sid : // 0x05
retval = new MultiplyPtg(in);
break;
-
+
case DividePtg.sid : // 0x06
- retval = new DividePtg(in);
- break;
-
+ retval = new DividePtg(in);
+ break;
+
case PowerPtg.sid : // 0x07
retval = new PowerPtg(in);
break;
-
+
case ConcatPtg.sid : // 0x08
retval = new ConcatPtg(in);
- break;
-
+ break;
+
case LessThanPtg.sid: // 0x09
retval = new LessThanPtg(in);
- break;
-
+ break;
+
case LessEqualPtg.sid : // 0x0a
retval = new LessEqualPtg(in);
- break;
-
+ break;
+
case EqualPtg.sid : // 0x0b
retval = new EqualPtg(in);
- break;
-
+ break;
+
case GreaterEqualPtg.sid : // 0x0c
retval = new GreaterEqualPtg(in);
- break;
-
+ break;
+
case GreaterThanPtg.sid : // 0x0d
retval = new GreaterThanPtg(in);
- break;
-
+ break;
+
case NotEqualPtg.sid : // 0x0e
retval = new NotEqualPtg(in);
- break;
-
+ break;
+
case IntersectionPtg.sid : // 0x0f
retval = new IntersectionPtg(in);
- break;
+ break;
case UnionPtg.sid : // 0x10
retval = new UnionPtg(in);
- break;
-
+ break;
+
case RangePtg.sid : // 0x11
retval = new RangePtg(in);
- break;
-
+ break;
+
case UnaryPlusPtg.sid : // 0x12
retval = new UnaryPlusPtg(in);
- break;
-
+ break;
+
case UnaryMinusPtg.sid : // 0x13
retval = new UnaryMinusPtg(in);
- break;
-
+ break;
+
case PercentPtg.sid : // 0x14
retval = new PercentPtg(in);
- break;
-
+ break;
+
case ParenthesisPtg.sid : // 0x15
retval = new ParenthesisPtg(in);
- break;
-
+ break;
+
case MissingArgPtg.sid : // 0x16
retval = new MissingArgPtg(in);
- break;
-
+ break;
+
case StringPtg.sid : // 0x17
retval = new StringPtg(in);
break;
-
+
case AttrPtg.sid : // 0x19
case 0x1a :
retval = new AttrPtg(in);
- break;
-
+ break;
+
case ErrPtg.sid : // 0x1c
retval = new ErrPtg(in);
- break;
-
+ break;
+
case BoolPtg.sid : // 0x1d
retval = new BoolPtg(in);
break;
-
+
case IntPtg.sid : // 0x1e
retval = new IntPtg(in);
- break;
-
+ break;
+
case NumberPtg.sid : // 0x1f
- retval = new NumberPtg(in);
- break;
-
+ retval = new NumberPtg(in);
+ break;
+
case ArrayPtg.sid : // 0x20
- retval = new ArrayPtg(in);
- break;
+ retval = new ArrayPtg(in);
+ break;
case ArrayPtgV.sid : // 0x40
- retval = new ArrayPtgV(in);
- break;
+ retval = new ArrayPtgV(in);
+ break;
case ArrayPtgA.sid : // 0x60
- retval = new ArrayPtgA(in);
- break;
-
+ retval = new ArrayPtgA(in);
+ break;
+
case FuncPtg.sid : // 0x21
case FuncPtg.sid + 0x20 : // 0x41
case FuncPtg.sid + 0x40 : // 0x61
retval = new FuncPtg(in);
break;
-
+
case FuncVarPtg.sid : // 0x22
case FuncVarPtg.sid + 0x20 : // 0x42
case FuncVarPtg.sid + 0x40 : // 0x62
retval = new FuncVarPtg(in);
- break;
-
- case ReferencePtg.sid : // 0x24
+ break;
+
+ case ReferencePtg.sid : // 0x24
retval = new ReferencePtg(in);
- break;
+ break;
case RefAPtg.sid : // 0x64
retval = new RefAPtg(in);
- break;
+ break;
case RefVPtg.sid : // 0x44
retval = new RefVPtg(in);
- break;
+ break;
case RefNAPtg.sid : // 0x6C
retval = new RefNAPtg(in);
break;
break;
case RefNVPtg.sid : // 0x4C
retval = new RefNVPtg(in);
- break;
-
- case AreaPtg.sid : // 0x25
+ break;
+
+ case AreaPtg.sid : // 0x25
retval = new AreaPtg(in);
- break;
+ break;
case AreaVPtg.sid: // 0x45
retval = new AreaVPtg(in);
break;
case AreaNVPtg.sid : // 0x4D
retval = new AreaNVPtg(in);
break;
-
+
case MemAreaPtg.sid : // 0x26
case MemAreaPtg.sid + 0x40 : // 0x46
case MemAreaPtg.sid + 0x20 : // 0x66
retval = new MemAreaPtg(in);
break;
-
+
case MemErrPtg.sid : // 0x27
case MemErrPtg.sid + 0x20 : // 0x47
case MemErrPtg.sid + 0x40 : // 0x67
retval = new MemErrPtg(in);
- break;
-
+ break;
+
case MemFuncPtg.sid : // 0x29
retval = new MemFuncPtg(in);
break;
-
+
case RefErrorPtg.sid : // 0x2a
case RefErrorPtg.sid + 0x20 : // 0x4a
case RefErrorPtg.sid + 0x40 : // 0x6a
retval = new RefErrorPtg(in);
- break;
-
+ break;
+
case AreaErrPtg.sid : // 0x2b
case AreaErrPtg.sid + 0x20 : // 0x4b
case AreaErrPtg.sid + 0x40 : // 0x6b
retval = new AreaErrPtg(in);
- break;
-
+ break;
+
case NamePtg.sid : // 0x23
case NamePtg.sid + 0x20 : // 0x43
case NamePtg.sid + 0x40 : // 0x63
retval = new NamePtg(in);
break;
-
+
case NameXPtg.sid : // 0x39
case NameXPtg.sid + 0x20 : // 0x45
case NameXPtg.sid + 0x40 : // 0x79
retval = new NameXPtg(in);
- break;
-
+ break;
+
case Area3DPtg.sid : // 0x3b
case Area3DPtg.sid + 0x20 : // 0x5b
case Area3DPtg.sid + 0x40 : // 0x7b
retval = new Area3DPtg(in);
- break;
-
+ break;
+
case Ref3DPtg.sid : // 0x3a
case Ref3DPtg.sid + 0x20: // 0x5a
case Ref3DPtg.sid + 0x40: // 0x7a
retval = new Ref3DPtg(in);
- break;
-
+ break;
+
case DeletedRef3DPtg.sid: // 0x3c
case DeletedRef3DPtg.sid + 0x20: // 0x5c
case DeletedRef3DPtg.sid + 0x40: // 0x7c
retval = new DeletedRef3DPtg(in);
- break;
-
+ break;
+
case DeletedArea3DPtg.sid : // 0x3d
case DeletedArea3DPtg.sid + 0x20 : // 0x5d
case DeletedArea3DPtg.sid + 0x40 : // 0x7d
retval = new DeletedArea3DPtg(in);
break;
-
+
case 0x00:
- retval = new UnknownPtg();
- break;
-
+ retval = new UnknownPtg();
+ break;
+
default :
//retval = new UnknownPtg();
throw new java.lang.UnsupportedOperationException(" Unknown Ptg in Formula: 0x"+
Integer.toHexString(( int ) id) + " (" + ( int ) id + ")");
}
-
+
if (id > 0x60) {
retval.setClass(CLASS_ARRAY);
} else if (id > 0x40) {
}
return retval;
-
+
}
-
+
public static int serializePtgStack(Stack expression, byte[] array, int offset) {
- int pos = 0;
- int size = 0;
- if (expression != null)
- size = expression.size();
-
- List arrayPtgs = null;
-
- for (int k = 0; k < size; k++) {
- Ptg ptg = ( Ptg ) expression.get(k);
-
- ptg.writeBytes(array, pos + offset);
- if (ptg instanceof ArrayPtg) {
- if (arrayPtgs == null)
- arrayPtgs = new ArrayList(5);
- arrayPtgs.add(ptg);
- pos += 8;
- } else pos += ptg.getSize();
- }
- if (arrayPtgs != null) {
- for (int i=0;i<arrayPtgs.size();i++) {
- ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
- pos += p.writeTokenValueBytes(array, pos + offset);
- }
- }
- return pos;
+ int pos = 0;
+ int size = 0;
+ if (expression != null)
+ size = expression.size();
+
+ List arrayPtgs = null;
+
+ for (int k = 0; k < size; k++) {
+ Ptg ptg = ( Ptg ) expression.get(k);
+
+ ptg.writeBytes(array, pos + offset);
+ if (ptg instanceof ArrayPtg) {
+ if (arrayPtgs == null)
+ arrayPtgs = new ArrayList(5);
+ arrayPtgs.add(ptg);
+ pos += 8;
+ } else pos += ptg.getSize();
+ }
+ if (arrayPtgs != null) {
+ for (int i=0;i<arrayPtgs.size();i++) {
+ ArrayPtg p = (ArrayPtg)arrayPtgs.get(i);
+ pos += p.writeTokenValueBytes(array, pos + offset);
+ }
+ }
+ return pos;
}
public abstract int getSize();
}
/** write this Ptg to a byte array*/
public abstract void writeBytes(byte [] array, int offset);
-
+
/**
* return a string representation of this token alone
*/
public String toDebugString() {
byte[] ba = new byte[getSize()];
String retval=null;
- writeBytes(ba,0);
+ writeBytes(ba,0);
try {
retval = org.apache.poi.util.HexDump.dump(ba,0,0);
} catch (Exception e) {
}
return retval;
}
-
+
/** Overridden toString method to ensure object hash is not printed.
* This helps get rid of gratuitous diffs when comparing two dumps
* Subclasses may output more relevant information by overriding this method
public String toString(){
return this.getClass().toString();
}
-
+
public static final byte CLASS_REF = 0x00;
public static final byte CLASS_VALUE = 0x20;
public static final byte CLASS_ARRAY = 0x40;
-
+
protected byte ptgClass = CLASS_REF; //base ptg
-
+
public void setClass(byte thePtgClass) {
ptgClass = thePtgClass;
}
-
+
/** returns the class (REF/VALUE/ARRAY) for this Ptg */
public byte getPtgClass() {
return ptgClass;
}
-
+
public abstract byte getDefaultOperandClass();
public abstract Object clone();
-
-
+
+
}