123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You 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.ByteArrayInputStream;
- import java.io.ByteArrayOutputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.UnsupportedEncodingException;
- import java.util.Iterator;
- import java.util.LinkedList;
- import java.util.ListIterator;
-
- import org.apache.poi.poifs.filesystem.DirectoryEntry;
- import org.apache.poi.poifs.filesystem.Entry;
- import org.apache.poi.util.LittleEndian;
- import org.apache.poi.util.LittleEndianConsts;
-
- /**
- * <p>Adds writing support to the {@link PropertySet} class.</p>
- *
- * <p>Please be aware that this class' functionality will be merged into the
- * {@link PropertySet} class at a later time, so the API will change.</p>
- *
- * @author Rainer Klute <a
- * href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
- */
- public class MutablePropertySet extends PropertySet
- {
-
- /**
- * <p>Constructs a <code>MutablePropertySet</code> instance. Its
- * primary task is to initialize the immutable field with their proper
- * values. It also sets fields that might change to reasonable defaults.</p>
- */
- public MutablePropertySet()
- {
- /* Initialize the "byteOrder" field. */
- byteOrder = LittleEndian.getUShort(BYTE_ORDER_ASSERTION);
-
- /* Initialize the "format" field. */
- format = LittleEndian.getUShort(FORMAT_ASSERTION);
-
- /* Initialize "osVersion" field as if the property has been created on
- * a Win32 platform, whether this is the case or not. */
- osVersion = (OS_WIN32 << 16) | 0x0A04;
-
- /* Initailize the "classID" field. */
- classID = new ClassID();
-
- /* Initialize the sections. Since property set must have at least
- * one section it is added right here. */
- sections = new LinkedList();
- sections.add(new MutableSection());
- }
-
-
-
- /**
- * <p>Constructs a <code>MutablePropertySet</code> by doing a deep copy of
- * an existing <code>PropertySet</code>. All nested elements, i.e.
- * <code>Section</code>s and <code>Property</code> instances, will be their
- * mutable counterparts in the new <code>MutablePropertySet</code>.</p>
- *
- * @param ps The property set to copy
- */
- public MutablePropertySet(final PropertySet ps)
- {
- byteOrder = ps.getByteOrder();
- format = ps.getFormat();
- osVersion = ps.getOSVersion();
- setClassID(ps.getClassID());
- clearSections();
- if (sections == null)
- sections = new LinkedList();
- for (final Iterator i = ps.getSections().iterator(); i.hasNext();)
- {
- final MutableSection s = new MutableSection((Section) (i.next()));
- addSection(s);
- }
- }
-
-
-
- /**
- * <p>The length of the property set stream header.</p>
- */
- private final int OFFSET_HEADER =
- BYTE_ORDER_ASSERTION.length + /* Byte order */
- FORMAT_ASSERTION.length + /* Format */
- LittleEndianConsts.INT_SIZE + /* OS version */
- ClassID.LENGTH + /* Class ID */
- LittleEndianConsts.INT_SIZE; /* Section count */
-
-
-
- /**
- * <p>Sets the "byteOrder" property.</p>
- *
- * @param byteOrder the byteOrder value to set
- */
- public void setByteOrder(final int byteOrder)
- {
- this.byteOrder = byteOrder;
- }
-
-
-
- /**
- * <p>Sets the "format" property.</p>
- *
- * @param format the format value to set
- */
- public void setFormat(final int format)
- {
- this.format = format;
- }
-
-
-
- /**
- * <p>Sets the "osVersion" property.</p>
- *
- * @param osVersion the osVersion value to set
- */
- public void setOSVersion(final int osVersion)
- {
- this.osVersion = osVersion;
- }
-
-
-
- /**
- * <p>Sets the property set stream's low-level "class ID"
- * field.</p>
- *
- * @param classID The property set stream's low-level "class ID" field.
- *
- * @see PropertySet#getClassID()
- */
- public void setClassID(final ClassID classID)
- {
- this.classID = classID;
- }
-
-
-
- /**
- * <p>Removes all sections from this property set.</p>
- */
- public void clearSections()
- {
- sections = null;
- }
-
-
-
- /**
- * <p>Adds a section to this property set.</p>
- *
- * @param section The {@link Section} to add. It will be appended
- * after any sections that are already present in the property set
- * and thus become the last section.
- */
- public void addSection(final Section section)
- {
- if (sections == null)
- sections = new LinkedList();
- sections.add(section);
- }
-
-
-
- /**
- * <p>Writes the property set to an output stream.</p>
- *
- * @param out the output stream to write the section to
- * @exception IOException if an error when writing to the output stream
- * occurs
- * @exception WritingNotSupportedException if HPSF does not yet support
- * writing a property's variant type.
- */
- public void write(final OutputStream out)
- throws WritingNotSupportedException, IOException
- {
- /* Write the number of sections in this property set stream. */
- final int nrSections = sections.size();
- int length = 0;
-
- /* Write the property set's header. */
- length += TypeWriter.writeToStream(out, (short) getByteOrder());
- length += TypeWriter.writeToStream(out, (short) getFormat());
- length += TypeWriter.writeToStream(out, getOSVersion());
- length += TypeWriter.writeToStream(out, getClassID());
- length += TypeWriter.writeToStream(out, nrSections);
- int offset = OFFSET_HEADER;
-
- /* Write the section list, i.e. the references to the sections. Each
- * entry in the section list consist of the section's class ID and the
- * section's offset relative to the beginning of the stream. */
- offset += nrSections * (ClassID.LENGTH + LittleEndian.INT_SIZE);
- final int sectionsBegin = offset;
- for (final ListIterator i = sections.listIterator(); i.hasNext();)
- {
- final MutableSection s = (MutableSection) i.next();
- final ClassID formatID = s.getFormatID();
- if (formatID == null)
- throw new NoFormatIDException();
- length += TypeWriter.writeToStream(out, s.getFormatID());
- length += TypeWriter.writeUIntToStream(out, offset);
- try
- {
- offset += s.getSize();
- }
- catch (HPSFRuntimeException ex)
- {
- final Throwable cause = ex.getReason();
- if (cause instanceof UnsupportedEncodingException) {
- throw new IllegalPropertySetDataException(cause);
- }
- throw ex;
- }
- }
-
- /* Write the sections themselves. */
- offset = sectionsBegin;
- for (final ListIterator i = sections.listIterator(); i.hasNext();)
- {
- final MutableSection s = (MutableSection) i.next();
- offset += s.write(out);
- }
- }
-
-
-
- /**
- * <p>Returns the contents of this property set stream as an input stream.
- * The latter can be used for example to write the property set into a POIFS
- * document. The input stream represents a snapshot of the property set.
- * If the latter is modified while the input stream is still being
- * read, the modifications will not be reflected in the input stream but in
- * the {@link MutablePropertySet} only.</p>
- *
- * @return the contents of this property set stream
- *
- * @throws WritingNotSupportedException if HPSF does not yet support writing
- * of a property's variant type.
- * @throws IOException if an I/O exception occurs.
- */
- public InputStream toInputStream()
- throws IOException, WritingNotSupportedException
- {
- final ByteArrayOutputStream psStream = new ByteArrayOutputStream();
- write(psStream);
- psStream.close();
- final byte[] streamData = psStream.toByteArray();
- return new ByteArrayInputStream(streamData);
- }
-
- /**
- * <p>Writes a property set to a document in a POI filesystem directory.</p>
- *
- * @param dir The directory in the POI filesystem to write the document to.
- * @param name The document's name. If there is already a document with the
- * same name in the directory the latter will be overwritten.
- *
- * @throws WritingNotSupportedException
- * @throws IOException
- */
- public void write(final DirectoryEntry dir, final String name)
- throws WritingNotSupportedException, IOException
- {
- /* If there is already an entry with the same name, remove it. */
- try
- {
- final Entry e = dir.getEntry(name);
- e.delete();
- }
- catch (FileNotFoundException ex)
- {
- /* Entry not found, no need to remove it. */
- }
- /* Create the new entry. */
- dir.createDocument(name, toInputStream());
- }
-
- }
|