View | Details | Raw Unified | Return to bug 61136
Collapse All | Expand All

(-)src/java/org/apache/poi/ss/formula/Formula.java (-22 / +70 lines)
Lines 37-47 Link Here
37
37
38
	private static final Formula EMPTY = new Formula(new byte[0], 0);
38
	private static final Formula EMPTY = new Formula(new byte[0], 0);
39
39
40
	/** immutable */
40
	/** immutable, lazily populated */
41
	private final byte[] _byteEncoding;
41
	private byte[] _byteEncoding;
42
	private final int _encodedTokenLen;
42
	private int _encodedTokenLen = -1;
43
	private Ptg[] _ptgTokens;
43
44
44
	private Formula(byte[] byteEncoding, int encodedTokenLen) {
45
	private Formula(final byte[] byteEncoding, final int encodedTokenLen) {
45
		_byteEncoding = byteEncoding.clone();
46
		_byteEncoding = byteEncoding.clone();
46
		_encodedTokenLen = encodedTokenLen;
47
		_encodedTokenLen = encodedTokenLen;
47
//		if (false) { // set to true to eagerly check Ptg decoding
48
//		if (false) { // set to true to eagerly check Ptg decoding
Lines 58-63 Link Here
58
//			}
59
//			}
59
//		}
60
//		}
60
	}
61
	}
62
63
	private Formula(final Ptg[] ptgs) {
64
		// cachedTokens should only be provided by a source that promises not to mutate the array
65
		// Since this class itself doesn't mutate _ptgTokens, as long as this promise is honored,
66
		// _ptgTokens is immutable.
67
		_ptgTokens = ptgs.clone();
68
	}
69
61
	/**
70
	/**
62
	 * Convenience method for {@link #read(int, LittleEndianInput, int)}
71
	 * Convenience method for {@link #read(int, LittleEndianInput, int)}
63
	 */
72
	 */
Lines 78-86 Link Here
78
	}
87
	}
79
88
80
	public Ptg[] getTokens() {
89
	public Ptg[] getTokens() {
90
		if (_ptgTokens == null) {
91
                	readPtgTokensFromBytes();
92
		}
93
		return _ptgTokens;
94
	}
95
96
	private byte[] getEncodedBytes() {
97
		if (_byteEncoding == null) {
98
			readBytesFromPtgTokens();
99
		}
100
		return _byteEncoding;
101
	}
102
103
	private int getEncodedTokenLen() {
104
		if (_getEncodedTokenLen <= 0) {
105
			readBytesFromPtgTokens();
106
		}
107
		return _getEncodedTokenLen;
108
	}
109
110
	private void readPtgTokensFromBytes() {
111
                if (_byteEncoding == null || _getEncodedTokenLen <= 0) {
112
			// EMPTY
113
			return;
114
		}
81
		LittleEndianInput in = new LittleEndianByteArrayInputStream(_byteEncoding);
115
		LittleEndianInput in = new LittleEndianByteArrayInputStream(_byteEncoding);
82
		return Ptg.readTokens(_encodedTokenLen, in);
116
		_ptgTokens = Ptg.readTokens(_encodedTokenLen, in);
83
	}
117
	}
118
119
	private void readBytesFromPtgTokens() {
120
		if (_ptgTokens == null) {
121
			// EMPTY
122
			return;
123
		}
124
		final int totalSize = Ptg.getEncodedSize(_ptgTokens);
125
		final byte[] encodedData = new byte[totalSize];
126
		Ptg.serializePtgs(ptgs, encodedData, 0);
127
		final int encodedTokenLen = Ptg.getEncodedSizeWithoutArrayData(ptgs);
128
		
129
		_byteEncoding = encodedData;
130
		_encodedTokenLen = encodedTokenLen;
131
	}
132
84
	/**
133
	/**
85
	 * Writes  The formula encoding is includes:
134
	 * Writes  The formula encoding is includes:
86
	 * <ul>
135
	 * <ul>
Lines 90-105 Link Here
90
	 * </ul>
139
	 * </ul>
91
	 */
140
	 */
92
	public void serialize(LittleEndianOutput out) {
141
	public void serialize(LittleEndianOutput out) {
93
		out.writeShort(_encodedTokenLen);
142
		out.writeShort(getEncodedTokenLen());
94
		out.write(_byteEncoding);
143
		out.write(getEncodedBytes());
95
	}
144
	}
96
145
97
	public void serializeTokens(LittleEndianOutput out) {
146
	public void serializeTokens(LittleEndianOutput out) {
98
		out.write(_byteEncoding, 0, _encodedTokenLen);
147
		out.write(getEncodedBytes(), 0, getEncodedTokenLen());
99
	}
148
	}
100
	public void serializeArrayConstantData(LittleEndianOutput out) {
149
	public void serializeArrayConstantData(LittleEndianOutput out) {
101
		int len = _byteEncoding.length-_encodedTokenLen;
150
		byte[] bytes = getEncodedBytes();
102
		out.write(_byteEncoding, _encodedTokenLen, len);
151
                int encodedLen = getEncodedTokenLen();
152
		int len = bytes.length - encodedLen;
153
		out.write(bytes, encodedLen, len);
103
	}
154
	}
104
155
105
156
Lines 113-119 Link Here
113
	 * Note - this value is different to <tt>tokenDataLength</tt>
164
	 * Note - this value is different to <tt>tokenDataLength</tt>
114
	 */
165
	 */
115
	public int getEncodedSize() {
166
	public int getEncodedSize() {
116
		return 2 + _byteEncoding.length;
167
		return 2 + getEncodedBytes().length;
117
	}
168
	}
118
	/**
169
	/**
119
	 * This method is often used when the formula length does not appear immediately before
170
	 * This method is often used when the formula length does not appear immediately before
Lines 123-129 Link Here
123
	 * the leading ushort field, nor any trailing array constant data.
174
	 * the leading ushort field, nor any trailing array constant data.
124
	 */
175
	 */
125
	public int getEncodedTokenSize() {
176
	public int getEncodedTokenSize() {
126
		return _encodedTokenLen;
177
	
178
		return getEncodedTokenLen();
127
	}
179
	}
128
180
129
	/**
181
	/**
Lines 132-146 Link Here
132
	 * @param ptgs may be <code>null</code>
184
	 * @param ptgs may be <code>null</code>
133
	 * @return Never <code>null</code> (Possibly empty if the supplied <tt>ptgs</tt> is <code>null</code>)
185
	 * @return Never <code>null</code> (Possibly empty if the supplied <tt>ptgs</tt> is <code>null</code>)
134
	 */
186
	 */
135
	public static Formula create(Ptg[] ptgs) {
187
	public static Formula create(final Ptg[] ptgs) {
136
		if (ptgs == null || ptgs.length < 1) {
188
		if (ptgs == null || ptgs.length < 1) {
137
			return EMPTY;
189
			return EMPTY;
138
		}
190
		}
139
		int totalSize = Ptg.getEncodedSize(ptgs);
191
		return new Formula(ptgs);
140
		byte[] encodedData = new byte[totalSize];
141
		Ptg.serializePtgs(ptgs, encodedData, 0);
142
		int encodedTokenLen = Ptg.getEncodedSizeWithoutArrayData(ptgs);
143
		return new Formula(encodedData, encodedTokenLen);
144
	}
192
	}
145
	/**
193
	/**
146
	 * Gets the {@link Ptg} array from the supplied {@link Formula}.
194
	 * Gets the {@link Ptg} array from the supplied {@link Formula}.
Lines 172-178 Link Here
172
	 * belongs to.  <code>null</code> if this formula is not part of an array or shared formula.
220
	 * belongs to.  <code>null</code> if this formula is not part of an array or shared formula.
173
	 */
221
	 */
174
	public CellReference getExpReference() {
222
	public CellReference getExpReference() {
175
		byte[] data = _byteEncoding;
223
		final byte[] data = getEncodedBytes();
176
		if (data.length != 5) {
224
		if (data.length != 5) {
177
			// tExp and tTbl are always 5 bytes long, and the only ptg in the formula
225
			// tExp and tTbl are always 5 bytes long, and the only ptg in the formula
178
			return null;
226
			return null;
Lines 185-195 Link Here
185
			default:
233
			default:
186
				return null;
234
				return null;
187
		}
235
		}
188
		int firstRow = LittleEndian.getUShort(data, 1);
236
		final int firstRow = LittleEndian.getUShort(data, 1);
189
		int firstColumn = LittleEndian.getUShort(data, 3);
237
		final int firstColumn = LittleEndian.getUShort(data, 3);
190
		return new CellReference(firstRow, firstColumn);
238
		return new CellReference(firstRow, firstColumn);
191
	}
239
	}
192
	public boolean isSame(Formula other) {
240
	public boolean isSame(Formula other) {
193
		return Arrays.equals(_byteEncoding, other._byteEncoding);
241
		return Arrays.equals(getEncodedBytes(), other.getEncodedBytes());
194
	}
242
	}
195
}
243
}

Return to bug 61136