001: /* ====================================================================
002: Licensed to the Apache Software Foundation (ASF) under one or more
003: contributor license agreements. See the NOTICE file distributed with
004: this work for additional information regarding copyright ownership.
005: The ASF licenses this file to You under the Apache License, Version 2.0
006: (the "License"); you may not use this file except in compliance with
007: the License. You may obtain a copy of the License at
008:
009: http://www.apache.org/licenses/LICENSE-2.0
010:
011: Unless required by applicable law or agreed to in writing, software
012: distributed under the License is distributed on an "AS IS" BASIS,
013: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: See the License for the specific language governing permissions and
015: limitations under the License.
016: ==================================================================== */
017:
018: package org.apache.poi.hwpf.model;
019:
020: import java.io.UnsupportedEncodingException;
021: import java.util.Arrays;
022:
023: import org.apache.poi.hwpf.usermodel.CharacterProperties;
024: import org.apache.poi.hwpf.usermodel.ParagraphProperties;
025: import org.apache.poi.util.LittleEndian;
026: import org.apache.poi.util.BitField;
027: import org.apache.poi.util.BitFieldFactory;
028:
029: /**
030: * Comment me
031: *
032: * @author Ryan Ackley
033: */
034:
035: public class StyleDescription implements HDFType {
036:
037: private final static int PARAGRAPH_STYLE = 1;
038: private final static int CHARACTER_STYLE = 2;
039:
040: private int _istd;
041: private int _baseLength;
042: private short _infoShort;
043: private static BitField _sti = BitFieldFactory.getInstance(0xfff);
044: private static BitField _fScratch = BitFieldFactory
045: .getInstance(0x1000);
046: private static BitField _fInvalHeight = BitFieldFactory
047: .getInstance(0x2000);
048: private static BitField _fHasUpe = BitFieldFactory
049: .getInstance(0x4000);
050: private static BitField _fMassCopy = BitFieldFactory
051: .getInstance(0x8000);
052: private short _infoShort2;
053: private static BitField _styleTypeCode = BitFieldFactory
054: .getInstance(0xf);
055: private static BitField _baseStyle = BitFieldFactory
056: .getInstance(0xfff0);
057: private short _infoShort3;
058: private static BitField _numUPX = BitFieldFactory.getInstance(0xf);
059: private static BitField _nextStyle = BitFieldFactory
060: .getInstance(0xfff0);
061: private short _bchUpe;
062: private short _infoShort4;
063: private static BitField _fAutoRedef = BitFieldFactory
064: .getInstance(0x1);
065: private static BitField _fHidden = BitFieldFactory.getInstance(0x2);
066:
067: UPX[] _upxs;
068: String _name;
069: ParagraphProperties _pap;
070: CharacterProperties _chp;
071:
072: public StyleDescription() {
073: // _pap = new ParagraphProperties();
074: // _chp = new CharacterProperties();
075: }
076:
077: public StyleDescription(byte[] std, int baseLength, int offset,
078: boolean word9) {
079: _baseLength = baseLength;
080: int nameStart = offset + baseLength;
081: _infoShort = LittleEndian.getShort(std, offset);
082: offset += LittleEndian.SHORT_SIZE;
083: _infoShort2 = LittleEndian.getShort(std, offset);
084: offset += LittleEndian.SHORT_SIZE;
085: _infoShort3 = LittleEndian.getShort(std, offset);
086: offset += LittleEndian.SHORT_SIZE;
087: _bchUpe = LittleEndian.getShort(std, offset);
088: offset += LittleEndian.SHORT_SIZE;
089: _infoShort4 = LittleEndian.getShort(std, offset);
090: offset += LittleEndian.SHORT_SIZE;
091:
092: //first byte(s) of variable length section of std is the length of the
093: //style name and aliases string
094: int nameLength = 0;
095: int multiplier = 1;
096: if (word9) {
097: nameLength = LittleEndian.getShort(std, nameStart);
098: multiplier = 2;
099: nameStart += LittleEndian.SHORT_SIZE;
100: } else {
101: nameLength = std[nameStart];
102: }
103:
104: try {
105: _name = new String(std, nameStart, nameLength * multiplier,
106: "UTF-16LE");
107: } catch (UnsupportedEncodingException ignore) {
108: // ignore
109: }
110:
111: //length then null terminator.
112: int grupxStart = ((nameLength + 1) * multiplier) + nameStart;
113:
114: // the spec only refers to two possible upxs but it mentions
115: // that more may be added in the future
116: int varOffset = grupxStart;
117: int numUPX = _numUPX.getValue(_infoShort3);
118: _upxs = new UPX[numUPX];
119: for (int x = 0; x < numUPX; x++) {
120: int upxSize = LittleEndian.getShort(std, varOffset);
121: varOffset += LittleEndian.SHORT_SIZE;
122:
123: byte[] upx = new byte[upxSize];
124: System.arraycopy(std, varOffset, upx, 0, upxSize);
125: _upxs[x] = new UPX(upx);
126: varOffset += upxSize;
127:
128: // the upx will always start on a word boundary.
129: if (upxSize % 2 == 1) {
130: ++varOffset;
131: }
132:
133: }
134:
135: }
136:
137: public int getBaseStyle() {
138: return _baseStyle.getValue(_infoShort2);
139: }
140:
141: public byte[] getCHPX() {
142: switch (_styleTypeCode.getValue(_infoShort2)) {
143: case PARAGRAPH_STYLE:
144: if (_upxs.length > 1) {
145: return _upxs[1].getUPX();
146: }
147: return null;
148: case CHARACTER_STYLE:
149: return _upxs[0].getUPX();
150: default:
151: return null;
152: }
153:
154: }
155:
156: public byte[] getPAPX() {
157: switch (_styleTypeCode.getValue(_infoShort2)) {
158: case PARAGRAPH_STYLE:
159: return _upxs[0].getUPX();
160: default:
161: return null;
162: }
163: }
164:
165: public ParagraphProperties getPAP() {
166: return _pap;
167: }
168:
169: public CharacterProperties getCHP() {
170: return _chp;
171: }
172:
173: void setPAP(ParagraphProperties pap) {
174: _pap = pap;
175: }
176:
177: void setCHP(CharacterProperties chp) {
178: _chp = chp;
179: }
180:
181: public String getName() {
182: return _name;
183: }
184:
185: public byte[] toByteArray() {
186: // size equals _baseLength bytes for known variables plus 2 bytes for name
187: // length plus name length * 2 plus 2 bytes for null plus upx's preceded by
188: // length
189: int size = _baseLength + 2 + ((_name.length() + 1) * 2);
190:
191: // determine the size needed for the upxs. They always fall on word
192: // boundaries.
193: size += _upxs[0].size() + 2;
194: for (int x = 1; x < _upxs.length; x++) {
195: size += _upxs[x - 1].size() % 2;
196: size += _upxs[x].size() + 2;
197: }
198:
199: byte[] buf = new byte[size];
200:
201: int offset = 0;
202: LittleEndian.putShort(buf, offset, _infoShort);
203: offset += LittleEndian.SHORT_SIZE;
204: LittleEndian.putShort(buf, offset, _infoShort2);
205: offset += LittleEndian.SHORT_SIZE;
206: LittleEndian.putShort(buf, offset, _infoShort3);
207: offset += LittleEndian.SHORT_SIZE;
208: LittleEndian.putShort(buf, offset, _bchUpe);
209: offset += LittleEndian.SHORT_SIZE;
210: LittleEndian.putShort(buf, offset, _infoShort4);
211: offset = _baseLength;
212:
213: char[] letters = _name.toCharArray();
214: LittleEndian.putShort(buf, _baseLength, (short) letters.length);
215: offset += LittleEndian.SHORT_SIZE;
216: for (int x = 0; x < letters.length; x++) {
217: LittleEndian.putShort(buf, offset, (short) letters[x]);
218: offset += LittleEndian.SHORT_SIZE;
219: }
220: // get past the null delimiter for the name.
221: offset += LittleEndian.SHORT_SIZE;
222:
223: for (int x = 0; x < _upxs.length; x++) {
224: short upxSize = (short) _upxs[x].size();
225: LittleEndian.putShort(buf, offset, upxSize);
226: offset += LittleEndian.SHORT_SIZE;
227: System
228: .arraycopy(_upxs[x].getUPX(), 0, buf, offset,
229: upxSize);
230: offset += upxSize + (upxSize % 2);
231: }
232:
233: return buf;
234: }
235:
236: public boolean equals(Object o) {
237: StyleDescription sd = (StyleDescription) o;
238: if (sd._infoShort == _infoShort
239: && sd._infoShort2 == _infoShort2
240: && sd._infoShort3 == _infoShort3
241: && sd._bchUpe == _bchUpe
242: && sd._infoShort4 == _infoShort4
243: && _name.equals(sd._name)) {
244:
245: if (!Arrays.equals(_upxs, sd._upxs)) {
246: return false;
247: }
248: return true;
249: }
250: return false;
251: }
252: }
|