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 org.apache.poi.util.LittleEndian;
021: import org.apache.poi.util.POILogFactory;
022: import org.apache.poi.util.POILogger;
023:
024: import org.apache.poi.hwpf.model.io.*;
025:
026: import java.util.HashMap;
027: import java.util.ArrayList;
028: import java.util.Iterator;
029: import java.util.NoSuchElementException;
030:
031: import java.io.ByteArrayOutputStream;
032: import java.io.IOException;
033:
034: /**
035: * @author Ryan Ackley
036: */
037: public class ListTables {
038: private static final int LIST_DATA_SIZE = 28;
039: private static final int LIST_FORMAT_OVERRIDE_SIZE = 16;
040: private static POILogger log = POILogFactory
041: .getLogger(ListTables.class);
042:
043: HashMap _listMap = new HashMap();
044: ArrayList _overrideList = new ArrayList();
045:
046: public ListTables() {
047:
048: }
049:
050: public ListTables(byte[] tableStream, int lstOffset, int lfoOffset) {
051: // get the list data
052: int length = LittleEndian.getShort(tableStream, lstOffset);
053: lstOffset += LittleEndian.SHORT_SIZE;
054: int levelOffset = lstOffset + (length * LIST_DATA_SIZE);
055:
056: for (int x = 0; x < length; x++) {
057: ListData lst = new ListData(tableStream, lstOffset);
058: _listMap.put(new Integer(lst.getLsid()), lst);
059: lstOffset += LIST_DATA_SIZE;
060:
061: int num = lst.numLevels();
062: for (int y = 0; y < num; y++) {
063: ListLevel lvl = new ListLevel(tableStream, levelOffset);
064: lst.setLevel(y, lvl);
065: levelOffset += lvl.getSizeInBytes();
066: }
067: }
068:
069: // now get the list format overrides. The size is an int unlike the LST size
070: length = LittleEndian.getInt(tableStream, lfoOffset);
071: lfoOffset += LittleEndian.INT_SIZE;
072: int lfolvlOffset = lfoOffset
073: + (LIST_FORMAT_OVERRIDE_SIZE * length);
074: for (int x = 0; x < length; x++) {
075: ListFormatOverride lfo = new ListFormatOverride(
076: tableStream, lfoOffset);
077: lfoOffset += LIST_FORMAT_OVERRIDE_SIZE;
078: int num = lfo.numOverrides();
079: for (int y = 0; y < num; y++) {
080: while (tableStream[lfolvlOffset] == -1) {
081: lfolvlOffset++;
082: }
083: ListFormatOverrideLevel lfolvl = new ListFormatOverrideLevel(
084: tableStream, lfolvlOffset);
085: lfo.setOverride(y, lfolvl);
086: lfolvlOffset += lfolvl.getSizeInBytes();
087: }
088: _overrideList.add(lfo);
089: }
090: }
091:
092: public int addList(ListData lst, ListFormatOverride override) {
093: int lsid = lst.getLsid();
094: while (_listMap.get(new Integer(lsid)) != null) {
095: lsid = lst.resetListID();
096: override.setLsid(lsid);
097: }
098: _listMap.put(new Integer(lsid), lst);
099: _overrideList.add(override);
100: return lsid;
101: }
102:
103: public void writeListDataTo(HWPFOutputStream tableStream)
104: throws IOException {
105:
106: Integer[] intList = (Integer[]) _listMap.keySet().toArray(
107: new Integer[0]);
108:
109: // use this stream as a buffer for the levels since their size varies.
110: ByteArrayOutputStream levelBuf = new ByteArrayOutputStream();
111:
112: // use a byte array for the lists because we know their size.
113: byte[] listBuf = new byte[intList.length * LIST_DATA_SIZE];
114:
115: byte[] shortHolder = new byte[2];
116: LittleEndian.putShort(shortHolder, (short) intList.length);
117: tableStream.write(shortHolder);
118:
119: for (int x = 0; x < intList.length; x++) {
120: ListData lst = (ListData) _listMap.get(intList[x]);
121: tableStream.write(lst.toByteArray());
122: ListLevel[] lvls = lst.getLevels();
123: for (int y = 0; y < lvls.length; y++) {
124: levelBuf.write(lvls[y].toByteArray());
125: }
126: }
127: tableStream.write(levelBuf.toByteArray());
128: }
129:
130: public void writeListOverridesTo(HWPFOutputStream tableStream)
131: throws IOException {
132:
133: // use this stream as a buffer for the levels since their size varies.
134: ByteArrayOutputStream levelBuf = new ByteArrayOutputStream();
135:
136: int size = _overrideList.size();
137:
138: byte[] intHolder = new byte[4];
139: LittleEndian.putInt(intHolder, size);
140: tableStream.write(intHolder);
141:
142: for (int x = 0; x < size; x++) {
143: ListFormatOverride lfo = (ListFormatOverride) _overrideList
144: .get(x);
145: tableStream.write(lfo.toByteArray());
146: ListFormatOverrideLevel[] lfolvls = lfo.getLevelOverrides();
147: for (int y = 0; y < lfolvls.length; y++) {
148: levelBuf.write(lfolvls[y].toByteArray());
149: }
150: }
151: tableStream.write(levelBuf.toByteArray());
152:
153: }
154:
155: public ListFormatOverride getOverride(int lfoIndex) {
156: return (ListFormatOverride) _overrideList.get(lfoIndex - 1);
157: }
158:
159: public int getOverrideIndexFromListID(int lstid) {
160: int returnVal = -1;
161: int size = _overrideList.size();
162: for (int x = 0; x < size; x++) {
163: ListFormatOverride next = (ListFormatOverride) _overrideList
164: .get(x);
165: if (next.getLsid() == lstid) {
166: // 1-based index I think
167: returnVal = x + 1;
168: break;
169: }
170: }
171: if (returnVal == -1) {
172: throw new NoSuchElementException(
173: "No list found with the specified ID");
174: }
175: return returnVal;
176: }
177:
178: public ListLevel getLevel(int listID, int level) {
179: ListData lst = (ListData) _listMap.get(new Integer(listID));
180: if (level < lst.numLevels()) {
181: ListLevel lvl = lst.getLevels()[level];
182: return lvl;
183: } else {
184: log.log(POILogger.WARN, "Requested level " + level
185: + " which was greater than the maximum defined ("
186: + lst.numLevels() + ")");
187: return null;
188: }
189: }
190:
191: public ListData getListData(int listID) {
192: return (ListData) _listMap.get(new Integer(listID));
193: }
194:
195: public boolean equals(Object obj) {
196: if (obj == null) {
197: return false;
198: }
199:
200: ListTables tables = (ListTables) obj;
201:
202: if (_listMap.size() == tables._listMap.size()) {
203: Iterator it = _listMap.keySet().iterator();
204: while (it.hasNext()) {
205: Object key = it.next();
206: ListData lst1 = (ListData) _listMap.get(key);
207: ListData lst2 = (ListData) tables._listMap.get(key);
208: if (!lst1.equals(lst2)) {
209: return false;
210: }
211: }
212: int size = _overrideList.size();
213: if (size == tables._overrideList.size()) {
214: for (int x = 0; x < size; x++) {
215: if (!_overrideList.get(x).equals(
216: tables._overrideList.get(x))) {
217: return false;
218: }
219: }
220: return true;
221: }
222: }
223: return false;
224: }
225: }
|