?? section.java
字號:
/* ==================================================================== Copyright 2002-2004 Apache Software Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.==================================================================== */ package org.apache.poi.hpsf;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.Collections;import java.util.Iterator;import java.util.List;import java.util.Map;import org.apache.poi.hpsf.wellknown.PropertyIDMap;import org.apache.poi.hpsf.wellknown.SectionIDMap;import org.apache.poi.util.LittleEndian;/** * <p>Represents a section in a {@link PropertySet}.</p> * * @author Rainer Klute <a * href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a> * @author Drew Varner (Drew.Varner allUpIn sc.edu) * @version $Id: Section.java,v 1.24 2004/08/15 13:43:35 klute Exp $ * @since 2002-02-09 */public class Section{ /** * <p>Maps property IDs to section-private PID strings. These * strings can be found in the property with ID 0.</p> */ protected Map dictionary; /** * <p>The section's format ID, {@link #getFormatID}.</p> */ protected ClassID formatID; /** * <p>Returns the format ID. The format ID is the "type" of the * section. For example, if the format ID of the first {@link * Section} contains the bytes specified by * <code>org.apache.poi.hpsf.wellknown.SectionIDMap.SUMMARY_INFORMATION_ID</code> * the section (and thus the property set) is a SummaryInformation.</p> * * @return The format ID */ public ClassID getFormatID() { return formatID; } /** * @see #getOffset */ protected long offset; /** * <p>Returns the offset of the section in the stream.</p> * * @return The offset of the section in the stream. */ public long getOffset() { return offset; } /** * @see #getSize */ protected int size; /** * <p>Returns the section's size in bytes.</p> * * @return The section's size in bytes. */ public int getSize() { return size; } /** * <p>Returns the number of properties in this section.</p> * * @return The number of properties in this section. */ public int getPropertyCount() { return properties.length; } /** * @see #getProperties */ protected Property[] properties; /** * <p>Returns this section's properties.</p> * * @return This section's properties. */ public Property[] getProperties() { return properties; } /** * <p>Creates an empty and uninitialized {@link Section}. */ protected Section() { } /** * <p>Creates a {@link Section} instance from a byte array.</p> * * @param src Contains the complete property set stream. * @param offset The position in the stream that points to the * section's format ID. * * @exception UnsupportedEncodingException if the section's codepage is not * supported. */ public Section(final byte[] src, final int offset) throws UnsupportedEncodingException { int o1 = offset; /* * Read the format ID. */ formatID = new ClassID(src, o1); o1 += ClassID.LENGTH; /* * Read the offset from the stream's start and positions to * the section header. */ this.offset = LittleEndian.getUInt(src, o1); o1 = (int) this.offset; /* * Read the section length. */ size = (int) LittleEndian.getUInt(src, o1); o1 += LittleEndian.INT_SIZE; /* * Read the number of properties. */ final int propertyCount = (int) LittleEndian.getUInt(src, o1); o1 += LittleEndian.INT_SIZE; /* * Read the properties. The offset is positioned at the first * entry of the property list. There are two problems: * * 1. For each property we have to find out its length. In the * property list we find each property's ID and its offset relative * to the section's beginning. Unfortunately the properties in the * property list need not to be in ascending order, so it is not * possible to calculate the length as * (offset of property(i+1) - offset of property(i)). Before we can * that we first have to sort the property list by ascending offsets. * * 2. We have to read the property with ID 1 before we read other * properties, at least before other properties containing strings. * The reason is that property 1 specifies the codepage. If it is * 1200, all strings are in Unicode. In other words: Before we can * read any strings we have to know whether they are in Unicode or * not. Unfortunately property 1 is not guaranteed to be the first in * a section. * * The algorithm below reads the properties in two passes: The first * one looks for property ID 1 and extracts the codepage number. The * seconds pass reads the other properties. */ properties = new Property[propertyCount]; /* Pass 1: Read the property list. */ int pass1Offset = o1; List propertyList = new ArrayList(propertyCount); PropertyListEntry ple; for (int i = 0; i < properties.length; i++) { ple = new PropertyListEntry(); /* Read the property ID. */ ple.id = (int) LittleEndian.getUInt(src, pass1Offset); pass1Offset += LittleEndian.INT_SIZE; /* Offset from the section's start. */ ple.offset = (int) LittleEndian.getUInt(src, pass1Offset); pass1Offset += LittleEndian.INT_SIZE; /* Add the entry to the property list. */ propertyList.add(ple); } /* Sort the property list by ascending offsets: */ Collections.sort(propertyList); /* Calculate the properties' lengths. */ for (int i = 0; i < propertyCount - 1; i++) { final PropertyListEntry ple1 = (PropertyListEntry) propertyList.get(i); final PropertyListEntry ple2 = (PropertyListEntry) propertyList.get(i + 1); ple1.length = ple2.offset - ple1.offset; } if (propertyCount > 0) { ple = (PropertyListEntry) propertyList.get(propertyCount - 1); ple.length = size - ple.offset; } /* Look for the codepage. */ int codepage = -1; for (final Iterator i = propertyList.iterator(); codepage == -1 && i.hasNext();) { ple = (PropertyListEntry) i.next(); /* Read the codepage if the property ID is 1. */ if (ple.id == PropertyIDMap.PID_CODEPAGE) { /* Read the property's value type. It must be * VT_I2. */ int o = (int) (this.offset + ple.offset); final long type = LittleEndian.getUInt(src, o); o += LittleEndian.INT_SIZE; if (type != Variant.VT_I2) throw new HPSFRuntimeException ("Value type of property ID 1 is not VT_I2 but " + type + "."); /* Read the codepage number. */ codepage = LittleEndian.getUShort(src, o); } } /* Pass 2: Read all properties - including the codepage property, * if available. */ int i1 = 0; for (final Iterator i = propertyList.iterator(); i.hasNext();) { ple = (PropertyListEntry) i.next(); properties[i1++] = new Property(ple.id, src, this.offset + ple.offset, ple.length, codepage); } /* * Extract the dictionary (if available). */ dictionary = (Map) getProperty(0); } /** * <p>Represents an entry in the property list and holds a property's ID and * its offset from the section's beginning.</p> */ class PropertyListEntry implements Comparable { int id; int offset; int length; /** * <p>Compares this {@link PropertyListEntry} with another one by their * offsets. A {@link PropertyListEntry} is "smaller" than another one if * its offset from the section's begin is smaller.</p> * * @see Comparable#compareTo(java.lang.Object) */ public int compareTo(final Object o) { if (!(o instanceof PropertyListEntry)) throw new ClassCastException(o.toString()); final int otherOffset = ((PropertyListEntry) o).offset; if (offset < otherOffset) return -1; else if (offset == otherOffset)
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -