* Writing support added to the SummaryInformation and DocumentSummaryInformation classes. These classes now have methods for setting and removing properties. Coherent extensions are:
** Documentation section about writing standard properties added to the HPSF HOW-TO. ** Example application added showing how to modify the document summary information. ** Testcases added for testing modifying summary information and document summary information. ** PropertySetFactory extended to create SummaryInformation and DocumentSummaryInformation instances. * Added MutablePropertySet.write(DirectoryEntry, String) to ease writing a property set to a POI filesystem document. * Improved codepage handling. * Bug fixed: Integral values were read and written as unsigned instead of signed. * Reworked the mapping between variant types and Java types: Variant.VT_I4 is mapped to Integer now and Variant.VT_I8 to Long. This might cause incompatibilities if you are doing low-level HPSF programming. * Changed SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID from a byte[] to a byte[][] in order to contain the format ID of the first and the second section. This is an incompatible change! * Added PropertySet.getFirstSection(). This method is similar to getSingleSection() won't choke if the property set has more than one section. * Support for low-level reading and writing of Variant.VT_I8 type properties added. * Unnecessary casts removed. * Poibrowser's display format changed slightly. git-svn-id: https://svn.apache.org/repos/asf/jakarta/poi/trunk@382887 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a7f8720bad
commit
bb7ebd3492
@ -128,7 +128,7 @@ public class POIBrowser extends JFrame
|
|||||||
new PropertySetDescriptorRenderer());
|
new PropertySetDescriptorRenderer());
|
||||||
treeUI.setCellRenderer(etcr);
|
treeUI.setCellRenderer(etcr);
|
||||||
setSize(600, 450);
|
setSize(600, 450);
|
||||||
setTitle("POI Browser 0.08");
|
setTitle("POI Browser 0.09");
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,7 +25,6 @@ import org.apache.poi.hpsf.MarkUnsupportedException;
|
|||||||
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
||||||
import org.apache.poi.hpsf.PropertySet;
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
import org.apache.poi.hpsf.PropertySetFactory;
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
|
|
||||||
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
|
import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
|
||||||
|
|
||||||
@ -70,7 +69,7 @@ public class PropertySetDescriptor extends DocumentDescriptor
|
|||||||
final POIFSDocumentPath path,
|
final POIFSDocumentPath path,
|
||||||
final DocumentInputStream stream,
|
final DocumentInputStream stream,
|
||||||
final int nrOfBytesToDump)
|
final int nrOfBytesToDump)
|
||||||
throws UnexpectedPropertySetTypeException, NoPropertySetStreamException,
|
throws NoPropertySetStreamException,
|
||||||
MarkUnsupportedException, UnsupportedEncodingException,
|
MarkUnsupportedException, UnsupportedEncodingException,
|
||||||
IOException
|
IOException
|
||||||
{
|
{
|
||||||
|
@ -127,6 +127,9 @@ public class PropertySetDescriptorRenderer extends DocumentDescriptorRenderer
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns a string representation of a {@link Section}.</p>
|
* <p>Returns a string representation of a {@link Section}.</p>
|
||||||
|
* @param s the section
|
||||||
|
* @param name the section's name
|
||||||
|
* @return a string representation of the {@link Section}
|
||||||
*/
|
*/
|
||||||
protected String toString(final Section s, final String name)
|
protected String toString(final Section s, final String name)
|
||||||
{
|
{
|
||||||
@ -141,12 +144,18 @@ public class PropertySetDescriptorRenderer extends DocumentDescriptorRenderer
|
|||||||
for (int i = 0; i < properties.length; i++)
|
for (int i = 0; i < properties.length; i++)
|
||||||
{
|
{
|
||||||
final Property p = properties[i];
|
final Property p = properties[i];
|
||||||
|
final long id = p.getID();
|
||||||
|
final long type = p.getType();
|
||||||
final Object value = p.getValue();
|
final Object value = p.getValue();
|
||||||
b.append("\n" + name + " ");
|
b.append('\n');
|
||||||
b.append("PID_");
|
b.append(name);
|
||||||
b.append(p.getID());
|
b.append(", Name: ");
|
||||||
b.append(' ');
|
b.append(id);
|
||||||
b.append(s.getPIDString(p.getID()) + ": ");
|
b.append(" (");
|
||||||
|
b.append(s.getPIDString(id));
|
||||||
|
b.append("), Type: ");
|
||||||
|
b.append(type);
|
||||||
|
b.append(", Value: ");
|
||||||
if (value instanceof byte[])
|
if (value instanceof byte[])
|
||||||
{
|
{
|
||||||
byte[] b2 = (byte[]) value;
|
byte[] b2 = (byte[]) value;
|
||||||
|
@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
The <link href="#sec1">first section</link> explains how to read
|
The <link href="#sec1">first section</link> explains how to <strong>read
|
||||||
the most important standard properties of a Microsoft Office
|
the most important standard properties</strong> of a Microsoft Office
|
||||||
document. Standard properties are things like title, author, creation
|
document. Standard properties are things like title, author, creation
|
||||||
date etc. It is quite likely that you will find here what you need and
|
date etc. It is quite likely that you will find here what you need and
|
||||||
don't have to read the other sections.
|
don't have to read the other sections.
|
||||||
@ -28,58 +28,78 @@
|
|||||||
|
|
||||||
<li>
|
<li>
|
||||||
The <link href="#sec2">second section</link> goes a small step
|
The <link href="#sec2">second section</link> goes a small step
|
||||||
further and focusses on reading additional standard properties. It also
|
further and focusses on <strong>reading additional standard
|
||||||
talks about exceptions that may be thrown when dealing with HPSF and
|
properties</strong>. It also talks about <strong>exceptions</strong> that
|
||||||
shows how you can read properties of embedded objects.
|
may be thrown when dealing with HPSF and shows how you can <strong>read
|
||||||
|
properties of embedded objects</strong>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
The <link href="#sec3">third section</link> tells how to read
|
The <link href="#sec3">third section</link> explains how to <strong>write
|
||||||
non-standard properties. Non-standard properties are application-specific
|
standard properties</strong>. HPSF provides some high-level classes and
|
||||||
triples consisting of an ID, a type, and a value.
|
methods which make writing of standard properties easy. They are based on
|
||||||
|
the low-level writing functions explained in the <link href="#sec3">fifth
|
||||||
|
section</link>.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
The <link href="#sec4">fourth section</link> tells you how to write
|
The <link href="#sec4">fourth section</link> tells how to <strong>read
|
||||||
property set streams. At this time HPSF provides low-level methods only
|
non-standard properties</strong>. Non-standard properties are
|
||||||
for writing properties. Therefore you have to understand the <link
|
application-specific triples consisting of an ID, a type, and a value.
|
||||||
href="#sec3">third section</link> before you should think about writing
|
</li>
|
||||||
properties. Check the Javadoc API documentation to find out about the
|
|
||||||
details! <strong>Please note:</strong> HPSF's writing functionality is
|
<li>
|
||||||
<strong>not</strong> present in POI releases up to and including 2.5. In
|
The <link href="#sec5">fifth section</link> tells you how to <strong>write
|
||||||
order to write properties you have to download a later POI release (when
|
property set streams</strong> using HPSF's low-level methods. You have to
|
||||||
available) or retrieve the POI development version from the Subversion
|
understand the <link href="#sec3">fourth section</link> before you should
|
||||||
repository.
|
think about low-level writing properties. Check the Javadoc API
|
||||||
|
documentation to find out about the details!
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<note><strong>Please note:</strong> HPSF's writing functionality is
|
||||||
|
<strong>not</strong> present in POI releases up to and including 2.5. In
|
||||||
|
order to write properties you have to download a later POI release (when
|
||||||
|
available) or retrieve the POI development version from the <link
|
||||||
|
href="http://jakarta.apache.org/site/cvsindex.html">Subversion
|
||||||
|
repository</link>.</note>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<anchor id="sec1"/>
|
<anchor id="sec1"/>
|
||||||
<section><title>Reading Standard Properties</title>
|
<section><title>Reading Standard Properties</title>
|
||||||
|
|
||||||
<note>This section explains how to read
|
<note>This section explains how to read the most important standard
|
||||||
the most important standard properties of a Microsoft Office
|
properties of a Microsoft Office document. Standard properties are things
|
||||||
document. Standard properties are things like title, author, creation
|
like title, author, creation date etc. This section introduces the
|
||||||
date etc. Chances are that you will find here what you need and
|
<strong>summary information stream</strong> which is used to keep these
|
||||||
don't have to read the other sections.</note>
|
properties. Chances are that you will find here what you need and don't
|
||||||
|
have to read the other sections.</note>
|
||||||
|
|
||||||
<p>The first thing you should understand is that properties are stored in
|
<p>The first thing you should understand is that a Microsoft Office file is
|
||||||
separate documents inside the POI filesystem. (If you don't know what a
|
not one large bunch of bytes but has an internal filesystem structure with
|
||||||
POI filesystem is, read the <link href="../poifs/index.html">POIFS
|
files and directories. You can access these files and directories using
|
||||||
documentation</link>.) A document in a POI filesystem is also called a
|
the <link href="../poifs/index.html">POI filesystem (POIFS)</link>
|
||||||
<strong>stream</strong>.</p>
|
provides. A file or document in a POI filesystem is also called a
|
||||||
|
<strong>stream</strong> - The properties of, say, an Excel document are
|
||||||
|
stored apart of the actual spreadsheet data in separate streams. The good
|
||||||
|
new is that this separation makes the properties independent of the
|
||||||
|
concrete Microsoft Office file. In the following text we will always say
|
||||||
|
"POI filesystem" instead of "Microsoft Office file" because a POI
|
||||||
|
filesystem is not necessarily created by or for a Microsoft Office
|
||||||
|
application, because it is shorter, and because we want to avoid the name
|
||||||
|
of That Redmond Company.</p>
|
||||||
|
|
||||||
<p>The following example shows how to read a POI filesystem's
|
<p>The following example shows how to read the "title" property. Reading
|
||||||
"title" property. Reading other properties is similar. Consider the API
|
other properties is similar. Consider the API documentation of the class
|
||||||
documentation of <code>org.apache.poi.hpsf.SummaryInformation</code> to
|
<code>org.apache.poi.hpsf.SummaryInformation</code> to learn which methods
|
||||||
learn which methods are available!</p>
|
are available.</p>
|
||||||
|
|
||||||
<p>The standard properties this section focusses on can be found in a
|
<p>The standard properties this section focusses on can be found in a
|
||||||
document called <em>\005SummaryInformation</em> located in the root of the
|
document called <em>\005SummaryInformation</em> located in the root of the
|
||||||
POI filesystem. The notation <em>\005</em> in the document's name means
|
POI filesystem. The notation <em>\005</em> in the document's name means
|
||||||
the character with the decimal value of 5. In order to read the title, an
|
the character with a decimal value of 5. In order to read the "title"
|
||||||
application has to perform the following steps:</p>
|
property, an application has to perform the following steps:</p>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
@ -103,7 +123,7 @@
|
|||||||
POI filesystem</title>
|
POI filesystem</title>
|
||||||
|
|
||||||
<p>An application that wants to open a document in a POI filesystem
|
<p>An application that wants to open a document in a POI filesystem
|
||||||
(POIFS) proceeds as shown by the following code fragment. (The full
|
(POIFS) proceeds as shown by the following code fragment. The full
|
||||||
source code of the sample application is available in the
|
source code of the sample application is available in the
|
||||||
<em>examples</em> section of the POI source tree as
|
<em>examples</em> section of the POI source tree as
|
||||||
<em>ReadTitle.java</em>.</p>
|
<em>ReadTitle.java</em>.</p>
|
||||||
@ -144,14 +164,15 @@ r.registerListener(new MyPOIFSReaderListener(),
|
|||||||
<p>This method call registers a
|
<p>This method call registers a
|
||||||
<code>org.apache.poi.poifs.eventfilesystem.POIFSReaderListener</code>
|
<code>org.apache.poi.poifs.eventfilesystem.POIFSReaderListener</code>
|
||||||
with the <code>POIFSReader</code>. The <code>POIFSReaderListener</code>
|
with the <code>POIFSReader</code>. The <code>POIFSReaderListener</code>
|
||||||
interface specifies the method <code>processPOIFSReaderEvent</code>
|
interface specifies the method <code>processPOIFSReaderEvent()</code>
|
||||||
which processes a document. The class
|
which processes a document. The class
|
||||||
<code>MyPOIFSReaderListener</code> implements the
|
<code>MyPOIFSReaderListener</code> implements the
|
||||||
<code>POIFSReaderListener</code> and thus the
|
<code>POIFSReaderListener</code> and thus the
|
||||||
<code>processPOIFSReaderEvent</code> method. The eventing POI filesystem
|
<code>processPOIFSReaderEvent()</code> method. The eventing POI
|
||||||
calls this method when it finds the <em>\005SummaryInformation</em>
|
filesystem calls this method when it finds the
|
||||||
document. In the sample application <code>MyPOIFSReaderListener</code> is
|
<em>\005SummaryInformation</em> document. In the sample application
|
||||||
a static class in the <em>ReadTitle.java</em> source file.</p>
|
<code>MyPOIFSReaderListener</code> is a static class in the
|
||||||
|
<em>ReadTitle.java</em> source file.</p>
|
||||||
|
|
||||||
<p>Now everything is prepared and reading the POI filesystem can
|
<p>Now everything is prepared and reading the POI filesystem can
|
||||||
start:</p>
|
start:</p>
|
||||||
@ -209,7 +230,7 @@ static class MyPOIFSReaderListener implements POIFSReaderListener
|
|||||||
convenience class with methods like <code>getTitle()</code>,
|
convenience class with methods like <code>getTitle()</code>,
|
||||||
<code>getAuthor()</code> etc.</p>
|
<code>getAuthor()</code> etc.</p>
|
||||||
|
|
||||||
<p>The <code>PropertySetFactory.create</code> method may throw all sorts
|
<p>The <code>PropertySetFactory.create()</code> method may throw all sorts
|
||||||
of exceptions. We'll deal with them in the next sections. For now we just
|
of exceptions. We'll deal with them in the next sections. For now we just
|
||||||
catch all exceptions and throw a <code>RuntimeException</code>
|
catch all exceptions and throw a <code>RuntimeException</code>
|
||||||
containing the message text of the origin exception.</p>
|
containing the message text of the origin exception.</p>
|
||||||
@ -224,10 +245,10 @@ if (title != null)
|
|||||||
else
|
else
|
||||||
System.out.println("Document has no title.");</source>
|
System.out.println("Document has no title.");</source>
|
||||||
|
|
||||||
<p>Please note that a Microsoft Office document does not necessarily
|
<p>Please note that a POI filesystem does not necessarily contain the
|
||||||
contain the <em>\005SummaryInformation</em> stream. The documents created
|
<em>\005SummaryInformation</em> stream. The documents created by the
|
||||||
by the Microsoft Office suite have one, as far as I know. However, an
|
Microsoft Office suite have one, as far as I know. However, an Excel
|
||||||
Excel spreadsheet exported from StarOffice 5.2 won't have a
|
spreadsheet exported from StarOffice 5.2 won't have a
|
||||||
<em>\005SummaryInformation</em> stream. In this case the applications
|
<em>\005SummaryInformation</em> stream. In this case the applications
|
||||||
won't throw an exception but simply does not call the
|
won't throw an exception but simply does not call the
|
||||||
<code>processPOIFSReaderEvent</code> method. You have been warned!</p>
|
<code>processPOIFSReaderEvent</code> method. You have been warned!</p>
|
||||||
@ -238,14 +259,16 @@ else
|
|||||||
<section><title>Additional Standard Properties, Exceptions And Embedded
|
<section><title>Additional Standard Properties, Exceptions And Embedded
|
||||||
Objects</title>
|
Objects</title>
|
||||||
|
|
||||||
<note>This section focusses on reading additional standard properties. It
|
<note>This section focusses on reading additional standard properties which
|
||||||
|
are kept in the <strong>document summary information</strong> stream. It
|
||||||
also talks about exceptions that may be thrown when dealing with HPSF and
|
also talks about exceptions that may be thrown when dealing with HPSF and
|
||||||
shows how you can read properties of embedded objects.</note>
|
shows how you can read properties of embedded objects.</note>
|
||||||
|
|
||||||
<p>A couple of <strong>additional standard properties</strong> are not
|
<p>A couple of <strong>additional standard properties</strong> are not
|
||||||
contained in the <em>\005SummaryInformation</em> stream explained above,
|
contained in the <em>\005SummaryInformation</em> stream explained
|
||||||
for example a document's category or the number of multimedia clips in a
|
above. Examples for such properties are a document's category or the
|
||||||
PowerPoint presentation. Microsoft has invented an additional stream named
|
number of multimedia clips in a PowerPoint presentation. Microsoft has
|
||||||
|
invented an additional stream named
|
||||||
<em>\005DocumentSummaryInformation</em> to hold these properties. With two
|
<em>\005DocumentSummaryInformation</em> to hold these properties. With two
|
||||||
minor exceptions you can proceed exactly as described above to read the
|
minor exceptions you can proceed exactly as described above to read the
|
||||||
properties stored in <em>\005DocumentSummaryInformation</em>:</p>
|
properties stored in <em>\005DocumentSummaryInformation</em>:</p>
|
||||||
@ -259,13 +282,14 @@ else
|
|||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<p>And of course you cannot call <code>getTitle()</code> because
|
<p>And of course you cannot call <code>getTitle()</code> because
|
||||||
<code>DocumentSummaryInformation</code> has different query methods. See
|
<code>DocumentSummaryInformation</code> has different query methods,
|
||||||
the Javadoc API documentation for the details!</p>
|
e.g. <code>getCategory</code>. See the Javadoc API documentation for the
|
||||||
|
details.</p>
|
||||||
|
|
||||||
<p>In the previous section the application simply caught all
|
<p>In the previous section the application simply caught all
|
||||||
<strong>exceptions</strong> and was in no way interested in any
|
<strong>exceptions</strong> and was in no way interested in any
|
||||||
details. However, a real application will likely want to know what went
|
details. However, a real application will likely want to know what went
|
||||||
wrong and act appropriately. Besides any IO exceptions there are three
|
wrong and act appropriately. Besides any I/O exceptions there are three
|
||||||
HPSF resp. POI specific exceptions you should know about:</p>
|
HPSF resp. POI specific exceptions you should know about:</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
@ -279,9 +303,9 @@ else
|
|||||||
being a property set stream at all. An application should be prepared to
|
being a property set stream at all. An application should be prepared to
|
||||||
deal with this case even if it opens streams named
|
deal with this case even if it opens streams named
|
||||||
<em>\005SummaryInformation</em> or
|
<em>\005SummaryInformation</em> or
|
||||||
<em>\005DocumentSummaryInformation</em> only. These are just names. A
|
<em>\005DocumentSummaryInformation</em>. These are just names. A
|
||||||
stream's name by itself does not ensure that the stream contains the
|
stream's name by itself does not ensure that the stream contains the
|
||||||
expected contents and that this contents is correct.
|
expected contents and that this contents is correct.
|
||||||
</dd>
|
</dd>
|
||||||
|
|
||||||
<dt><code>UnexpectedPropertySetTypeException</code></dt>
|
<dt><code>UnexpectedPropertySetTypeException</code></dt>
|
||||||
@ -301,7 +325,7 @@ else
|
|||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p>Many Microsoft Office documents contain <strong>embedded
|
<p>Many Microsoft Office documents contain <strong>embedded
|
||||||
objects</strong>, for example an Excel sheet on a page in a Word
|
objects</strong>, for example an Excel sheet within a Word
|
||||||
document. Embedded objects may have property sets of their own. An
|
document. Embedded objects may have property sets of their own. An
|
||||||
application can open these property set streams as described above. The
|
application can open these property set streams as described above. The
|
||||||
only difference is that they are not located in the POI filesystem's root
|
only difference is that they are not located in the POI filesystem's root
|
||||||
@ -313,7 +337,252 @@ else
|
|||||||
properties.</p>
|
properties.</p>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<anchor id="sec3"/>
|
<anchor id="sec3"/>
|
||||||
|
<section><title>Writing Standard Properties</title>
|
||||||
|
|
||||||
|
<note>This section explains how to <strong>write standard
|
||||||
|
properties</strong>. HPSF provides some high-level classes and methods
|
||||||
|
which make writing of standard properties easy. They are based on the
|
||||||
|
low-level writing functions explained in <link href="#sec4">another
|
||||||
|
section</link>.</note>
|
||||||
|
|
||||||
|
<p>As explained above, standard properties are located in the summary
|
||||||
|
information and document summary information streams of typical POI
|
||||||
|
filesystems. You have already learned about the classes
|
||||||
|
<code>SummaryInformation</code> and
|
||||||
|
<code>DocumentSummaryInformation</code> and their <code>get...()</code>
|
||||||
|
methods for reading standard properties. These classes also provide
|
||||||
|
<code>set...()</code> methods for writing properties.</p>
|
||||||
|
|
||||||
|
<p>After setting properties in <code>SummaryInformation</code> or
|
||||||
|
<code>DocumentSummaryInformation</code> you have to write them to a disk
|
||||||
|
file. The following sample program shows how you can</p>
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>read a disk file into a POI filesystem,</li>
|
||||||
|
<li>read the document summary information from the POI filesystem,</li>
|
||||||
|
<li>set a property to a new value,</li>
|
||||||
|
<li>write the modified document summary information back to the POI
|
||||||
|
filesystem, and</li>
|
||||||
|
<li>write the POI filesystem to a disk file.</li>
|
||||||
|
</ol>
|
||||||
|
|
||||||
|
<p>The complete source code of this program is available as
|
||||||
|
<em>ModifyDocumentSummaryInformation.java</em> in the <em>examples</em>
|
||||||
|
section of the POI source tree.</p>
|
||||||
|
|
||||||
|
<note>Dealing with the summary information stream is analogous to handling
|
||||||
|
the document summary information and therefore does not need to be
|
||||||
|
explained here in detailed. See the HPSF API documentation to learn about
|
||||||
|
the <code>set...()</code> methods of the class
|
||||||
|
<code>SummaryInformation</code>.</note>
|
||||||
|
|
||||||
|
<p>The first step is to read the POI filesystem into memory:</p>
|
||||||
|
|
||||||
|
<source>InputStream is = new FileInputStream(poiFilesystem);
|
||||||
|
POIFSFileSystem poifs = new POIFSFileSystem(is);
|
||||||
|
is.close();</source>
|
||||||
|
|
||||||
|
<p>The code snippet above assumes that the variable
|
||||||
|
<code>poiFilesystem</code> holds the name of a disk file. It reads the
|
||||||
|
file from an input stream and creates a <code>POIFSFileSystem</code>
|
||||||
|
object in memory. After having read the file, the input stream should be
|
||||||
|
closed as shown.</p>
|
||||||
|
|
||||||
|
<p>In order to read the document summary information stream the application
|
||||||
|
must open the element <em>\005DocumentSummaryInformation</em> in the POI
|
||||||
|
filesystem's root directory. However, the POI filesystem does not
|
||||||
|
necessarily contain a document summary information stream, and the
|
||||||
|
application should be able to deal with that situation. The following
|
||||||
|
code does so by creating a new <code>DocumentSummaryInformation</code> if
|
||||||
|
there is none in the POI filesystem:</p>
|
||||||
|
|
||||||
|
<source>DirectoryEntry dir = poifs.getRoot();
|
||||||
|
DocumentSummaryInformation dsi;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/* There is no document summary information. We have to create a
|
||||||
|
* new one. */
|
||||||
|
dsi = PropertySetFactory.newDocumentSummaryInformation();
|
||||||
|
}
|
||||||
|
</source>
|
||||||
|
|
||||||
|
<p>In the source code above the statement</p>
|
||||||
|
|
||||||
|
<source>DirectoryEntry dir = poifs.getRoot();</source>
|
||||||
|
|
||||||
|
<p>gets hold of the POI filesystem's root directory as a
|
||||||
|
<code>DirectoryEntry</code>. The <code>getEntry()</code> method of this
|
||||||
|
class is used to access a file or directory entry in a directory. However,
|
||||||
|
if the file to be opened does not exist, a
|
||||||
|
<code>FileNotFoundException</code> will be thrown. Therefore opening the
|
||||||
|
document summary information entry should be done in a <code>try</code>
|
||||||
|
block:</p>
|
||||||
|
|
||||||
|
<source> DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);</source>
|
||||||
|
|
||||||
|
<p><code>DocumentSummaryInformation.DEFAULT_STREAM_NAME</code> represents
|
||||||
|
the string "\005DocumentSummaryInformation", i.e. the standard name of a
|
||||||
|
document summary information stream. If this stream exists, the
|
||||||
|
<code>getEntry()</code> method returns a <code>DocumentEntry</code>. To
|
||||||
|
read the <code>DocumentEntry</code>'s contents, create a
|
||||||
|
<code>DocumentInputStream</code>:</p>
|
||||||
|
|
||||||
|
<source> DocumentInputStream dis = new DocumentInputStream(dsiEntry);</source>
|
||||||
|
|
||||||
|
<p>Up to this point we have used POI's <link
|
||||||
|
href="../poifs/index.html">POIFS component</link>. Now HPSF enters the
|
||||||
|
stage. A property set is created from the input stream's data:</p>
|
||||||
|
|
||||||
|
<source> PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
dsi = new DocumentSummaryInformation(ps); </source>
|
||||||
|
|
||||||
|
<p>If the data really constitutes a property set, a
|
||||||
|
<code>PropertySet</code> object is created. Otherwise a
|
||||||
|
<code>NoPropertySetStreamException</code> is thrown. After having read the
|
||||||
|
data from the input stream the latter should be closed.</p>
|
||||||
|
|
||||||
|
<p>Since we know - or at least hope - that the stream named
|
||||||
|
"\005DocumentSummaryInformation" is not just any property set but really
|
||||||
|
contains the document summary information, we try to create a new
|
||||||
|
<code>DocumentSummaryInformation</code> from the property set. If the
|
||||||
|
stream is not document summary information stream the sample application
|
||||||
|
fails with a <code>UnexpectedPropertySetTypeException</code>.</p>
|
||||||
|
|
||||||
|
<p>If the POI document does not contain a document summary information
|
||||||
|
stream, we can create a new one in the <code>catch</code> clause. The
|
||||||
|
<code>PropertySetFactory</code>'s method
|
||||||
|
<code>newDocumentSummaryInformation()</code> establishes a new and empty
|
||||||
|
<code>DocumentSummaryInformation</code> instance:</p>
|
||||||
|
|
||||||
|
<source> dsi = PropertySetFactory.newDocumentSummaryInformation();</source>
|
||||||
|
|
||||||
|
<p>Whether we read the document summary information from the POI filesystem
|
||||||
|
or created it from scratch, in either case we now have a
|
||||||
|
<code>DocumentSummaryInformation</code> instance we can write to. Writing
|
||||||
|
is quite simple, as the following line of code shows:</p>
|
||||||
|
|
||||||
|
<source>dsi.setCategory("POI example");</source>
|
||||||
|
|
||||||
|
<p>This statement sets the "category" property to "POI example". Any
|
||||||
|
former "category" value will be lost. If there hasn't been a "category"
|
||||||
|
property yet, a new one will be created.</p>
|
||||||
|
|
||||||
|
<p><code>DocumentSummaryInformation</code> of course has methods to set the
|
||||||
|
other standard properties, too - look into the API documentation to see
|
||||||
|
all of them.</p>
|
||||||
|
|
||||||
|
<p>Once all properties are set as needed, they should be stored into the
|
||||||
|
file on disk. The first step is to write the
|
||||||
|
<code>DocumentSummaryInformation</code> into the POI filesystem:</p>
|
||||||
|
|
||||||
|
<source>dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);</source>
|
||||||
|
|
||||||
|
<p>The <code>DocumentSummaryInformation</code>'s <code>write()</code>
|
||||||
|
method takes two parameters: The first is the <code>DirectoryEntry</code>
|
||||||
|
in the POI filesystem, the second is the name of the stream to create in
|
||||||
|
the directory. If this stream already exists, it will be overwritten.</p>
|
||||||
|
|
||||||
|
<note>If you not only modified the document summary information but also
|
||||||
|
the summary information you have to write both of them to the POI
|
||||||
|
filesystem.</note>
|
||||||
|
|
||||||
|
<p>Still the POI filesystem is a data structure in memory only and must be
|
||||||
|
written to a disk file to make it permanent. The following lines write
|
||||||
|
back the POI filesystem to the file it was read from before. Please note
|
||||||
|
that in production-quality code you should never write directly to the
|
||||||
|
origin file, because in case of an error everything would be lost. Here it
|
||||||
|
is done this way to keep the example short.</p>
|
||||||
|
|
||||||
|
<source>OutputStream out = new FileOutputStream(poiFilesystem);
|
||||||
|
poifs.writeFilesystem(out);
|
||||||
|
out.close();</source>
|
||||||
|
|
||||||
|
<section><title>User-Defined Properties</title>
|
||||||
|
|
||||||
|
<p>If you compare the source code excerpts above with the file containing
|
||||||
|
the full source code, you will notice that I left out some following
|
||||||
|
lines of code. The are dealing with the special topic of custom
|
||||||
|
properties.</p>
|
||||||
|
|
||||||
|
<source>DocumentSummaryInformation dsi = ...
|
||||||
|
...
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null)
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put("Key 1", "Value 1");
|
||||||
|
customProperties.put("Schlüssel 2", "Wert 2");
|
||||||
|
customProperties.put("Sample Number", new Integer(12345));
|
||||||
|
customProperties.put("Sample Boolean", new Boolean(true));
|
||||||
|
customProperties.put("Sample Date", new Date());
|
||||||
|
|
||||||
|
/* Read a custom property. */
|
||||||
|
Object value = customProperties.get("Sample Number");
|
||||||
|
|
||||||
|
/* Write the custom properties back to the document summary
|
||||||
|
* information. */
|
||||||
|
dsi.setCustomProperties(customProperties);</source>
|
||||||
|
|
||||||
|
<p>Custom properties are properties the user can define himself. Using for
|
||||||
|
example Microsoft Word he can define these extra properties and give
|
||||||
|
each of them a <strong>name</strong>, a <strong>type</strong> and a
|
||||||
|
<strong>value</strong>. The custom properties are stored in the document
|
||||||
|
information summary along with the standard properties.</p>
|
||||||
|
|
||||||
|
<p>The source code example shows how to retrieve the custom properties
|
||||||
|
as a whole from a <code>DocumentSummaryInformation</code> instance using
|
||||||
|
the <code>getCustomProperties()</code> method. The result is a
|
||||||
|
<code>CustomProperties</code> instance or <code>null</code> if no
|
||||||
|
user-defined properties exist.</p>
|
||||||
|
|
||||||
|
<p>Since <code>CustomProperties</code> implements the <code>Map</code>
|
||||||
|
interface you can read and write properties with the usual
|
||||||
|
<code>Map</code> methods. However, <code>CustomProperties</code> poses
|
||||||
|
some restrictions on the types of keys and values.</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>The <strong>key</strong> is a string.</li>
|
||||||
|
<li>The <strong>value</strong> is one of <code>String</code>,
|
||||||
|
<code>Boolean</code>, <code>Long</code>, <code>Integer</code>,
|
||||||
|
<code>Short</code>, or <code>java.util.Date</code>.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>The <code>CustomProperties</code> class has been designed for easy
|
||||||
|
access using just keys and values. The underlying Microsoft-specific
|
||||||
|
custom properties data structure is more complicated. However, it does
|
||||||
|
not provide noteworthy additional benefits. It is possible to have
|
||||||
|
multiple properties with the same name or properties without a
|
||||||
|
name at all. When reading custom properties from a document summary
|
||||||
|
information stream, the <code>CustomProperties</code> class ignores
|
||||||
|
properties without a name and keeps only the "last" (whatever that means)
|
||||||
|
of those properties having the same name. You can find out whether a
|
||||||
|
<code>CustomProperties</code> instance dropped any properties with the
|
||||||
|
<code>isPure()</code> method.</p>
|
||||||
|
|
||||||
|
<p>You can read and write the full spectrum of custom properties with
|
||||||
|
HPSF's low-level methods. They are explained in the <link
|
||||||
|
href="#sec4">next section</link>.</p>
|
||||||
|
</section>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<anchor id="sec4"/>
|
||||||
<section><title>Reading Non-Standard Properties</title>
|
<section><title>Reading Non-Standard Properties</title>
|
||||||
|
|
||||||
<note>This section tells how to read non-standard properties. Non-standard
|
<note>This section tells how to read non-standard properties. Non-standard
|
||||||
@ -863,7 +1132,8 @@ No property set stream: "/1Table"</source>
|
|||||||
|
|
||||||
<p>There are some exceptions to the rule saying that a character
|
<p>There are some exceptions to the rule saying that a character
|
||||||
encoding's name is derived from the codepage number by prepending the
|
encoding's name is derived from the codepage number by prepending the
|
||||||
string "cp" to it:</p>
|
string "cp" to it. In these cases the codepage number is mapped to a
|
||||||
|
well-known character encoding name. Here are a few examples:</p>
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
<dt>Codepage 932</dt>
|
<dt>Codepage 932</dt>
|
||||||
@ -874,26 +1144,32 @@ No property set stream: "/1Table"</source>
|
|||||||
<dd>is mapped to the character encoding "UTF-8".</dd>
|
<dd>is mapped to the character encoding "UTF-8".</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<p>Probably there will be a need to add more mappings between codepage
|
<p>More of these mappings between codepage and character encoding name are
|
||||||
numbers and character encoding names. They should be added to the method
|
hard-coded in the classes <code>org.apache.poi.hpsf.Constants</code> and
|
||||||
<code>codepageToEncoding</code> in the class
|
<code>org.apache.poi.hpsf.VariantSupport</code>. Probably there will be a
|
||||||
<code>org.apache.poi.hpsf.VariantSupport</code>. The HPSF author will
|
need to add more mappings. The HPSF author will appreciate any hints.</p>
|
||||||
appreciate any advices for mappings to be added.</p>
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<anchor id="sec4"/>
|
<anchor id="sec5"/>
|
||||||
<section><title>Writing Properties</title>
|
<section><title>Writing Properties</title>
|
||||||
|
|
||||||
<note>This section describes how to write properties.</note>
|
<note>This section describes how to write properties.</note>
|
||||||
|
|
||||||
<section><title>Overview of Writing Properties</title>
|
<section><title>Overview of Writing Properties</title>
|
||||||
<p>Writing properties is possible at a low level only at the moment. You
|
<p>Writing properties is possible at a high level and at a low level:</p>
|
||||||
have to deal with things like property IDs and variant types to write
|
|
||||||
properties. There are no convenience classes or convenience methods for
|
<ul>
|
||||||
dealing with summary information and document summary information streams
|
|
||||||
yet. Therefore you should have read <link href="#sec3">section 3</link>
|
<li>Most users will want to create or change entries in the summary
|
||||||
to understand what follows in this section.</p>
|
information or document summary information streams. </li>
|
||||||
|
|
||||||
|
<li>On the low level, there are no convenience classes or methods. You
|
||||||
|
have to deal with things like property IDs and variant types to write
|
||||||
|
properties. Therefore you should have read <link href="#sec3">section
|
||||||
|
3</link> to understand the description of the low-level writing
|
||||||
|
functions.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<p>HPSF's writing capabilities come with the classes
|
<p>HPSF's writing capabilities come with the classes
|
||||||
<code>MutablePropertySet</code>, <code>MutableSection</code>,
|
<code>MutablePropertySet</code>, <code>MutableSection</code>,
|
||||||
@ -903,7 +1179,10 @@ No property set stream: "/1Table"</source>
|
|||||||
"write" methods, following the <link
|
"write" methods, following the <link
|
||||||
href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator
|
href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator
|
||||||
pattern</link>.</p>
|
pattern</link>.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
|
||||||
|
<section><title>Low-Level Writing: An Overview</title>
|
||||||
<p>When you are going to write a property set stream your application has
|
<p>When you are going to write a property set stream your application has
|
||||||
to perform the following steps:</p>
|
to perform the following steps:</p>
|
||||||
|
|
||||||
|
@ -1006,41 +1006,40 @@
|
|||||||
helpful. If you have any amendments or corrections, please let us know!
|
helpful. If you have any amendments or corrections, please let us know!
|
||||||
Thank you!</p>
|
Thank you!</p>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
|
|
||||||
<li>In
|
<li>In
|
||||||
<link href="http://www.kyler.com/pubs/ddj9894.html"><em>Understanding OLE
|
<link href="http://www.kyler.com/pubs/ddj9894.html"><em>Understanding OLE
|
||||||
documents</em></link>, Ken Kyler gives an introduction to OLE2
|
documents</em></link>, Ken Kyler gives an introduction to OLE2
|
||||||
documents
|
documents and especially to property sets. He names the property names,
|
||||||
and especially to property sets. He names the property names, types, and
|
types, and IDs of the Summary Information and Document Summary
|
||||||
IDs of the Summary Information and Document Summary Information
|
Information stream.</li>
|
||||||
stream.</li>
|
|
||||||
|
|
||||||
<li>The
|
<li>The <link href="http://www.dwam.net/docs/oleref/"><em>ActiveX
|
||||||
<link href="http://www.dwam.net/docs/oleref/"><em>ActiveX Programmer's
|
Programmer's Reference</em></link> at <link
|
||||||
Reference</em></link> at
|
href="http://www.dwam.net/docs/oleref/">http://www.dwam.net/docs/oleref/</link>
|
||||||
<link href="http://www.dwam.net/docs/oleref/">http://www.dwam.net/docs/oleref/</link>
|
|
||||||
seems a little outdated, but that's what I have found.</li>
|
seems a little outdated, but that's what I have found.</li>
|
||||||
|
|
||||||
<li>An overview of the <code>VT_</code> types is in
|
<li>An overview of the <code>VT_</code> types is in
|
||||||
<link href="http://www.marin.clara.net/COM/variant_type_definitions.htm"><em>Variant
|
<link href="http://www.marin.clara.net/COM/variant_type_definitions.htm"><em>Variant
|
||||||
Type Definitions</em></link>.</li>
|
Type Definitions</em></link>.</li>
|
||||||
|
|
||||||
<li>What is a <code>FILETIME</code>? The answer can be found
|
<li>What is a <code>FILETIME</code>? The answer can be found
|
||||||
under <link
|
under <link
|
||||||
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/filetime_str.asp"></link>, <link href="http://www.vbapi.com/ref/f/filetime.html">http://www.vbapi.com/ref/f/filetime.html</link> or
|
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/filetime_str.asp"></link>, <link href="http://www.vbapi.com/ref/f/filetime.html">http://www.vbapi.com/ref/f/filetime.html</link> or
|
||||||
<link href="http://www.cs.rpi.edu/courses/fall01/os/FILETIME.html">http://www.cs.rpi.edu/courses/fall01/os/FILETIME.html</link>.
|
<link href="http://www.cs.rpi.edu/courses/fall01/os/FILETIME.html">http://www.cs.rpi.edu/courses/fall01/os/FILETIME.html</link>.
|
||||||
In short: <em>The FILETIME structure holds a date and time associated
|
In short: <em>The FILETIME structure holds a date and time associated
|
||||||
with a file. The structure identifies a 64-bit integer specifying the
|
with a file. The structure identifies a 64-bit integer specifying the
|
||||||
number of 100-nanosecond intervals which have passed since January 1,
|
number of 100-nanosecond intervals which have passed since January 1,
|
||||||
1601. This 64-bit value is split into the two dwords stored in the
|
1601. This 64-bit value is split into the two dwords stored in the
|
||||||
structure.</em></li>
|
structure.</em></li>
|
||||||
|
|
||||||
<li>Information about the code page property in the
|
<li>Microsoft provides some public information in the <link
|
||||||
DocumentSummaryInformation stream is available at <link
|
href="http://msdn.microsoft.com/library/default.asp">MSDN
|
||||||
href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/property_id_1.asp">http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stg/stg/property_id_1.asp</link>.</li>
|
Library</link>. Use the search function to try to find what you are
|
||||||
|
looking for, e.g. "codepage" or "document summary information" etc.</li>
|
||||||
|
|
||||||
<li>This documentation origins from the <link href="http://www.rainer-klute.de/~klute/Software/poibrowser/doc/HPSF-Description.html">HPSF description</link> available at <link href="http://www.rainer-klute.de/~klute/Software/poibrowser/doc/HPSF-Description.html">http://www.rainer-klute.de/~klute/Software/poibrowser/doc/HPSF-Description.html</link>.</li>
|
<li>This documentation origins from the <link href="http://www.rainer-klute.de/~klute/Software/poibrowser/doc/HPSF-Description.html">HPSF description</link> available at <link href="http://www.rainer-klute.de/~klute/Software/poibrowser/doc/HPSF-Description.html">http://www.rainer-klute.de/~klute/Software/poibrowser/doc/HPSF-Description.html</link>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
@ -0,0 +1,200 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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.examples;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import org.apache.poi.hpsf.CustomProperties;
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.MarkUnsupportedException;
|
||||||
|
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
||||||
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
|
||||||
|
import org.apache.poi.hpsf.WritingNotSupportedException;
|
||||||
|
import org.apache.poi.poifs.filesystem.DirectoryEntry;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This is a sample application showing how to easily modify properties in
|
||||||
|
* the summary information and in the document summary information. The
|
||||||
|
* application reads the name of a POI filesystem from the command line and
|
||||||
|
* performs the following actions:</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
*
|
||||||
|
* <li><p>Open the POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Read the summary information.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Read and print the "author" property.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Change the author to "Rainer Klute".</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Read the document summary information.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Read and print the "category" property.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Change the category to "POI example".</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Read the custom properties (if available).</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Insert a new custom property.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the custom properties back to the document summary
|
||||||
|
* information.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the summary information to the POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the document summary information to the POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the POI filesystem back to the original file.</p></li>
|
||||||
|
*
|
||||||
|
* </ol>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de">klute@rainer-klute.de</a>
|
||||||
|
* @since 2006-02-09
|
||||||
|
* @version $Id: TestWrite.java 353637 2005-04-13 16:33:22Z klute $
|
||||||
|
*/
|
||||||
|
public class ModifyDocumentSummaryInformation
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Main method - see class description.</p>
|
||||||
|
*
|
||||||
|
* @param args The command-line parameters.
|
||||||
|
* @throws IOException
|
||||||
|
* @throws MarkUnsupportedException
|
||||||
|
* @throws NoPropertySetStreamException
|
||||||
|
* @throws UnexpectedPropertySetTypeException
|
||||||
|
* @throws WritingNotSupportedException
|
||||||
|
*/
|
||||||
|
public static void main(final String[] args) throws IOException,
|
||||||
|
NoPropertySetStreamException, MarkUnsupportedException,
|
||||||
|
UnexpectedPropertySetTypeException, WritingNotSupportedException
|
||||||
|
{
|
||||||
|
/* Read the name of the POI filesystem to modify from the command line.
|
||||||
|
* For brevity to boundary check is performed on the command-line
|
||||||
|
* arguments. */
|
||||||
|
File poiFilesystem = new File(args[0]);
|
||||||
|
|
||||||
|
/* Open the POI filesystem. */
|
||||||
|
InputStream is = new FileInputStream(poiFilesystem);
|
||||||
|
POIFSFileSystem poifs = new POIFSFileSystem(is);
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
/* Read the summary information. */
|
||||||
|
DirectoryEntry dir = poifs.getRoot();
|
||||||
|
SummaryInformation si;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry siEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(siEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
si = new SummaryInformation(ps);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/* There is no summary information yet. We have to create a new
|
||||||
|
* one. */
|
||||||
|
si = PropertySetFactory.newSummaryInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the author to "Rainer Klute". Any former author value will
|
||||||
|
* be lost. If there has been no author yet, it will be created. */
|
||||||
|
si.setAuthor("Rainer Klute");
|
||||||
|
System.out.println("Author changed to " + si.getAuthor() + ".");
|
||||||
|
|
||||||
|
|
||||||
|
/* Handling the document summary information is analogous to handling
|
||||||
|
* the summary information. An additional feature, however, are the
|
||||||
|
* custom properties. */
|
||||||
|
|
||||||
|
/* Read the document summary information. */
|
||||||
|
DocumentSummaryInformation dsi;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/* There is no document summary information yet. We have to create a
|
||||||
|
* new one. */
|
||||||
|
dsi = PropertySetFactory.newDocumentSummaryInformation();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the category to "POI example". Any former category value will
|
||||||
|
* be lost. If there has been no category yet, it will be created. */
|
||||||
|
dsi.setCategory("POI example");
|
||||||
|
System.out.println("Category changed to " + dsi.getCategory() + ".");
|
||||||
|
|
||||||
|
/* Read the custom properties. If there are no custom properties yet,
|
||||||
|
* the application has to create a new CustomProperties object. It will
|
||||||
|
* serve as a container for custom properties. */
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null)
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put("Key 1", "Value 1");
|
||||||
|
customProperties.put("Schlüssel 2", "Wert 2");
|
||||||
|
customProperties.put("Sample Number", new Integer(12345));
|
||||||
|
customProperties.put("Sample Boolean", new Boolean(true));
|
||||||
|
customProperties.put("Sample Date", new Date());
|
||||||
|
|
||||||
|
/* Read a custom property. */
|
||||||
|
Object value = customProperties.get("Sample Number");
|
||||||
|
|
||||||
|
/* Write the custom properties back to the document summary
|
||||||
|
* information. */
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
/* Write the summary information and the document summary information
|
||||||
|
* to the POI filesystem. */
|
||||||
|
si.write(dir, SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
|
||||||
|
/* Write the POI filesystem back to the original file. Please note that
|
||||||
|
* in production code you should never write directly to the origin
|
||||||
|
* file! In case of a writing error everything would be lost. */
|
||||||
|
OutputStream out = new FileOutputStream(poiFilesystem);
|
||||||
|
poifs.writeFilesystem(out);
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
367
src/java/org/apache/poi/hpsf/CustomProperties.java
Normal file
367
src/java/org/apache/poi/hpsf/CustomProperties.java
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Maintains the instances of {@link CustomProperty} that belong to a
|
||||||
|
* {@link DocumentSummaryInformation}. The class maintains the names of the
|
||||||
|
* custom properties in a dictionary. It implements the {@link Map} interface
|
||||||
|
* and by this provides a simplified view on custom properties: A property's
|
||||||
|
* name is the key that maps to a typed value. This implementation hides
|
||||||
|
* property IDs from the developer and regards the property names as keys to
|
||||||
|
* typed values.</p>
|
||||||
|
*
|
||||||
|
* <p>While this class provides a simple API to custom properties, it ignores
|
||||||
|
* the fact that not names, but IDs are the real keys to properties. Under the
|
||||||
|
* hood this class maintains a 1:1 relationship between IDs and names. Therefore
|
||||||
|
* you should not use this class to process property sets with several IDs
|
||||||
|
* mapping to the same name or with properties without a name: the result will
|
||||||
|
* contain only a subset of the original properties. If you really need to deal
|
||||||
|
* such property sets, use HPSF's low-level access methods.</p>
|
||||||
|
*
|
||||||
|
* <p>An application can call the {@link #isPure} method to check whether a
|
||||||
|
* property set parsed by {@link CustomProperties} is still pure (i.e.
|
||||||
|
* unmodified) or whether one or more properties have been dropped.</p>
|
||||||
|
*
|
||||||
|
* <p>This class is not thread-safe; concurrent access to instances of this
|
||||||
|
* class must be syncronized.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @since 2006-02-09
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class CustomProperties extends HashMap
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Maps property IDs to property names.</p>
|
||||||
|
*/
|
||||||
|
private Map dictionaryIDToName = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Maps property names to property IDs.</p>
|
||||||
|
*/
|
||||||
|
private Map dictionaryNameToID = new HashMap();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tells whether this object is pure or not.</p>
|
||||||
|
*/
|
||||||
|
private boolean isPure = true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Puts a {@link CustomProperty} into this map. It is assumed that the
|
||||||
|
* {@link CustomProperty} already has a valid ID. Otherwise use
|
||||||
|
* {@link #put(CustomProperty)}.</p>
|
||||||
|
*/
|
||||||
|
public Object put(final Object name, final Object customProperty) throws ClassCastException
|
||||||
|
{
|
||||||
|
final CustomProperty cp = (CustomProperty) customProperty;
|
||||||
|
if (name == null)
|
||||||
|
{
|
||||||
|
/* Ignoring a property without a name. */
|
||||||
|
isPure = false;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!(name instanceof String))
|
||||||
|
throw new ClassCastException("The name of a custom property must " +
|
||||||
|
"be a java.lang.String, but it is a " +
|
||||||
|
name.getClass().getName());
|
||||||
|
if (!(name.equals(cp.getName())))
|
||||||
|
throw new IllegalArgumentException("Parameter \"name\" (" + name +
|
||||||
|
") and custom property's name (" + cp.getName() +
|
||||||
|
") do not match.");
|
||||||
|
|
||||||
|
/* Register name and ID in the dictionary. Mapping in both directions is possible. If there is already a */
|
||||||
|
final Long idKey = new Long(cp.getID());
|
||||||
|
final Object oldID = dictionaryNameToID.get(name);
|
||||||
|
dictionaryIDToName.remove(oldID);
|
||||||
|
dictionaryNameToID.put(name, idKey);
|
||||||
|
dictionaryIDToName.put(idKey, name);
|
||||||
|
|
||||||
|
/* Put the custom property into this map. */
|
||||||
|
final Object oldCp = super.remove(oldID);
|
||||||
|
super.put(idKey, cp);
|
||||||
|
return oldCp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Puts a {@link CustomProperty} that has not yet a valid ID into this
|
||||||
|
* map. The method will allocate a suitable ID for the custom property:</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
*
|
||||||
|
* <li><p>If there is already a property with the same name, take the ID
|
||||||
|
* of that property.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Otherwise find the highest ID and use its value plus one.</p></li>
|
||||||
|
*
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param customProperty
|
||||||
|
* @return If the was already a property with the same name, the
|
||||||
|
* @throws ClassCastException
|
||||||
|
*/
|
||||||
|
private Object put(final CustomProperty customProperty) throws ClassCastException
|
||||||
|
{
|
||||||
|
final String name = customProperty.getName();
|
||||||
|
|
||||||
|
/* Check whether a property with this name is in the map already. */
|
||||||
|
final Long oldId = (Long) dictionaryNameToID.get(name);
|
||||||
|
if (oldId != null)
|
||||||
|
customProperty.setID(oldId.longValue());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long max = 1;
|
||||||
|
for (final Iterator i = dictionaryIDToName.keySet().iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
final long id = ((Long) i.next()).longValue();
|
||||||
|
if (id > max)
|
||||||
|
max = id;
|
||||||
|
}
|
||||||
|
customProperty.setID(max + 1);
|
||||||
|
}
|
||||||
|
return this.put(name, customProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes a custom property.</p>
|
||||||
|
* @param name The name of the custom property to remove
|
||||||
|
* @return The removed property or <code>null</code> if the specified property was not found.
|
||||||
|
*
|
||||||
|
* @see java.util.HashSet#remove(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public Object remove(final String name)
|
||||||
|
{
|
||||||
|
final Long id = (Long) dictionaryNameToID.get(name);
|
||||||
|
if (id == null)
|
||||||
|
return null;
|
||||||
|
dictionaryIDToName.remove(id);
|
||||||
|
dictionaryNameToID.remove(name);
|
||||||
|
return super.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a named string property.</p>
|
||||||
|
*
|
||||||
|
* @param name The property's name.
|
||||||
|
* @param value The property's value.
|
||||||
|
* @return the property that was stored under the specified name before, or
|
||||||
|
* <code>null</code> if there was no such property before.
|
||||||
|
*/
|
||||||
|
public Object put(final String name, final String value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(-1);
|
||||||
|
p.setType(Variant.VT_LPWSTR);
|
||||||
|
p.setValue(value);
|
||||||
|
final CustomProperty cp = new CustomProperty(p, name);
|
||||||
|
return put(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a named long property.</p>
|
||||||
|
*
|
||||||
|
* @param name The property's name.
|
||||||
|
* @param value The property's value.
|
||||||
|
* @return the property that was stored under the specified name before, or
|
||||||
|
* <code>null</code> if there was no such property before.
|
||||||
|
*/
|
||||||
|
public Object put(final String name, final Long value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(-1);
|
||||||
|
p.setType(Variant.VT_I8);
|
||||||
|
p.setValue(value);
|
||||||
|
final CustomProperty cp = new CustomProperty(p, name);
|
||||||
|
return put(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a named double property.</p>
|
||||||
|
*
|
||||||
|
* @param name The property's name.
|
||||||
|
* @param value The property's value.
|
||||||
|
* @return the property that was stored under the specified name before, or
|
||||||
|
* <code>null</code> if there was no such property before.
|
||||||
|
*/
|
||||||
|
public Object put(final String name, final Double value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(-1);
|
||||||
|
p.setType(Variant.VT_R8);
|
||||||
|
p.setValue(value);
|
||||||
|
final CustomProperty cp = new CustomProperty(p, name);
|
||||||
|
return put(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a named integer property.</p>
|
||||||
|
*
|
||||||
|
* @param name The property's name.
|
||||||
|
* @param value The property's value.
|
||||||
|
* @return the property that was stored under the specified name before, or
|
||||||
|
* <code>null</code> if there was no such property before.
|
||||||
|
*/
|
||||||
|
public Object put(final String name, final Integer value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(-1);
|
||||||
|
p.setType(Variant.VT_I4);
|
||||||
|
p.setValue(value);
|
||||||
|
final CustomProperty cp = new CustomProperty(p, name);
|
||||||
|
return put(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a named boolean property.</p>
|
||||||
|
*
|
||||||
|
* @param name The property's name.
|
||||||
|
* @param value The property's value.
|
||||||
|
* @return the property that was stored under the specified name before, or
|
||||||
|
* <code>null</code> if there was no such property before.
|
||||||
|
*/
|
||||||
|
public Object put(final String name, final Boolean value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(-1);
|
||||||
|
p.setType(Variant.VT_BOOL);
|
||||||
|
p.setValue(value);
|
||||||
|
final CustomProperty cp = new CustomProperty(p, name);
|
||||||
|
return put(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets a named value from the custom properties.</p>
|
||||||
|
*
|
||||||
|
* @param name the name of the value to get
|
||||||
|
* @return the value or <code>null</code> if a value with the specified
|
||||||
|
* name is not found in the custom properties.
|
||||||
|
*/
|
||||||
|
public Object get(final String name)
|
||||||
|
{
|
||||||
|
final Long id = (Long) dictionaryNameToID.get(name);
|
||||||
|
final CustomProperty cp = (CustomProperty) super.get(id);
|
||||||
|
return cp != null ? cp.getValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Adds a named date property.</p>
|
||||||
|
*
|
||||||
|
* @param name The property's name.
|
||||||
|
* @param value The property's value.
|
||||||
|
* @return the property that was stored under the specified name before, or
|
||||||
|
* <code>null</code> if there was no such property before.
|
||||||
|
*/
|
||||||
|
public Object put(final String name, final Date value)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(-1);
|
||||||
|
p.setType(Variant.VT_FILETIME);
|
||||||
|
p.setValue(value);
|
||||||
|
final CustomProperty cp = new CustomProperty(p, name);
|
||||||
|
return put(cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the codepage.</p>
|
||||||
|
*
|
||||||
|
* @param codepage the codepage
|
||||||
|
*/
|
||||||
|
public void setCodepage(final int codepage)
|
||||||
|
{
|
||||||
|
final MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(PropertyIDMap.PID_CODEPAGE);
|
||||||
|
p.setType(Variant.VT_I2);
|
||||||
|
p.setValue(new Integer(codepage));
|
||||||
|
put(new CustomProperty(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the dictionary which contains IDs and names of the named custom
|
||||||
|
* properties.
|
||||||
|
*
|
||||||
|
* @return the dictionary.
|
||||||
|
*/
|
||||||
|
Map getDictionary()
|
||||||
|
{
|
||||||
|
return dictionaryIDToName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the codepage.</p>
|
||||||
|
*
|
||||||
|
* @return the codepage or -1 if the codepage is undefined.
|
||||||
|
*/
|
||||||
|
public int getCodepage()
|
||||||
|
{
|
||||||
|
int codepage = -1;
|
||||||
|
for (final Iterator i = this.values().iterator(); codepage == -1 && i.hasNext();)
|
||||||
|
{
|
||||||
|
final CustomProperty cp = (CustomProperty) i.next();
|
||||||
|
if (cp.getID() == PropertyIDMap.PID_CODEPAGE)
|
||||||
|
codepage = ((Integer) cp.getValue()).intValue();
|
||||||
|
}
|
||||||
|
return codepage;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tells whether this {@link CustomProperties} instance is pure or one or
|
||||||
|
* more properties of the underlying low-level property set has been
|
||||||
|
* dropped.</p>
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the {@link CustomProperties} is pure, else
|
||||||
|
* <code>false</code>.
|
||||||
|
*/
|
||||||
|
public boolean isPure()
|
||||||
|
{
|
||||||
|
return isPure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the purity of the custom property set.</p>
|
||||||
|
*
|
||||||
|
* @param isPure the purity
|
||||||
|
*/
|
||||||
|
public void setPure(final boolean isPure)
|
||||||
|
{
|
||||||
|
this.isPure = isPure;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
123
src/java/org/apache/poi/hpsf/CustomProperty.java
Normal file
123
src/java/org/apache/poi/hpsf/CustomProperty.java
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This class represents custum properties in the document summary
|
||||||
|
* information stream. The difference to normal properties is that custom
|
||||||
|
* properties have an optional name. If the name is not <code>null</code> it
|
||||||
|
* will be maintained in the section's dictionary.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @since 2006-02-09
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class CustomProperty extends MutableProperty
|
||||||
|
{
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates an empty {@link CustomProperty}. The set methods must be
|
||||||
|
* called to make it usable.</p>
|
||||||
|
*/
|
||||||
|
public CustomProperty()
|
||||||
|
{
|
||||||
|
this.name = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a {@link CustomProperty} without a name by copying the
|
||||||
|
* underlying {@link Property}' attributes.</p>
|
||||||
|
*
|
||||||
|
* @param property the property to copy
|
||||||
|
*/
|
||||||
|
public CustomProperty(final Property property)
|
||||||
|
{
|
||||||
|
this(property, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a {@link CustomProperty} with a name.</p>
|
||||||
|
*
|
||||||
|
* @param property This property's attributes are copied to the new custom
|
||||||
|
* property.
|
||||||
|
* @param name The new custom property's name.
|
||||||
|
*/
|
||||||
|
public CustomProperty(final Property property, final String name)
|
||||||
|
{
|
||||||
|
super(property);
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the property's name.</p>
|
||||||
|
*
|
||||||
|
* @return the property's name.
|
||||||
|
*/
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the property's name.</p>
|
||||||
|
*
|
||||||
|
* @param name The name to set.
|
||||||
|
*/
|
||||||
|
public void setName(final String name)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Compares two custom properties for equality. The method returns
|
||||||
|
* <code>true</code> if all attributes of the two custom properties are
|
||||||
|
* equal.</p>
|
||||||
|
*
|
||||||
|
* @param o The custom property to compare with.
|
||||||
|
* @return <code>true</code> if both custom properties are equal, else
|
||||||
|
* <code>false</code>.
|
||||||
|
*
|
||||||
|
* @see java.util.AbstractSet#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equalsContents(final Object o)
|
||||||
|
{
|
||||||
|
final CustomProperty c = (CustomProperty) o;
|
||||||
|
final String name1 = c.getName();
|
||||||
|
final String name2 = this.getName();
|
||||||
|
boolean equalNames = true;
|
||||||
|
if (name1 == null)
|
||||||
|
equalNames = name2 == null;
|
||||||
|
else
|
||||||
|
equalNames = name1.equals(name2);
|
||||||
|
return equalNames && c.getID() == this.getID()
|
||||||
|
&& c.getType() == this.getType()
|
||||||
|
&& c.getValue().equals(this.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see java.util.AbstractSet#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return (int) this.getID();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -17,11 +16,11 @@
|
|||||||
|
|
||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
||||||
|
import org.apache.poi.hpsf.wellknown.SectionIDMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Convenience class representing a DocumentSummary Information stream in a
|
* <p>Convenience class representing a DocumentSummary Information stream in a
|
||||||
@ -68,7 +67,7 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's category (or <code>null</code>).</p>
|
* <p>Returns the category (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The category value
|
* @return The category value
|
||||||
*/
|
*/
|
||||||
@ -77,23 +76,63 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
return (String) getProperty(PropertyIDMap.PID_CATEGORY);
|
return (String) getProperty(PropertyIDMap.PID_CATEGORY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the category.</p>
|
||||||
|
*
|
||||||
|
* @param category The category to set.
|
||||||
|
*/
|
||||||
|
public void setCategory(final String category)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_CATEGORY, category);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the category.</p>
|
||||||
|
*/
|
||||||
|
public void removeCategory()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_CATEGORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's presentation format (or
|
* <p>Returns the presentation format (or
|
||||||
* <code>null</code>).</p>
|
* <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The presentationFormat value
|
* @return The presentation format value
|
||||||
*/
|
*/
|
||||||
public String getPresentationFormat()
|
public String getPresentationFormat()
|
||||||
{
|
{
|
||||||
return (String) getProperty(PropertyIDMap.PID_PRESFORMAT);
|
return (String) getProperty(PropertyIDMap.PID_PRESFORMAT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the presentation format.</p>
|
||||||
|
*
|
||||||
|
* @param presentationFormat The presentation format to set.
|
||||||
|
*/
|
||||||
|
public void setPresentationFormat(final String presentationFormat)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_PRESFORMAT, presentationFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the presentation format.</p>
|
||||||
|
*/
|
||||||
|
public void removePresentationFormat()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_PRESFORMAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's byte count or 0 if the {@link
|
* <p>Returns the byte count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a byte count.</p>
|
* DocumentSummaryInformation} does not contain a byte count.</p>
|
||||||
*
|
*
|
||||||
* @return The byteCount value
|
* @return The byteCount value
|
||||||
@ -103,86 +142,226 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
return getPropertyIntValue(PropertyIDMap.PID_BYTECOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_BYTECOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the byte count.</p>
|
||||||
|
*
|
||||||
|
* @param byteCount The byte count to set.
|
||||||
|
*/
|
||||||
|
public void setByteCount(final int byteCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_BYTECOUNT, byteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the byte count.</p>
|
||||||
|
*/
|
||||||
|
public void removeByteCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_BYTECOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's line count or 0 if the {@link
|
* <p>Returns the line count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a line count.</p>
|
* DocumentSummaryInformation} does not contain a line count.</p>
|
||||||
*
|
*
|
||||||
* @return The lineCount value
|
* @return The line count value
|
||||||
*/
|
*/
|
||||||
public int getLineCount()
|
public int getLineCount()
|
||||||
{
|
{
|
||||||
return getPropertyIntValue(PropertyIDMap.PID_LINECOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_LINECOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the line count.</p>
|
||||||
|
*
|
||||||
|
* @param lineCount The line count to set.
|
||||||
|
*/
|
||||||
|
public void setLineCount(final int lineCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_LINECOUNT, lineCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the line count.</p>
|
||||||
|
*/
|
||||||
|
public void removeLineCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_LINECOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's par count or 0 if the {@link
|
* <p>Returns the par count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a par count.</p>
|
* DocumentSummaryInformation} does not contain a par count.</p>
|
||||||
*
|
*
|
||||||
* @return The parCount value
|
* @return The par count value
|
||||||
*/
|
*/
|
||||||
public int getParCount()
|
public int getParCount()
|
||||||
{
|
{
|
||||||
return getPropertyIntValue(PropertyIDMap.PID_PARCOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_PARCOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the par count.</p>
|
||||||
|
*
|
||||||
|
* @param parCount The par count to set.
|
||||||
|
*/
|
||||||
|
public void setParCount(final int parCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_PARCOUNT, parCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the par count.</p>
|
||||||
|
*/
|
||||||
|
public void removeParCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_PARCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's slide count or 0 if the {@link
|
* <p>Returns the slide count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a slide count.</p>
|
* DocumentSummaryInformation} does not contain a slide count.</p>
|
||||||
*
|
*
|
||||||
* @return The slideCount value
|
* @return The slide count value
|
||||||
*/
|
*/
|
||||||
public int getSlideCount()
|
public int getSlideCount()
|
||||||
{
|
{
|
||||||
return getPropertyIntValue(PropertyIDMap.PID_SLIDECOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_SLIDECOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the slideCount.</p>
|
||||||
|
*
|
||||||
|
* @param slideCount The slide count to set.
|
||||||
|
*/
|
||||||
|
public void setSlideCount(final int slideCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_SLIDECOUNT, slideCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the slide count.</p>
|
||||||
|
*/
|
||||||
|
public void removeSlideCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_SLIDECOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's note count or 0 if the {@link
|
* <p>Returns the note count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a note count.</p>
|
* DocumentSummaryInformation} does not contain a note count.</p>
|
||||||
*
|
*
|
||||||
* @return The noteCount value
|
* @return The note count value
|
||||||
*/
|
*/
|
||||||
public int getNoteCount()
|
public int getNoteCount()
|
||||||
{
|
{
|
||||||
return getPropertyIntValue(PropertyIDMap.PID_NOTECOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_NOTECOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the note count.</p>
|
||||||
|
*
|
||||||
|
* @param noteCount The note count to set.
|
||||||
|
*/
|
||||||
|
public void setNoteCount(final int noteCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_NOTECOUNT, noteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the noteCount.</p>
|
||||||
|
*/
|
||||||
|
public void removeNoteCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_NOTECOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's hidden count or 0 if the {@link
|
* <p>Returns the hidden count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a hidden
|
* DocumentSummaryInformation} does not contain a hidden
|
||||||
* count.</p>
|
* count.</p>
|
||||||
*
|
*
|
||||||
* @return The hiddenCount value
|
* @return The hidden count value
|
||||||
*/
|
*/
|
||||||
public int getHiddenCount()
|
public int getHiddenCount()
|
||||||
{
|
{
|
||||||
return getPropertyIntValue(PropertyIDMap.PID_HIDDENCOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_HIDDENCOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the hidden count.</p>
|
||||||
|
*
|
||||||
|
* @param hiddenCount The hidden count to set.
|
||||||
|
*/
|
||||||
|
public void setHiddenCount(final int hiddenCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getSections().get(0);
|
||||||
|
s.setProperty(PropertyIDMap.PID_HIDDENCOUNT, hiddenCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the hidden count.</p>
|
||||||
|
*/
|
||||||
|
public void removeHiddenCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_HIDDENCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's mmclip count or 0 if the {@link
|
* <p>Returns the mmclip count or 0 if the {@link
|
||||||
* DocumentSummaryInformation} does not contain a mmclip
|
* DocumentSummaryInformation} does not contain a mmclip
|
||||||
* count.</p>
|
* count.</p>
|
||||||
*
|
*
|
||||||
* @return The mMClipCount value
|
* @return The mmclip count value
|
||||||
*/
|
*/
|
||||||
public int getMMClipCount()
|
public int getMMClipCount()
|
||||||
{
|
{
|
||||||
return getPropertyIntValue(PropertyIDMap.PID_MMCLIPCOUNT);
|
return getPropertyIntValue(PropertyIDMap.PID_MMCLIPCOUNT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the mmclip count.</p>
|
||||||
|
*
|
||||||
|
* @param mmClipCount The mmclip count to set.
|
||||||
|
*/
|
||||||
|
public void setMMClipCount(final int mmClipCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_MMCLIPCOUNT, mmClipCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the mmclip count.</p>
|
||||||
|
*/
|
||||||
|
public void removeMMClipCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_MMCLIPCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,42 +375,100 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
return getPropertyBooleanValue(PropertyIDMap.PID_SCALE);
|
return getPropertyBooleanValue(PropertyIDMap.PID_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the scale.</p>
|
||||||
|
*
|
||||||
|
* @param scale The scale to set.
|
||||||
|
*/
|
||||||
|
public void setScale(final boolean scale)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_SCALE, scale);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's heading pair (or <code>null</code>)
|
* <p>Removes the scale.</p>
|
||||||
* <strong>when this method is implemented. Please note that the
|
|
||||||
* return type is likely to change!</strong>
|
|
||||||
*
|
|
||||||
* @return The headingPair value
|
|
||||||
*/
|
*/
|
||||||
public byte[] getHeadingPair()
|
public void removeScale()
|
||||||
{
|
{
|
||||||
if (true)
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
throw new UnsupportedOperationException("FIXME");
|
s.removeProperty(PropertyIDMap.PID_SCALE);
|
||||||
return (byte[]) getProperty(PropertyIDMap.PID_HEADINGPAIR);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's doc parts (or <code>null</code>)
|
* <p>Returns the heading pair (or <code>null</code>)
|
||||||
* <strong>when this method is implemented. Please note that the
|
* <strong>when this method is implemented. Please note that the
|
||||||
* return type is likely to change!</strong>
|
* return type is likely to change!</strong>
|
||||||
*
|
*
|
||||||
* @return The docparts value
|
* @return The heading pair value
|
||||||
|
*/
|
||||||
|
public byte[] getHeadingPair()
|
||||||
|
{
|
||||||
|
notYetImplemented("Reading byte arrays ");
|
||||||
|
return (byte[]) getProperty(PropertyIDMap.PID_HEADINGPAIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the heading pair.</p>
|
||||||
|
*
|
||||||
|
* @param headingPair The heading pair to set.
|
||||||
|
*/
|
||||||
|
public void setHeadingPair(final byte[] headingPair)
|
||||||
|
{
|
||||||
|
notYetImplemented("Writing byte arrays ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the heading pair.</p>
|
||||||
|
*/
|
||||||
|
public void removeHeadingPair()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_HEADINGPAIR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the doc parts (or <code>null</code>)
|
||||||
|
* <strong>when this method is implemented. Please note that the
|
||||||
|
* return type is likely to change!</strong>
|
||||||
|
*
|
||||||
|
* @return The doc parts value
|
||||||
*/
|
*/
|
||||||
public byte[] getDocparts()
|
public byte[] getDocparts()
|
||||||
{
|
{
|
||||||
if (true)
|
notYetImplemented("Reading byte arrays");
|
||||||
throw new UnsupportedOperationException("FIXME");
|
|
||||||
return (byte[]) getProperty(PropertyIDMap.PID_DOCPARTS);
|
return (byte[]) getProperty(PropertyIDMap.PID_DOCPARTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's manager (or <code>null</code>).</p>
|
* <p>Sets the doc parts.</p>
|
||||||
|
*
|
||||||
|
* @param docparts The doc parts to set.
|
||||||
|
*/
|
||||||
|
public void setDocparts(final byte[] docparts)
|
||||||
|
{
|
||||||
|
notYetImplemented("Writing byte arrays");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the doc parts.</p>
|
||||||
|
*/
|
||||||
|
public void removeDocparts()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_DOCPARTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the manager (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The manager value
|
* @return The manager value
|
||||||
*/
|
*/
|
||||||
@ -240,10 +477,30 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
return (String) getProperty(PropertyIDMap.PID_MANAGER);
|
return (String) getProperty(PropertyIDMap.PID_MANAGER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the manager.</p>
|
||||||
|
*
|
||||||
|
* @param manager The manager to set.
|
||||||
|
*/
|
||||||
|
public void setManager(final String manager)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_MANAGER, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the manager.</p>
|
||||||
|
*/
|
||||||
|
public void removeManager()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_MANAGER);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's company (or <code>null</code>).</p>
|
* <p>Returns the company (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The company value
|
* @return The company value
|
||||||
*/
|
*/
|
||||||
@ -252,47 +509,168 @@ public class DocumentSummaryInformation extends SpecialPropertySet
|
|||||||
return (String) getProperty(PropertyIDMap.PID_COMPANY);
|
return (String) getProperty(PropertyIDMap.PID_COMPANY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the company.</p>
|
||||||
|
*
|
||||||
|
* @param company The company to set.
|
||||||
|
*/
|
||||||
|
public void setCompany(final String company)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_COMPANY, company);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the company.</p>
|
||||||
|
*/
|
||||||
|
public void removeCompany()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_COMPANY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns <code>true</code> if the custom links are dirty.</p> <p>
|
* <p>Returns <code>true</code> if the custom links are dirty.</p> <p>
|
||||||
*
|
*
|
||||||
* @return The linksDirty value
|
* @return The links dirty value
|
||||||
*/
|
*/
|
||||||
public boolean getLinksDirty()
|
public boolean getLinksDirty()
|
||||||
{
|
{
|
||||||
return getPropertyBooleanValue(PropertyIDMap.PID_LINKSDIRTY);
|
return getPropertyBooleanValue(PropertyIDMap.PID_LINKSDIRTY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the linksDirty.</p>
|
||||||
|
*
|
||||||
|
* @param linksDirty The links dirty value to set.
|
||||||
|
*/
|
||||||
|
public void setLinksDirty(final boolean linksDirty)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_LINKSDIRTY, linksDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the links dirty.</p>
|
||||||
|
*/
|
||||||
|
public void removeLinksDirty()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_LINKSDIRTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Gets the custom properties as a map from the property name to
|
* <p>Gets the custom properties.</p>
|
||||||
* value.</p>
|
|
||||||
*
|
*
|
||||||
* @return The custom properties if any exist, <code>null</code> otherwise.
|
* @return The custom properties.
|
||||||
* @since 2003-10-22
|
* @since 2006-02-09
|
||||||
*/
|
*/
|
||||||
public Map getCustomProperties()
|
public CustomProperties getCustomProperties()
|
||||||
{
|
{
|
||||||
Map nameToValue = null;
|
CustomProperties cps = null;
|
||||||
if (getSectionCount() >= 2)
|
if (getSectionCount() >= 2)
|
||||||
{
|
{
|
||||||
|
cps = new CustomProperties();
|
||||||
final Section section = (Section) getSections().get(1);
|
final Section section = (Section) getSections().get(1);
|
||||||
final Map pidToName =
|
final Map dictionary = section.getDictionary();
|
||||||
(Map) section.getProperty(PropertyIDMap.PID_DICTIONARY);
|
final Property[] properties = section.getProperties();
|
||||||
if (pidToName != null)
|
int propertyCount = 0;
|
||||||
|
for (int i = 0; i < properties.length; i++)
|
||||||
{
|
{
|
||||||
nameToValue = new HashMap(pidToName.size());
|
final Property p = properties[i];
|
||||||
for (Iterator i = pidToName.entrySet().iterator(); i.hasNext();)
|
final long id = p.getID();
|
||||||
|
if (id != 0 && id != 1)
|
||||||
{
|
{
|
||||||
final Map.Entry e = (Map.Entry) i.next();
|
propertyCount++;
|
||||||
final long pid = ((Number) e.getKey()).longValue();
|
final CustomProperty cp = new CustomProperty(p,
|
||||||
nameToValue.put(e.getValue(), section.getProperty(pid));
|
(String) dictionary.get(new Long(id)));
|
||||||
|
cps.put(cp.getName(), cp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cps.size() != propertyCount)
|
||||||
|
cps.setPure(false);
|
||||||
}
|
}
|
||||||
return nameToValue;
|
return cps;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the custom properties.</p>
|
||||||
|
*
|
||||||
|
* @param customProperties The custom properties
|
||||||
|
* @since 2006-02-07
|
||||||
|
*/
|
||||||
|
public void setCustomProperties(final CustomProperties customProperties)
|
||||||
|
{
|
||||||
|
ensureSection2();
|
||||||
|
final MutableSection section = (MutableSection) getSections().get(1);
|
||||||
|
final Map dictionary = customProperties.getDictionary();
|
||||||
|
section.clear();
|
||||||
|
|
||||||
|
/* Set the codepage. If both custom properties and section have a
|
||||||
|
* codepage, the codepage from the custom properties wins, else take the
|
||||||
|
* one that is defined. If none is defined, take Unicode. */
|
||||||
|
int cpCodepage = customProperties.getCodepage();
|
||||||
|
if (cpCodepage < 0)
|
||||||
|
cpCodepage = section.getCodepage();
|
||||||
|
if (cpCodepage < 0)
|
||||||
|
cpCodepage = Constants.CP_UNICODE;
|
||||||
|
customProperties.setCodepage(cpCodepage);
|
||||||
|
section.setCodepage(cpCodepage);
|
||||||
|
section.setDictionary(dictionary);
|
||||||
|
for (final Iterator i = customProperties.values().iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
final Property p = (Property) i.next();
|
||||||
|
section.setProperty(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates section 2 if it is not already present.</p>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void ensureSection2()
|
||||||
|
{
|
||||||
|
if (getSectionCount() < 2)
|
||||||
|
{
|
||||||
|
MutableSection s2 = new MutableSection();
|
||||||
|
s2.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[1]);
|
||||||
|
addSection(s2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the custom properties.</p>
|
||||||
|
*
|
||||||
|
* @since 2006-02-08
|
||||||
|
*/
|
||||||
|
public void removeCustomProperties()
|
||||||
|
{
|
||||||
|
if (getSectionCount() >= 2)
|
||||||
|
getSections().remove(1);
|
||||||
|
else
|
||||||
|
throw new HPSFRuntimeException("Illegal internal format of Document SummaryInformation stream: second section is missing.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Throws an {@link UnsupportedOperationException} with a message text
|
||||||
|
* telling which functionality is not yet implemented.</p>
|
||||||
|
*
|
||||||
|
* @param msg text telling was leaves to be implemented, e.g.
|
||||||
|
* "Reading byte arrays".
|
||||||
|
*/
|
||||||
|
private void notYetImplemented(final String msg)
|
||||||
|
{
|
||||||
|
throw new UnsupportedOperationException(msg + " is not yet implemented.");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
@ -18,12 +17,12 @@
|
|||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>This exception is the superclass of all other checked exceptions
|
* <p>This exception is the superclass of all other checked exceptions thrown
|
||||||
* thrown in this package. It supports a nested "reason" throwable,
|
* in this package. It supports a nested "reason" throwable, i.e. an exception
|
||||||
* i.e. an exception that caused this one to be thrown.</p>
|
* that caused this one to be thrown.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute <a
|
* @author Rainer Klute <a
|
||||||
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
76
src/java/org/apache/poi/hpsf/MissingSectionException.java
Normal file
76
src/java/org/apache/poi/hpsf/MissingSectionException.java
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This exception is thrown if one of the {@link PropertySet}'s
|
||||||
|
* convenience methods does not find a required {@link Section}.</p>
|
||||||
|
*
|
||||||
|
* <p>The constructors of this class are analogous to those of its
|
||||||
|
* superclass and documented there.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @version $Id: NoSingleSectionException.java 353545 2004-04-09 13:05:39Z glens $
|
||||||
|
* @since 2006-02-08
|
||||||
|
*/
|
||||||
|
public class MissingSectionException extends HPSFRuntimeException
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructor</p>
|
||||||
|
*/
|
||||||
|
public MissingSectionException()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructor</p>
|
||||||
|
*
|
||||||
|
* @param msg The exception's message string
|
||||||
|
*/
|
||||||
|
public MissingSectionException(final String msg)
|
||||||
|
{
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructor</p>
|
||||||
|
*
|
||||||
|
* @param reason This exception's underlying reason
|
||||||
|
*/
|
||||||
|
public MissingSectionException(final Throwable reason)
|
||||||
|
{
|
||||||
|
super(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructor</p>
|
||||||
|
*
|
||||||
|
* @param msg The exception's message string
|
||||||
|
* @param reason This exception's underlying reason
|
||||||
|
*/
|
||||||
|
public MissingSectionException(final String msg, final Throwable reason)
|
||||||
|
{
|
||||||
|
super(msg, reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -18,6 +18,7 @@ package org.apache.poi.hpsf;
|
|||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -26,6 +27,8 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.ListIterator;
|
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.LittleEndian;
|
||||||
import org.apache.poi.util.LittleEndianConsts;
|
import org.apache.poi.util.LittleEndianConsts;
|
||||||
|
|
||||||
@ -151,7 +154,7 @@ public class MutablePropertySet extends PropertySet
|
|||||||
*
|
*
|
||||||
* @param classID The property set stream's low-level "class ID" field.
|
* @param classID The property set stream's low-level "class ID" field.
|
||||||
*
|
*
|
||||||
* @see #getClassID
|
* @see PropertySet#getClassID()
|
||||||
*/
|
*/
|
||||||
public void setClassID(final ClassID classID)
|
public void setClassID(final ClassID classID)
|
||||||
{
|
{
|
||||||
@ -205,9 +208,9 @@ public class MutablePropertySet extends PropertySet
|
|||||||
/* Write the property set's header. */
|
/* Write the property set's header. */
|
||||||
length += TypeWriter.writeToStream(out, (short) getByteOrder());
|
length += TypeWriter.writeToStream(out, (short) getByteOrder());
|
||||||
length += TypeWriter.writeToStream(out, (short) getFormat());
|
length += TypeWriter.writeToStream(out, (short) getFormat());
|
||||||
length += TypeWriter.writeToStream(out, (int) getOSVersion());
|
length += TypeWriter.writeToStream(out, getOSVersion());
|
||||||
length += TypeWriter.writeToStream(out, getClassID());
|
length += TypeWriter.writeToStream(out, getClassID());
|
||||||
length += TypeWriter.writeToStream(out, (int) nrSections);
|
length += TypeWriter.writeToStream(out, nrSections);
|
||||||
int offset = OFFSET_HEADER;
|
int offset = OFFSET_HEADER;
|
||||||
|
|
||||||
/* Write the section list, i.e. the references to the sections. Each
|
/* Write the section list, i.e. the references to the sections. Each
|
||||||
@ -272,4 +275,31 @@ public class MutablePropertySet extends PropertySet
|
|||||||
return new ByteArrayInputStream(streamData);
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -21,6 +21,7 @@ import java.io.IOException;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -107,7 +108,7 @@ public class MutableSection extends Section
|
|||||||
* @param formatID The section's format ID
|
* @param formatID The section's format ID
|
||||||
*
|
*
|
||||||
* @see #setFormatID(byte[])
|
* @see #setFormatID(byte[])
|
||||||
* @see #getFormatID
|
* @see Section#getFormatID
|
||||||
*/
|
*/
|
||||||
public void setFormatID(final ClassID formatID)
|
public void setFormatID(final ClassID formatID)
|
||||||
{
|
{
|
||||||
@ -123,7 +124,7 @@ public class MutableSection extends Section
|
|||||||
* are in big-endian format.
|
* are in big-endian format.
|
||||||
*
|
*
|
||||||
* @see #setFormatID(ClassID)
|
* @see #setFormatID(ClassID)
|
||||||
* @see #getFormatID
|
* @see Section#getFormatID
|
||||||
*/
|
*/
|
||||||
public void setFormatID(final byte[] formatID)
|
public void setFormatID(final byte[] formatID)
|
||||||
{
|
{
|
||||||
@ -155,10 +156,7 @@ public class MutableSection extends Section
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Sets the value of the property with the specified ID. If a
|
* <p>Sets the string value of the property with the specified ID.</p>
|
||||||
* property with this ID is not yet present in the section, it
|
|
||||||
* will be added. An already present property with the specified
|
|
||||||
* ID will be overwritten.</p>
|
|
||||||
*
|
*
|
||||||
* @param id The property's ID
|
* @param id The property's ID
|
||||||
* @param value The property's value. It will be written as a Unicode
|
* @param value The property's value. It will be written as a Unicode
|
||||||
@ -175,6 +173,57 @@ public class MutableSection extends Section
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the int value of the property with the specified ID.</p>
|
||||||
|
*
|
||||||
|
* @param id The property's ID
|
||||||
|
* @param value The property's value.
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, long, Object)
|
||||||
|
* @see #getProperty
|
||||||
|
*/
|
||||||
|
public void setProperty(final int id, final int value)
|
||||||
|
{
|
||||||
|
setProperty(id, Variant.VT_I4, new Integer(value));
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the long value of the property with the specified ID.</p>
|
||||||
|
*
|
||||||
|
* @param id The property's ID
|
||||||
|
* @param value The property's value.
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, long, Object)
|
||||||
|
* @see #getProperty
|
||||||
|
*/
|
||||||
|
public void setProperty(final int id, final long value)
|
||||||
|
{
|
||||||
|
setProperty(id, Variant.VT_I8, new Long(value));
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the boolean value of the property with the specified ID.</p>
|
||||||
|
*
|
||||||
|
* @param id The property's ID
|
||||||
|
* @param value The property's value.
|
||||||
|
*
|
||||||
|
* @see #setProperty(int, long, Object)
|
||||||
|
* @see #getProperty
|
||||||
|
*/
|
||||||
|
public void setProperty(final int id, final boolean value)
|
||||||
|
{
|
||||||
|
setProperty(id, Variant.VT_BOOL, new Boolean(value));
|
||||||
|
dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Sets the value and the variant type of the property with the
|
* <p>Sets the value and the variant type of the property with the
|
||||||
* specified ID. If a property with this ID is not yet present in
|
* specified ID. If a property with this ID is not yet present in
|
||||||
@ -204,15 +253,11 @@ public class MutableSection extends Section
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Sets a property. If a property with the same ID is not yet present in
|
* <p>Sets a property.</p>
|
||||||
* the section, the property will be added to the section. If there is
|
|
||||||
* already a property with the same ID present in the section, it will be
|
|
||||||
* overwritten.</p>
|
|
||||||
*
|
*
|
||||||
* @param p The property to be added to the section
|
* @param p The property to be set.
|
||||||
*
|
*
|
||||||
* @see #setProperty(int, long, Object)
|
* @see #setProperty(int, long, Object)
|
||||||
* @see #setProperty(int, String)
|
|
||||||
* @see #getProperty
|
* @see #getProperty
|
||||||
* @see Variant
|
* @see Variant
|
||||||
*/
|
*/
|
||||||
@ -257,7 +302,7 @@ public class MutableSection extends Section
|
|||||||
*/
|
*/
|
||||||
protected void setPropertyBooleanValue(final int id, final boolean value)
|
protected void setPropertyBooleanValue(final int id, final boolean value)
|
||||||
{
|
{
|
||||||
setProperty(id, (long) Variant.VT_BOOL, new Boolean(value));
|
setProperty(id, Variant.VT_BOOL, new Boolean(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -296,6 +341,8 @@ public class MutableSection extends Section
|
|||||||
* properties) and the properties themselves.</p>
|
* properties) and the properties themselves.</p>
|
||||||
*
|
*
|
||||||
* @return the section's length in bytes.
|
* @return the section's length in bytes.
|
||||||
|
* @throws WritingNotSupportedException
|
||||||
|
* @throws IOException
|
||||||
*/
|
*/
|
||||||
private int calcSize() throws WritingNotSupportedException, IOException
|
private int calcSize() throws WritingNotSupportedException, IOException
|
||||||
{
|
{
|
||||||
@ -372,7 +419,7 @@ public class MutableSection extends Section
|
|||||||
/* Warning: The codepage property is not set although a
|
/* Warning: The codepage property is not set although a
|
||||||
* dictionary is present. In order to cope with this problem we
|
* dictionary is present. In order to cope with this problem we
|
||||||
* add the codepage property and set it to Unicode. */
|
* add the codepage property and set it to Unicode. */
|
||||||
setProperty(PropertyIDMap.PID_CODEPAGE, (long) Variant.VT_I2,
|
setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
|
||||||
new Integer(Constants.CP_UNICODE));
|
new Integer(Constants.CP_UNICODE));
|
||||||
codepage = getCodepage();
|
codepage = getCodepage();
|
||||||
}
|
}
|
||||||
@ -474,16 +521,15 @@ public class MutableSection extends Section
|
|||||||
sLength++;
|
sLength++;
|
||||||
length += TypeWriter.writeUIntToStream(out, key.longValue());
|
length += TypeWriter.writeUIntToStream(out, key.longValue());
|
||||||
length += TypeWriter.writeUIntToStream(out, sLength);
|
length += TypeWriter.writeUIntToStream(out, sLength);
|
||||||
final char[] ca = value.toCharArray();
|
final byte[] ca =
|
||||||
for (int j = 0; j < ca.length; j++)
|
value.getBytes(VariantSupport.codepageToEncoding(codepage));
|
||||||
|
for (int j = 2; j < ca.length; j += 2)
|
||||||
{
|
{
|
||||||
int high = (ca[j] & 0x0ff00) >> 8;
|
out.write(ca[j+1]);
|
||||||
int low = (ca[j] & 0x000ff);
|
out.write(ca[j]);
|
||||||
out.write(low);
|
|
||||||
out.write(high);
|
|
||||||
length += 2;
|
length += 2;
|
||||||
sLength--;
|
|
||||||
}
|
}
|
||||||
|
sLength -= value.length();
|
||||||
while (sLength > 0)
|
while (sLength > 0)
|
||||||
{
|
{
|
||||||
out.write(0x00);
|
out.write(0x00);
|
||||||
@ -610,4 +656,60 @@ public class MutableSection extends Section
|
|||||||
removeProperty(PropertyIDMap.PID_DICTIONARY);
|
removeProperty(PropertyIDMap.PID_DICTIONARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets a property.</p>
|
||||||
|
*
|
||||||
|
* @param id The property ID.
|
||||||
|
* @param value The property's value. The value's class must be one of those
|
||||||
|
* supported by HPSF.
|
||||||
|
*/
|
||||||
|
public void setProperty(final int id, final Object value)
|
||||||
|
{
|
||||||
|
if (value instanceof String)
|
||||||
|
setProperty(id, (String) value);
|
||||||
|
else if (value instanceof Long)
|
||||||
|
setProperty(id, ((Long) value).longValue());
|
||||||
|
else if (value instanceof Integer)
|
||||||
|
setProperty(id, ((Integer) value).intValue());
|
||||||
|
else if (value instanceof Short)
|
||||||
|
setProperty(id, ((Short) value).intValue());
|
||||||
|
else if (value instanceof Boolean)
|
||||||
|
setProperty(id, ((Boolean) value).booleanValue());
|
||||||
|
else if (value instanceof Date)
|
||||||
|
setProperty(id, Variant.VT_FILETIME, value);
|
||||||
|
else
|
||||||
|
throw new HPSFRuntimeException(
|
||||||
|
"HPSF does not support properties of type " +
|
||||||
|
value.getClass().getName() + ".");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes all properties from the section including 0 (dictionary) and
|
||||||
|
* 1 (codepage).</p>
|
||||||
|
*/
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
final Property[] properties = getProperties();
|
||||||
|
for (int i = 0; i < properties.length; i++)
|
||||||
|
{
|
||||||
|
final Property p = properties[i];
|
||||||
|
removeProperty(p.getID());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the codepage.</p>
|
||||||
|
*
|
||||||
|
* @param codepage the codepage
|
||||||
|
*/
|
||||||
|
public void setCodepage(final int codepage)
|
||||||
|
{
|
||||||
|
setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
|
||||||
|
new Integer(codepage));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -107,6 +107,22 @@ public class Property
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a property.</p>
|
||||||
|
*
|
||||||
|
* @param id the property's ID.
|
||||||
|
* @param type the property's type, see {@link Variant}.
|
||||||
|
* @param value the property's value. Only certain types are allowed, see {@link Variant}.
|
||||||
|
*/
|
||||||
|
public Property(final long id, final long type, final Object value)
|
||||||
|
{
|
||||||
|
this.id = id;
|
||||||
|
this.type = type;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Creates a {@link Property} instance by reading its bytes
|
* <p>Creates a {@link Property} instance by reading its bytes
|
||||||
* from the property set stream.</p>
|
* from the property set stream.</p>
|
||||||
@ -222,12 +238,15 @@ public class Property
|
|||||||
{
|
{
|
||||||
/* The length is the number of characters, i.e. the number
|
/* The length is the number of characters, i.e. the number
|
||||||
* of bytes is twice the number of the characters. */
|
* of bytes is twice the number of the characters. */
|
||||||
for (int j = 0; j < sLength; j++)
|
final int nrBytes = (int) (sLength * 2);
|
||||||
|
final byte[] h = new byte[nrBytes];
|
||||||
|
for (int i2 = 0; i2 < nrBytes; i2 += 2)
|
||||||
{
|
{
|
||||||
final int i1 = o + (j * 2);
|
h[i2] = src[o + i2 + 1];
|
||||||
final int i2 = i1 + 1;
|
h[i2 + 1] = src[o + i2];
|
||||||
b.append((char) ((src[i2] << 8) + src[i1]));
|
|
||||||
}
|
}
|
||||||
|
b.append(new String(h, 0, nrBytes,
|
||||||
|
VariantSupport.codepageToEncoding(codepage)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -402,8 +401,10 @@ public class PropertySet
|
|||||||
*
|
*
|
||||||
* @param src Byte array containing the property set stream
|
* @param src Byte array containing the property set stream
|
||||||
* @param offset The property set stream starts at this offset
|
* @param offset The property set stream starts at this offset
|
||||||
* from the beginning of <var>src</src>
|
* from the beginning of <var>src</var>
|
||||||
* @param length Length of the property set stream.
|
* @param length Length of the property set stream.
|
||||||
|
* @throws UnsupportedEncodingException if HPSF does not (yet) support the
|
||||||
|
* property set's character encoding.
|
||||||
*/
|
*/
|
||||||
private void init(final byte[] src, final int offset, final int length)
|
private void init(final byte[] src, final int offset, final int length)
|
||||||
throws UnsupportedEncodingException
|
throws UnsupportedEncodingException
|
||||||
@ -482,7 +483,7 @@ public class PropertySet
|
|||||||
public boolean isDocumentSummaryInformation()
|
public boolean isDocumentSummaryInformation()
|
||||||
{
|
{
|
||||||
return Util.equal(((Section) sections.get(0)).getFormatID().getBytes(),
|
return Util.equal(((Section) sections.get(0)).getFormatID().getBytes(),
|
||||||
SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID);
|
SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -492,9 +493,7 @@ public class PropertySet
|
|||||||
* contained in this property set. It is a shortcut for getting
|
* contained in this property set. It is a shortcut for getting
|
||||||
* the {@link PropertySet}'s {@link Section}s list and then
|
* the {@link PropertySet}'s {@link Section}s list and then
|
||||||
* getting the {@link Property} array from the first {@link
|
* getting the {@link Property} array from the first {@link
|
||||||
* Section}. However, it can only be used if the {@link
|
* Section}.</p>
|
||||||
* PropertySet} contains exactly one {@link Section}, so check
|
|
||||||
* {@link #getSectionCount} first!</p>
|
|
||||||
*
|
*
|
||||||
* @return The properties of the only {@link Section} of this
|
* @return The properties of the only {@link Section} of this
|
||||||
* {@link PropertySet}.
|
* {@link PropertySet}.
|
||||||
@ -504,7 +503,7 @@ public class PropertySet
|
|||||||
public Property[] getProperties()
|
public Property[] getProperties()
|
||||||
throws NoSingleSectionException
|
throws NoSingleSectionException
|
||||||
{
|
{
|
||||||
return getSingleSection().getProperties();
|
return getFirstSection().getProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,7 +521,7 @@ public class PropertySet
|
|||||||
*/
|
*/
|
||||||
protected Object getProperty(final int id) throws NoSingleSectionException
|
protected Object getProperty(final int id) throws NoSingleSectionException
|
||||||
{
|
{
|
||||||
return getSingleSection().getProperty(id);
|
return getFirstSection().getProperty(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -543,7 +542,7 @@ public class PropertySet
|
|||||||
protected boolean getPropertyBooleanValue(final int id)
|
protected boolean getPropertyBooleanValue(final int id)
|
||||||
throws NoSingleSectionException
|
throws NoSingleSectionException
|
||||||
{
|
{
|
||||||
return getSingleSection().getPropertyBooleanValue(id);
|
return getFirstSection().getPropertyBooleanValue(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -563,7 +562,7 @@ public class PropertySet
|
|||||||
protected int getPropertyIntValue(final int id)
|
protected int getPropertyIntValue(final int id)
|
||||||
throws NoSingleSectionException
|
throws NoSingleSectionException
|
||||||
{
|
{
|
||||||
return getSingleSection().getPropertyIntValue(id);
|
return getFirstSection().getPropertyIntValue(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -585,7 +584,21 @@ public class PropertySet
|
|||||||
*/
|
*/
|
||||||
public boolean wasNull() throws NoSingleSectionException
|
public boolean wasNull() throws NoSingleSectionException
|
||||||
{
|
{
|
||||||
return getSingleSection().wasNull();
|
return getFirstSection().wasNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets the {@link PropertySet}'s first section.</p>
|
||||||
|
*
|
||||||
|
* @return The {@link PropertySet}'s first section.
|
||||||
|
*/
|
||||||
|
public Section getFirstSection()
|
||||||
|
{
|
||||||
|
if (getSectionCount() < 1)
|
||||||
|
throw new MissingSectionException("Property set does not contain any sections.");
|
||||||
|
return ((Section) sections.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -22,6 +21,8 @@ import java.io.IOException;
|
|||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.rmi.UnexpectedException;
|
import java.rmi.UnexpectedException;
|
||||||
|
|
||||||
|
import org.apache.poi.hpsf.wellknown.SectionIDMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Factory class to create instances of {@link SummaryInformation},
|
* <p>Factory class to create instances of {@link SummaryInformation},
|
||||||
* {@link DocumentSummaryInformation} and {@link PropertySet}.</p>
|
* {@link DocumentSummaryInformation} and {@link PropertySet}.</p>
|
||||||
@ -74,4 +75,50 @@ public class PropertySetFactory
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a new summary information.</p>
|
||||||
|
*
|
||||||
|
* @return the new summary information.
|
||||||
|
*/
|
||||||
|
public static SummaryInformation newSummaryInformation()
|
||||||
|
{
|
||||||
|
final MutablePropertySet ps = new MutablePropertySet();
|
||||||
|
final MutableSection s = (MutableSection) ps.getFirstSection();
|
||||||
|
s.setFormatID(SectionIDMap.SUMMARY_INFORMATION_ID);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new SummaryInformation(ps);
|
||||||
|
}
|
||||||
|
catch (UnexpectedPropertySetTypeException ex)
|
||||||
|
{
|
||||||
|
/* This should never happen. */
|
||||||
|
throw new HPSFRuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a new document summary information.</p>
|
||||||
|
*
|
||||||
|
* @return the new document summary information.
|
||||||
|
*/
|
||||||
|
public static DocumentSummaryInformation newDocumentSummaryInformation()
|
||||||
|
{
|
||||||
|
final MutablePropertySet ps = new MutablePropertySet();
|
||||||
|
final MutableSection s = (MutableSection) ps.getFirstSection();
|
||||||
|
s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new DocumentSummaryInformation(ps);
|
||||||
|
}
|
||||||
|
catch (UnexpectedPropertySetTypeException ex)
|
||||||
|
{
|
||||||
|
/* This should never happen. */
|
||||||
|
throw new HPSFRuntimeException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -278,9 +277,12 @@ public class Section
|
|||||||
for (final Iterator i = propertyList.iterator(); i.hasNext();)
|
for (final Iterator i = propertyList.iterator(); i.hasNext();)
|
||||||
{
|
{
|
||||||
ple = (PropertyListEntry) i.next();
|
ple = (PropertyListEntry) i.next();
|
||||||
properties[i1++] = new Property(ple.id, src,
|
Property p = new Property(ple.id, src,
|
||||||
this.offset + ple.offset,
|
this.offset + ple.offset,
|
||||||
ple.length, codepage);
|
ple.length, codepage);
|
||||||
|
if (p.getID() == PropertyIDMap.PID_CODEPAGE)
|
||||||
|
p = new Property(p.getID(), p.getType(), new Integer(codepage));
|
||||||
|
properties[i1++] = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -359,15 +361,15 @@ public class Section
|
|||||||
*/
|
*/
|
||||||
protected int getPropertyIntValue(final long id)
|
protected int getPropertyIntValue(final long id)
|
||||||
{
|
{
|
||||||
final Long i;
|
final Number i;
|
||||||
final Object o = getProperty(id);
|
final Object o = getProperty(id);
|
||||||
if (o == null)
|
if (o == null)
|
||||||
return 0;
|
return 0;
|
||||||
if (!(o instanceof Long))
|
if (!(o instanceof Long || o instanceof Integer))
|
||||||
throw new HPSFRuntimeException
|
throw new HPSFRuntimeException
|
||||||
("This property is not an integer type, but " +
|
("This property is not an integer type, but " +
|
||||||
o.getClass().getName() + ".");
|
o.getClass().getName() + ".");
|
||||||
i = (Long) o;
|
i = (Number) o;
|
||||||
return i.intValue();
|
return i.intValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,6 +547,10 @@ public class Section
|
|||||||
/**
|
/**
|
||||||
* <p>Removes a field from a property array. The resulting array is
|
* <p>Removes a field from a property array. The resulting array is
|
||||||
* compactified and returned.</p>
|
* compactified and returned.</p>
|
||||||
|
*
|
||||||
|
* @param pa The property array.
|
||||||
|
* @param i The index of the field to be removed.
|
||||||
|
* @return the compactified array.
|
||||||
*/
|
*/
|
||||||
private Property[] remove(final Property[] pa, final int i)
|
private Property[] remove(final Property[] pa, final int i)
|
||||||
{
|
{
|
||||||
@ -629,7 +635,10 @@ public class Section
|
|||||||
{
|
{
|
||||||
final Integer codepage =
|
final Integer codepage =
|
||||||
(Integer) getProperty(PropertyIDMap.PID_CODEPAGE);
|
(Integer) getProperty(PropertyIDMap.PID_CODEPAGE);
|
||||||
return codepage != null ? codepage.intValue() : -1;
|
if (codepage == null)
|
||||||
|
return -1;
|
||||||
|
int cp = codepage.intValue();
|
||||||
|
return cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -17,8 +16,13 @@
|
|||||||
|
|
||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.poi.poifs.filesystem.DirectoryEntry;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Abstract superclass for the convenience classes {@link
|
* <p>Abstract superclass for the convenience classes {@link
|
||||||
* SummaryInformation} and {@link DocumentSummaryInformation}.</p>
|
* SummaryInformation} and {@link DocumentSummaryInformation}.</p>
|
||||||
@ -50,24 +54,37 @@ import java.util.List;
|
|||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
*/
|
*/
|
||||||
public abstract class SpecialPropertySet extends PropertySet
|
public abstract class SpecialPropertySet extends MutablePropertySet
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The "real" property set <code>SpecialPropertySet</code>
|
* <p>The "real" property set <code>SpecialPropertySet</code>
|
||||||
* delegates to.</p>
|
* delegates to.</p>
|
||||||
*/
|
*/
|
||||||
private PropertySet delegate;
|
private MutablePropertySet delegate;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Creates a <code>SpecialPropertySet</code>.
|
* <p>Creates a <code>SpecialPropertySet</code>.
|
||||||
*
|
*
|
||||||
* @param ps The property set encapsulated by the
|
* @param ps The property set to be encapsulated by the
|
||||||
* <code>SpecialPropertySet</code>
|
* <code>SpecialPropertySet</code>
|
||||||
*/
|
*/
|
||||||
public SpecialPropertySet(final PropertySet ps)
|
public SpecialPropertySet(final PropertySet ps)
|
||||||
|
{
|
||||||
|
delegate = new MutablePropertySet(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Creates a <code>SpecialPropertySet</code>.
|
||||||
|
*
|
||||||
|
* @param ps The mutable property set to be encapsulated by the
|
||||||
|
* <code>SpecialPropertySet</code>
|
||||||
|
*/
|
||||||
|
public SpecialPropertySet(final MutablePropertySet ps)
|
||||||
{
|
{
|
||||||
delegate = ps;
|
delegate = ps;
|
||||||
}
|
}
|
||||||
@ -157,9 +174,178 @@ public abstract class SpecialPropertySet extends PropertySet
|
|||||||
/**
|
/**
|
||||||
* @see PropertySet#getSingleSection
|
* @see PropertySet#getSingleSection
|
||||||
*/
|
*/
|
||||||
public Section getSingleSection()
|
public Section getFirstSection()
|
||||||
{
|
{
|
||||||
return delegate.getSingleSection();
|
return delegate.getFirstSection();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#addSection(org.apache.poi.hpsf.Section)
|
||||||
|
*/
|
||||||
|
public void addSection(final Section section)
|
||||||
|
{
|
||||||
|
delegate.addSection(section);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#clearSections()
|
||||||
|
*/
|
||||||
|
public void clearSections()
|
||||||
|
{
|
||||||
|
delegate.clearSections();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#setByteOrder(int)
|
||||||
|
*/
|
||||||
|
public void setByteOrder(final int byteOrder)
|
||||||
|
{
|
||||||
|
delegate.setByteOrder(byteOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#setClassID(org.apache.poi.hpsf.ClassID)
|
||||||
|
*/
|
||||||
|
public void setClassID(final ClassID classID)
|
||||||
|
{
|
||||||
|
delegate.setClassID(classID);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#setFormat(int)
|
||||||
|
*/
|
||||||
|
public void setFormat(final int format)
|
||||||
|
{
|
||||||
|
delegate.setFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#setOSVersion(int)
|
||||||
|
*/
|
||||||
|
public void setOSVersion(final int osVersion)
|
||||||
|
{
|
||||||
|
delegate.setOSVersion(osVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#toInputStream()
|
||||||
|
*/
|
||||||
|
public InputStream toInputStream() throws IOException, WritingNotSupportedException
|
||||||
|
{
|
||||||
|
return delegate.toInputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#write(org.apache.poi.poifs.filesystem.DirectoryEntry, java.lang.String)
|
||||||
|
*/
|
||||||
|
public void write(final DirectoryEntry dir, final String name) throws WritingNotSupportedException, IOException
|
||||||
|
{
|
||||||
|
delegate.write(dir, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.MutablePropertySet#write(java.io.OutputStream)
|
||||||
|
*/
|
||||||
|
public void write(final OutputStream out) throws WritingNotSupportedException, IOException
|
||||||
|
{
|
||||||
|
delegate.write(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#equals(java.lang.Object)
|
||||||
|
*/
|
||||||
|
public boolean equals(final Object o)
|
||||||
|
{
|
||||||
|
return delegate.equals(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#getProperties()
|
||||||
|
*/
|
||||||
|
public Property[] getProperties() throws NoSingleSectionException
|
||||||
|
{
|
||||||
|
return delegate.getProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#getProperty(int)
|
||||||
|
*/
|
||||||
|
protected Object getProperty(final int id) throws NoSingleSectionException
|
||||||
|
{
|
||||||
|
return delegate.getProperty(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#getPropertyBooleanValue(int)
|
||||||
|
*/
|
||||||
|
protected boolean getPropertyBooleanValue(final int id) throws NoSingleSectionException
|
||||||
|
{
|
||||||
|
return delegate.getPropertyBooleanValue(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#getPropertyIntValue(int)
|
||||||
|
*/
|
||||||
|
protected int getPropertyIntValue(final int id) throws NoSingleSectionException
|
||||||
|
{
|
||||||
|
return delegate.getPropertyIntValue(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#hashCode()
|
||||||
|
*/
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return delegate.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#toString()
|
||||||
|
*/
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return delegate.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.apache.poi.hpsf.PropertySet#wasNull()
|
||||||
|
*/
|
||||||
|
public boolean wasNull() throws NoSingleSectionException
|
||||||
|
{
|
||||||
|
return delegate.wasNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,23 +1,25 @@
|
|||||||
|
/*
|
||||||
/* ====================================================================
|
* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
* Copyright 2002-2006 Apache Software Foundation
|
||||||
|
*
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||||
you may not use this file except in compliance with the License.
|
* use this file except in compliance with the License. You may obtain a copy of
|
||||||
You may obtain a copy of the License at
|
* the License at
|
||||||
|
*
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
See the License for the specific language governing permissions and
|
* License for the specific language governing permissions and limitations under
|
||||||
limitations under the License.
|
* the License.
|
||||||
==================================================================== */
|
* ====================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
package org.apache.poi.hpsf;
|
package org.apache.poi.hpsf;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +27,7 @@ import org.apache.poi.hpsf.wellknown.PropertyIDMap;
|
|||||||
* Microsoft Office document.</p>
|
* Microsoft Office document.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute <a
|
* @author Rainer Klute <a
|
||||||
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
* @see DocumentSummaryInformation
|
* @see DocumentSummaryInformation
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
* @since 2002-02-09
|
* @since 2002-02-09
|
||||||
@ -34,8 +36,8 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The document name a summary information stream usually has
|
* <p>The document name a summary information stream usually has in a POIFS
|
||||||
* in a POIFS filesystem.</p>
|
* filesystem.</p>
|
||||||
*/
|
*/
|
||||||
public static final String DEFAULT_STREAM_NAME = "\005SummaryInformation";
|
public static final String DEFAULT_STREAM_NAME = "\005SummaryInformation";
|
||||||
|
|
||||||
@ -46,23 +48,23 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
* PropertySet}.</p>
|
* PropertySet}.</p>
|
||||||
*
|
*
|
||||||
* @param ps A property set which should be created from a summary
|
* @param ps A property set which should be created from a summary
|
||||||
* information stream.
|
* information stream.
|
||||||
* @throws UnexpectedPropertySetTypeException if <var>ps</var>
|
* @throws UnexpectedPropertySetTypeException if <var>ps</var> does not
|
||||||
* does not contain a summary information stream.
|
* contain a summary information stream.
|
||||||
*/
|
*/
|
||||||
public SummaryInformation(final PropertySet ps)
|
public SummaryInformation(final PropertySet ps)
|
||||||
throws UnexpectedPropertySetTypeException
|
throws UnexpectedPropertySetTypeException
|
||||||
{
|
{
|
||||||
super(ps);
|
super(ps);
|
||||||
if (!isSummaryInformation())
|
if (!isSummaryInformation())
|
||||||
throw new UnexpectedPropertySetTypeException
|
throw new UnexpectedPropertySetTypeException("Not a "
|
||||||
("Not a " + getClass().getName());
|
+ getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's title (or <code>null</code>).</p>
|
* <p>Returns the title (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The title or <code>null</code>
|
* @return The title or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -74,7 +76,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's subject (or <code>null</code>).</p>
|
* <p>Sets the title.</p>
|
||||||
|
*
|
||||||
|
* @param title The title to set.
|
||||||
|
*/
|
||||||
|
public void setTitle(final String title)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_TITLE, title);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the title.</p>
|
||||||
|
*/
|
||||||
|
public void removeTitle()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_TITLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the subject (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The subject or <code>null</code>
|
* @return The subject or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -86,7 +112,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's author (or <code>null</code>).</p>
|
* <p>Sets the subject.</p>
|
||||||
|
*
|
||||||
|
* @param subject The subject to set.
|
||||||
|
*/
|
||||||
|
public void setSubject(final String subject)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_SUBJECT, subject);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the subject.</p>
|
||||||
|
*/
|
||||||
|
public void removeSubject()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_SUBJECT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the author (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The author or <code>null</code>
|
* @return The author or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -98,7 +148,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's keywords (or <code>null</code>).</p>
|
* <p>Sets the author.</p>
|
||||||
|
*
|
||||||
|
* @param author The author to set.
|
||||||
|
*/
|
||||||
|
public void setAuthor(final String author)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_AUTHOR, author);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the author.</p>
|
||||||
|
*/
|
||||||
|
public void removeAuthor()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_AUTHOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the keywords (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The keywords or <code>null</code>
|
* @return The keywords or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -110,7 +184,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's comments (or <code>null</code>).</p>
|
* <p>Sets the keywords.</p>
|
||||||
|
*
|
||||||
|
* @param keywords The keywords to set.
|
||||||
|
*/
|
||||||
|
public void setKeywords(final String keywords)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_KEYWORDS, keywords);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the keywords.</p>
|
||||||
|
*/
|
||||||
|
public void removeKeywords()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_KEYWORDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the comments (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The comments or <code>null</code>
|
* @return The comments or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -122,7 +220,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's template (or <code>null</code>).</p>
|
* <p>Sets the comments.</p>
|
||||||
|
*
|
||||||
|
* @param comments The comments to set.
|
||||||
|
*/
|
||||||
|
public void setComments(final String comments)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_COMMENTS, comments);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the comments.</p>
|
||||||
|
*/
|
||||||
|
public void removeComments()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_COMMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the template (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The template or <code>null</code>
|
* @return The template or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -134,7 +256,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's last author (or <code>null</code>).</p>
|
* <p>Sets the template.</p>
|
||||||
|
*
|
||||||
|
* @param template The template to set.
|
||||||
|
*/
|
||||||
|
public void setTemplate(final String template)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_TEMPLATE, template);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the template.</p>
|
||||||
|
*/
|
||||||
|
public void removeTemplate()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_TEMPLATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the last author (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The last author or <code>null</code>
|
* @return The last author or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -146,8 +292,31 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's revision number (or
|
* <p>Sets the last author.</p>
|
||||||
* <code>null</code>). </p>
|
*
|
||||||
|
* @param lastAuthor The last author to set.
|
||||||
|
*/
|
||||||
|
public void setLastAuthor(final String lastAuthor)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_LASTAUTHOR, lastAuthor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the last author.</p>
|
||||||
|
*/
|
||||||
|
public void removeLastAuthor()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_LASTAUTHOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the revision number (or <code>null</code>). </p>
|
||||||
*
|
*
|
||||||
* @return The revision number or <code>null</code>
|
* @return The revision number or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -159,11 +328,35 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the total time spent in editing the document
|
* <p>Sets the revision number.</p>
|
||||||
* (or <code>0</code>).</p>
|
*
|
||||||
|
* @param revNumber The revision number to set.
|
||||||
|
*/
|
||||||
|
public void setRevNumber(final String revNumber)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_REVNUMBER, revNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the revision number.</p>
|
||||||
|
*/
|
||||||
|
public void removeRevNumber()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_REVNUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the total time spent in editing the document (or
|
||||||
|
* <code>0</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The total time spent in editing the document or 0 if the {@link
|
* @return The total time spent in editing the document or 0 if the {@link
|
||||||
* SummaryInformation} does not contain this information.
|
* SummaryInformation} does not contain this information.
|
||||||
*/
|
*/
|
||||||
public long getEditTime()
|
public long getEditTime()
|
||||||
{
|
{
|
||||||
@ -177,8 +370,32 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's last printed time (or
|
* <p>Sets the total time spent in editing the document.</p>
|
||||||
* <code>null</code>).</p>
|
*
|
||||||
|
* @param time The time to set.
|
||||||
|
*/
|
||||||
|
public void setEditTime(final long time)
|
||||||
|
{
|
||||||
|
final Date d = Util.filetimeToDate(time);
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_EDITTIME, Variant.VT_FILETIME, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Remove the total time spent in editing the document.</p>
|
||||||
|
*/
|
||||||
|
public void removeEditTime()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_EDITTIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the last printed time (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The last printed time or <code>null</code>
|
* @return The last printed time or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -190,8 +407,32 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's creation time (or
|
* <p>Sets the lastPrinted.</p>
|
||||||
* <code>null</code>).</p>
|
*
|
||||||
|
* @param lastPrinted The lastPrinted to set.
|
||||||
|
*/
|
||||||
|
public void setLastPrinted(final Date lastPrinted)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_LASTPRINTED, Variant.VT_FILETIME,
|
||||||
|
lastPrinted);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the lastPrinted.</p>
|
||||||
|
*/
|
||||||
|
public void removeLastPrinted()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_LASTPRINTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the creation time (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The creation time or <code>null</code>
|
* @return The creation time or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -203,8 +444,32 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's last save time (or
|
* <p>Sets the creation time.</p>
|
||||||
* <code>null</code>).</p>
|
*
|
||||||
|
* @param createDateTime The creation time to set.
|
||||||
|
*/
|
||||||
|
public void setCreateDateTime(final Date createDateTime)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_CREATE_DTM, Variant.VT_FILETIME,
|
||||||
|
createDateTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the creation time.</p>
|
||||||
|
*/
|
||||||
|
public void removeCreateDateTime()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_CREATE_DTM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the last save time (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The last save time or <code>null</code>
|
* @return The last save time or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -216,11 +481,37 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's page count or 0 if the {@link
|
* <p>Sets the total time spent in editing the document.</p>
|
||||||
* SummaryInformation} does not contain a page count.</p>
|
*
|
||||||
|
* @param time The time to set.
|
||||||
|
*/
|
||||||
|
public void setLastSaveDateTime(final Date time)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s
|
||||||
|
.setProperty(PropertyIDMap.PID_LASTSAVE_DTM,
|
||||||
|
Variant.VT_FILETIME, time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Remove the total time spent in editing the document.</p>
|
||||||
|
*/
|
||||||
|
public void removeLastSaveDateTime()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_LASTSAVE_DTM);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the page count or 0 if the {@link SummaryInformation} does
|
||||||
|
* not contain a page count.</p>
|
||||||
*
|
*
|
||||||
* @return The page count or 0 if the {@link SummaryInformation} does not
|
* @return The page count or 0 if the {@link SummaryInformation} does not
|
||||||
* contain a page count.
|
* contain a page count.
|
||||||
*/
|
*/
|
||||||
public int getPageCount()
|
public int getPageCount()
|
||||||
{
|
{
|
||||||
@ -230,8 +521,32 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's word count or 0 if the {@link
|
* <p>Sets the page count.</p>
|
||||||
* SummaryInformation} does not contain a word count.</p>
|
*
|
||||||
|
* @param pageCount The page count to set.
|
||||||
|
*/
|
||||||
|
public void setPageCount(final int pageCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_PAGECOUNT, pageCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the page count.</p>
|
||||||
|
*/
|
||||||
|
public void removePageCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_PAGECOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the word count or 0 if the {@link SummaryInformation} does
|
||||||
|
* not contain a word count.</p>
|
||||||
*
|
*
|
||||||
* @return The word count or <code>null</code>
|
* @return The word count or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -243,8 +558,32 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's character count or 0 if the {@link
|
* <p>Sets the word count.</p>
|
||||||
* SummaryInformation} does not contain a char count.</p>
|
*
|
||||||
|
* @param wordCount The word count to set.
|
||||||
|
*/
|
||||||
|
public void setWordCount(final int wordCount)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_WORDCOUNT, wordCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the word count.</p>
|
||||||
|
*/
|
||||||
|
public void removeWordCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_WORDCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the character count or 0 if the {@link SummaryInformation}
|
||||||
|
* does not contain a char count.</p>
|
||||||
*
|
*
|
||||||
* @return The character count or <code>null</code>
|
* @return The character count or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -256,14 +595,38 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's thumbnail (or <code>null</code>)
|
* <p>Sets the character count.</p>
|
||||||
* <strong>when this method is implemented. Please note that the
|
|
||||||
* return type is likely to change!</strong></p>
|
|
||||||
*
|
*
|
||||||
* <p><strong>Hint to developers:</strong> Drew Varner <Drew.Varner -at-
|
* @param charCount The character count to set.
|
||||||
* sc.edu> said that this is an image in WMF or Clipboard (BMP?) format.
|
*/
|
||||||
* However, we won't do any conversion into any image type but instead just
|
public void setCharCount(final int charCount)
|
||||||
* return a byte array.</p>
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_CHARCOUNT, charCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the character count.</p>
|
||||||
|
*/
|
||||||
|
public void removeCharCount()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_CHARCOUNT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the thumbnail (or <code>null</code>) <strong>when this
|
||||||
|
* method is implemented. Please note that the return type is likely to
|
||||||
|
* change!</strong></p>
|
||||||
|
*
|
||||||
|
* <p><strong>Hint to developers:</strong> Drew Varner <Drew.Varner
|
||||||
|
* -at- sc.edu> said that this is an image in WMF or Clipboard (BMP?)
|
||||||
|
* format. However, we won't do any conversion into any image type but
|
||||||
|
* instead just return a byte array.</p>
|
||||||
*
|
*
|
||||||
* @return The thumbnail or <code>null</code>
|
* @return The thumbnail or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -275,8 +638,32 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns the stream's application name (or
|
* <p>Sets the thumbnail.</p>
|
||||||
* <code>null</code>).</p>
|
*
|
||||||
|
* @param thumbnail The thumbnail to set.
|
||||||
|
*/
|
||||||
|
public void setThumbnail(final byte[] thumbnail)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_THUMBNAIL, /* FIXME: */
|
||||||
|
Variant.VT_LPSTR, thumbnail);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the thumbnail.</p>
|
||||||
|
*/
|
||||||
|
public void removeThumbnail()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_THUMBNAIL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the application name (or <code>null</code>).</p>
|
||||||
*
|
*
|
||||||
* @return The application name or <code>null</code>
|
* @return The application name or <code>null</code>
|
||||||
*/
|
*/
|
||||||
@ -288,32 +675,46 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Returns a security code which is one of the following
|
* <p>Sets the application name.</p>
|
||||||
* values:</p>
|
*
|
||||||
|
* @param applicationName The application name to set.
|
||||||
|
*/
|
||||||
|
public void setApplicationName(final String applicationName)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_APPNAME, applicationName);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the application name.</p>
|
||||||
|
*/
|
||||||
|
public void removeApplicationName()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_APPNAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns a security code which is one of the following values:</p>
|
||||||
*
|
*
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>
|
|
||||||
* <p>0 if the {@link SummaryInformation} does not contain a
|
|
||||||
* security field or if there is no security on the
|
|
||||||
* document. Use {@link #wasNull} to distinguish between the
|
|
||||||
* two cases!</p>
|
|
||||||
* </li>
|
|
||||||
*
|
*
|
||||||
* <li>
|
* <li><p>0 if the {@link SummaryInformation} does not contain a
|
||||||
* <p>1 if the document is password protected</p>
|
* security field or if there is no security on the document. Use
|
||||||
* </li>
|
* {@link PropertySet#wasNull()} to distinguish between the two
|
||||||
|
* cases!</p></li>
|
||||||
*
|
*
|
||||||
* <li>
|
* <li><p>1 if the document is password protected</p></li>
|
||||||
* <p>2 if the document is read-only recommended</p>
|
|
||||||
* </li>
|
|
||||||
*
|
*
|
||||||
* <li>
|
* <li><p>2 if the document is read-only recommended</p></li>
|
||||||
* <p>4 if the document is read-only enforced</p>
|
|
||||||
* </li>
|
|
||||||
*
|
*
|
||||||
* <li>
|
* <li><p>4 if the document is read-only enforced</p></li>
|
||||||
* <p>8 if the document is locked for annotations</p>
|
*
|
||||||
* </li>
|
* <li><p>8 if the document is locked for annotations</p></li>
|
||||||
*
|
*
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
@ -324,4 +725,28 @@ public class SummaryInformation extends SpecialPropertySet
|
|||||||
return getPropertyIntValue(PropertyIDMap.PID_SECURITY);
|
return getPropertyIntValue(PropertyIDMap.PID_SECURITY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Sets the security code.</p>
|
||||||
|
*
|
||||||
|
* @param security The security code to set.
|
||||||
|
*/
|
||||||
|
public void setSecurity(final int security)
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.setProperty(PropertyIDMap.PID_SECURITY, security);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Removes the security code.</p>
|
||||||
|
*/
|
||||||
|
public void removeSecurity()
|
||||||
|
{
|
||||||
|
final MutableSection s = (MutableSection) getFirstSection();
|
||||||
|
s.removeProperty(PropertyIDMap.PID_SECURITY);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -46,7 +45,7 @@ public class TypeWriter
|
|||||||
{
|
{
|
||||||
final int length = LittleEndian.SHORT_SIZE;
|
final int length = LittleEndian.SHORT_SIZE;
|
||||||
byte[] buffer = new byte[length];
|
byte[] buffer = new byte[length];
|
||||||
LittleEndian.putUShort(buffer, 0, n);
|
LittleEndian.putShort(buffer, 0, n); // FIXME: unsigned
|
||||||
out.write(buffer, 0, length);
|
out.write(buffer, 0, length);
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
@ -74,6 +73,27 @@ public class TypeWriter
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Writes a eight-byte value to an output stream.</p>
|
||||||
|
*
|
||||||
|
* @param out The stream to write to.
|
||||||
|
* @param n The value to write.
|
||||||
|
* @exception IOException if an I/O error occurs
|
||||||
|
* @return The number of bytes written to the output stream.
|
||||||
|
*/
|
||||||
|
public static int writeToStream(final OutputStream out, final long n)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
final int l = LittleEndian.LONG_SIZE;
|
||||||
|
final byte[] buffer = new byte[l];
|
||||||
|
LittleEndian.putLong(buffer, 0, n);
|
||||||
|
out.write(buffer, 0, l);
|
||||||
|
return l;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Writes an unsigned two-byte value to an output stream.</p>
|
* <p>Writes an unsigned two-byte value to an output stream.</p>
|
||||||
*
|
*
|
||||||
@ -118,6 +138,7 @@ public class TypeWriter
|
|||||||
*
|
*
|
||||||
* @param out The stream to write to
|
* @param out The stream to write to
|
||||||
* @param n The value to write
|
* @param n The value to write
|
||||||
|
* @return The number of bytes written
|
||||||
* @exception IOException if an I/O error occurs
|
* @exception IOException if an I/O error occurs
|
||||||
*/
|
*/
|
||||||
public static int writeToStream(final OutputStream out, final ClassID n)
|
public static int writeToStream(final OutputStream out, final ClassID n)
|
||||||
@ -137,7 +158,10 @@ public class TypeWriter
|
|||||||
*
|
*
|
||||||
* @param out The stream to write to
|
* @param out The stream to write to
|
||||||
* @param properties The array to write to the stream
|
* @param properties The array to write to the stream
|
||||||
|
* @param codepage The codepage number to use for writing strings
|
||||||
* @exception IOException if an I/O error occurs
|
* @exception IOException if an I/O error occurs
|
||||||
|
* @throws UnsupportedVariantTypeException if HPSF does not support some
|
||||||
|
* variant type.
|
||||||
*/
|
*/
|
||||||
public static void writeToStream(final OutputStream out,
|
public static void writeToStream(final OutputStream out,
|
||||||
final Property[] properties,
|
final Property[] properties,
|
||||||
@ -152,7 +176,7 @@ public class TypeWriter
|
|||||||
* ID and offset into the stream. */
|
* ID and offset into the stream. */
|
||||||
for (int i = 0; i < properties.length; i++)
|
for (int i = 0; i < properties.length; i++)
|
||||||
{
|
{
|
||||||
final Property p = (Property) properties[i];
|
final Property p = properties[i];
|
||||||
writeUIntToStream(out, p.getID());
|
writeUIntToStream(out, p.getID());
|
||||||
writeUIntToStream(out, p.getSize());
|
writeUIntToStream(out, p.getSize());
|
||||||
}
|
}
|
||||||
@ -160,7 +184,7 @@ public class TypeWriter
|
|||||||
/* Write the properties themselves. */
|
/* Write the properties themselves. */
|
||||||
for (int i = 0; i < properties.length; i++)
|
for (int i = 0; i < properties.length; i++)
|
||||||
{
|
{
|
||||||
final Property p = (Property) properties[i];
|
final Property p = properties[i];
|
||||||
long type = p.getType();
|
long type = p.getType();
|
||||||
writeUIntToStream(out, type);
|
writeUIntToStream(out, type);
|
||||||
VariantSupport.write(out, (int) type, p.getValue(), codepage);
|
VariantSupport.write(out, (int) type, p.getValue(), codepage);
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ import org.apache.poi.util.HexDump;
|
|||||||
/**
|
/**
|
||||||
* <p>This exception is thrown if HPSF encounters a variant type that isn't
|
* <p>This exception is thrown if HPSF encounters a variant type that isn't
|
||||||
* supported yet. Although a variant type is unsupported the value can still be
|
* supported yet. Although a variant type is unsupported the value can still be
|
||||||
* retrieved using the {@link #getValue} method.</p>
|
* retrieved using the {@link VariantTypeException#getValue} method.</p>
|
||||||
*
|
*
|
||||||
* <p>Obviously this class should disappear some day.</p>
|
* <p>Obviously this class should disappear some day.</p>
|
||||||
*
|
*
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -152,6 +151,21 @@ public class Util
|
|||||||
public static Date filetimeToDate(final int high, final int low)
|
public static Date filetimeToDate(final int high, final int low)
|
||||||
{
|
{
|
||||||
final long filetime = ((long) high) << 32 | (low & 0xffffffffL);
|
final long filetime = ((long) high) << 32 | (low & 0xffffffffL);
|
||||||
|
return filetimeToDate(filetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Converts a Windows FILETIME into a {@link Date}. The Windows
|
||||||
|
* FILETIME structure holds a date and time associated with a
|
||||||
|
* file. The structure identifies a 64-bit integer specifying the
|
||||||
|
* number of 100-nanosecond intervals which have passed since
|
||||||
|
* January 1, 1601.</p>
|
||||||
|
*
|
||||||
|
* @param filetime The filetime to convert.
|
||||||
|
* @return The Windows FILETIME as a {@link Date}.
|
||||||
|
*/
|
||||||
|
public static Date filetimeToDate(final long filetime)
|
||||||
|
{
|
||||||
final long ms_since_16010101 = filetime / (1000 * 10);
|
final long ms_since_16010101 = filetime / (1000 * 10);
|
||||||
final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF;
|
final long ms_since_19700101 = ms_since_16010101 - EPOCH_DIFF;
|
||||||
return new Date(ms_since_19700101);
|
return new Date(ms_since_19700101);
|
||||||
@ -165,7 +179,8 @@ public class Util
|
|||||||
* @param date The date to be converted
|
* @param date The date to be converted
|
||||||
* @return The filetime
|
* @return The filetime
|
||||||
*
|
*
|
||||||
* @see #filetimeToDate
|
* @see #filetimeToDate(long)
|
||||||
|
* @see #filetimeToDate(int, int)
|
||||||
*/
|
*/
|
||||||
public static long dateToFileTime(final Date date)
|
public static long dateToFileTime(final Date date)
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -157,16 +157,25 @@ public class VariantSupport extends Variant
|
|||||||
* Read a short. In Java it is represented as an
|
* Read a short. In Java it is represented as an
|
||||||
* Integer object.
|
* Integer object.
|
||||||
*/
|
*/
|
||||||
value = new Integer(LittleEndian.getUShort(src, o1));
|
value = new Integer(LittleEndian.getShort(src, o1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_I4:
|
case Variant.VT_I4:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Read a word. In Java it is represented as a
|
* Read a word. In Java it is represented as an
|
||||||
|
* Integer object.
|
||||||
|
*/
|
||||||
|
value = new Integer(LittleEndian.getInt(src, o1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Variant.VT_I8:
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Read a double word. In Java it is represented as a
|
||||||
* Long object.
|
* Long object.
|
||||||
*/
|
*/
|
||||||
value = new Long(LittleEndian.getUInt(src, o1));
|
value = new Long(LittleEndian.getLong(src, o1));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_R8:
|
case Variant.VT_R8:
|
||||||
@ -204,9 +213,9 @@ public class VariantSupport extends Variant
|
|||||||
last--;
|
last--;
|
||||||
final int l = (int) (last - first + 1);
|
final int l = (int) (last - first + 1);
|
||||||
value = codepage != -1 ?
|
value = codepage != -1 ?
|
||||||
new String(src, (int) first, l,
|
new String(src, first, l,
|
||||||
codepageToEncoding(codepage)) :
|
codepageToEncoding(codepage)) :
|
||||||
new String(src, (int) first, l);
|
new String(src, first, l);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_LPWSTR:
|
case Variant.VT_LPWSTR:
|
||||||
@ -240,7 +249,7 @@ public class VariantSupport extends Variant
|
|||||||
{
|
{
|
||||||
final byte[] v = new byte[l1];
|
final byte[] v = new byte[l1];
|
||||||
for (int i = 0; i < l1; i++)
|
for (int i = 0; i < l1; i++)
|
||||||
v[i] = src[(int) (o1 + i)];
|
v[i] = src[(o1 + i)];
|
||||||
value = v;
|
value = v;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -263,7 +272,7 @@ public class VariantSupport extends Variant
|
|||||||
{
|
{
|
||||||
final byte[] v = new byte[l1];
|
final byte[] v = new byte[l1];
|
||||||
for (int i = 0; i < l1; i++)
|
for (int i = 0; i < l1; i++)
|
||||||
v[i] = src[(int) (o1 + i)];
|
v[i] = src[(o1 + i)];
|
||||||
throw new ReadingNotSupportedException(type, v);
|
throw new ReadingNotSupportedException(type, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -397,8 +406,8 @@ public class VariantSupport extends Variant
|
|||||||
char[] s = Util.pad4((String) value);
|
char[] s = Util.pad4((String) value);
|
||||||
for (int i = 0; i < s.length; i++)
|
for (int i = 0; i < s.length; i++)
|
||||||
{
|
{
|
||||||
final int high = (int) ((s[i] & 0x0000ff00) >> 8);
|
final int high = ((s[i] & 0x0000ff00) >> 8);
|
||||||
final int low = (int) (s[i] & 0x000000ff);
|
final int low = (s[i] & 0x000000ff);
|
||||||
final byte highb = (byte) high;
|
final byte highb = (byte) high;
|
||||||
final byte lowb = (byte) low;
|
final byte lowb = (byte) low;
|
||||||
out.write(lowb);
|
out.write(lowb);
|
||||||
@ -431,8 +440,21 @@ public class VariantSupport extends Variant
|
|||||||
}
|
}
|
||||||
case Variant.VT_I4:
|
case Variant.VT_I4:
|
||||||
{
|
{
|
||||||
|
if (!(value instanceof Integer))
|
||||||
|
{
|
||||||
|
throw new ClassCastException("Could not cast an object to "
|
||||||
|
+ Integer.class.toString() + ": "
|
||||||
|
+ value.getClass().toString() + ", "
|
||||||
|
+ value.toString());
|
||||||
|
}
|
||||||
length += TypeWriter.writeToStream(out,
|
length += TypeWriter.writeToStream(out,
|
||||||
((Long) value).intValue());
|
((Integer) value).intValue());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Variant.VT_I8:
|
||||||
|
{
|
||||||
|
TypeWriter.writeToStream(out, ((Long) value).longValue());
|
||||||
|
length = LittleEndianConsts.LONG_SIZE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Variant.VT_R8:
|
case Variant.VT_R8:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
@ -232,6 +231,11 @@ public class PropertyIDMap extends HashMap
|
|||||||
*/
|
*/
|
||||||
public static final int PID_LINKSDIRTY = 16;
|
public static final int PID_LINKSDIRTY = 16;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>The highest well-known property ID. Applications are free to use higher values for custom purposes.</p>
|
||||||
|
*/
|
||||||
|
public static final int PID_MAX = PID_LINKSDIRTY;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -53,16 +52,23 @@ public class SectionIDMap extends HashMap
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>The DocumentSummaryInformation's first section's format
|
* <p>The DocumentSummaryInformation's first and second sections' format
|
||||||
* ID. The second section has a different format ID which is not
|
* ID.</p>
|
||||||
* well-known.</p>
|
|
||||||
*/
|
*/
|
||||||
public static final byte[] DOCUMENT_SUMMARY_INFORMATION_ID = new byte[]
|
public static final byte[][] DOCUMENT_SUMMARY_INFORMATION_ID = new byte[][]
|
||||||
{
|
{
|
||||||
(byte) 0xD5, (byte) 0xCD, (byte) 0xD5, (byte) 0x02,
|
{
|
||||||
(byte) 0x2E, (byte) 0x9C, (byte) 0x10, (byte) 0x1B,
|
(byte) 0xD5, (byte) 0xCD, (byte) 0xD5, (byte) 0x02,
|
||||||
(byte) 0x93, (byte) 0x97, (byte) 0x08, (byte) 0x00,
|
(byte) 0x2E, (byte) 0x9C, (byte) 0x10, (byte) 0x1B,
|
||||||
(byte) 0x2B, (byte) 0x2C, (byte) 0xF9, (byte) 0xAE
|
(byte) 0x93, (byte) 0x97, (byte) 0x08, (byte) 0x00,
|
||||||
|
(byte) 0x2B, (byte) 0x2C, (byte) 0xF9, (byte) 0xAE
|
||||||
|
},
|
||||||
|
{
|
||||||
|
(byte) 0xD5, (byte) 0xCD, (byte) 0xD5, (byte) 0x05,
|
||||||
|
(byte) 0x2E, (byte) 0x9C, (byte) 0x10, (byte) 0x1B,
|
||||||
|
(byte) 0x93, (byte) 0x97, (byte) 0x08, (byte) 0x00,
|
||||||
|
(byte) 0x2B, (byte) 0x2C, (byte) 0xF9, (byte) 0xAE
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -91,7 +97,7 @@ public class SectionIDMap extends HashMap
|
|||||||
final SectionIDMap m = new SectionIDMap();
|
final SectionIDMap m = new SectionIDMap();
|
||||||
m.put(SUMMARY_INFORMATION_ID,
|
m.put(SUMMARY_INFORMATION_ID,
|
||||||
PropertyIDMap.getSummaryInformationProperties());
|
PropertyIDMap.getSummaryInformationProperties());
|
||||||
m.put(DOCUMENT_SUMMARY_INFORMATION_ID,
|
m.put(DOCUMENT_SUMMARY_INFORMATION_ID[0],
|
||||||
PropertyIDMap.getDocumentSummaryInformationProperties());
|
PropertyIDMap.getDocumentSummaryInformationProperties());
|
||||||
defaultMap = m;
|
defaultMap = m;
|
||||||
}
|
}
|
||||||
@ -116,8 +122,7 @@ public class SectionIDMap extends HashMap
|
|||||||
public static String getPIDString(final byte[] sectionFormatID,
|
public static String getPIDString(final byte[] sectionFormatID,
|
||||||
final long pid)
|
final long pid)
|
||||||
{
|
{
|
||||||
final PropertyIDMap m =
|
final PropertyIDMap m = getInstance().get(sectionFormatID);
|
||||||
(PropertyIDMap) getInstance().get(sectionFormatID);
|
|
||||||
if (m == null)
|
if (m == null)
|
||||||
return UNDEFINED;
|
return UNDEFINED;
|
||||||
else
|
else
|
||||||
@ -178,7 +183,8 @@ public class SectionIDMap extends HashMap
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Use {@link #put(byte[], PropertyIDMap)} instead!
|
* @deprecated Use {@link #put(byte[], PropertyIDMap)} instead!
|
||||||
* @link #put(byte[], PropertyIDMap)
|
*
|
||||||
|
* @see #put(byte[], PropertyIDMap)
|
||||||
*
|
*
|
||||||
* @param key This parameter remains undocumented since the method is
|
* @param key This parameter remains undocumented since the method is
|
||||||
* deprecated.
|
* deprecated.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2003-2004 Apache Software Foundation
|
Copyright 2003-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -64,9 +64,9 @@ public class LittleEndian
|
|||||||
short num = (short) getNumber(data, offset, SHORT_SIZE);
|
short num = (short) getNumber(data, offset, SHORT_SIZE);
|
||||||
int retNum;
|
int retNum;
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
retNum = ((int) Short.MAX_VALUE + 1) * 2 + (int) num;
|
retNum = (Short.MAX_VALUE + 1) * 2 + num;
|
||||||
} else {
|
} else {
|
||||||
retNum = (int) num;
|
retNum = num;
|
||||||
}
|
}
|
||||||
return retNum;
|
return retNum;
|
||||||
}
|
}
|
||||||
@ -163,9 +163,9 @@ public class LittleEndian
|
|||||||
int num = (int) getNumber(data, offset, INT_SIZE);
|
int num = (int) getNumber(data, offset, INT_SIZE);
|
||||||
long retNum;
|
long retNum;
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
retNum = ((long) Integer.MAX_VALUE + 1) * 2 + (long) num;
|
retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
|
||||||
} else {
|
} else {
|
||||||
retNum = (int) num;
|
retNum = num;
|
||||||
}
|
}
|
||||||
return retNum;
|
return retNum;
|
||||||
}
|
}
|
||||||
@ -522,7 +522,7 @@ public class LittleEndian
|
|||||||
*@return Description of the Return Value
|
*@return Description of the Return Value
|
||||||
*/
|
*/
|
||||||
public static int ubyteToInt(byte b) {
|
public static int ubyteToInt(byte b) {
|
||||||
return ((b & 0x80) == 0 ? (int) b : (int) (b & (byte) 0x7f) + 0x80);
|
return ((b & 0x80) == 0 ? (int) b : (b & (byte) 0x7f) + 0x80);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -566,5 +566,22 @@ public class LittleEndian
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Gets an unsigned int value (8 bytes) from a byte array.</p>
|
||||||
|
*
|
||||||
|
* @param data the byte array
|
||||||
|
* @param offset a starting offset into the byte array
|
||||||
|
* @return the unsigned int (32-bit) value in a long
|
||||||
|
*/
|
||||||
|
public static long getULong(final byte[] data, final int offset)
|
||||||
|
{
|
||||||
|
int num = (int) getNumber(data, offset, LONG_SIZE);
|
||||||
|
long retNum;
|
||||||
|
if (num < 0)
|
||||||
|
retNum = ((long) Integer.MAX_VALUE + 1) * 2 + num;
|
||||||
|
else
|
||||||
|
retNum = num;
|
||||||
|
return retNum;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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.basic;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Processes a test method for all OLE2 files in the HPSF test data
|
||||||
|
* directory. Well, this class does not check whether a file is an OLE2 file but
|
||||||
|
* rather whether its name begins with "Test".</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @since 2006-02-11
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class AllDataFilesTester
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Interface specifying how to run a test on a single file.</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute <a
|
||||||
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
|
* @since 2006-02-11
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public interface TestTask
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* <p>Executes a test on a single file.</p>
|
||||||
|
*
|
||||||
|
* @param file the file
|
||||||
|
* @throws Throwable if the method throws anything.
|
||||||
|
*/
|
||||||
|
void runTest(File file) throws Throwable;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tests the simplified custom properties.</p>
|
||||||
|
*
|
||||||
|
* @param task the task to execute
|
||||||
|
* @throws Throwable
|
||||||
|
*/
|
||||||
|
public void runTests(final TestTask task) throws Throwable
|
||||||
|
{
|
||||||
|
final String dataDirName = System.getProperty("HPSF.testdata.path");
|
||||||
|
final File dataDir = new File(dataDirName);
|
||||||
|
final File[] docs = dataDir.listFiles(new FileFilter()
|
||||||
|
{
|
||||||
|
public boolean accept(final File file)
|
||||||
|
{
|
||||||
|
return file.isFile() && file.getName().startsWith("Test");
|
||||||
|
}});
|
||||||
|
for (int i = 0; i < docs.length; i++)
|
||||||
|
{
|
||||||
|
final File doc = docs[i];
|
||||||
|
final Logger logger = Logger.getLogger(getClass().getName());
|
||||||
|
logger.info("Processing file \" " + doc.toString() + "\".");
|
||||||
|
|
||||||
|
/* Execute the test task. */
|
||||||
|
task.runTest(doc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -112,10 +112,8 @@ public class TestBasic extends TestCase
|
|||||||
/**
|
/**
|
||||||
* <p>Checks the names of the files in the POI filesystem. They
|
* <p>Checks the names of the files in the POI filesystem. They
|
||||||
* are expected to be in a certain order.</p>
|
* are expected to be in a certain order.</p>
|
||||||
*
|
|
||||||
* @exception IOException if an I/O exception occurs
|
|
||||||
*/
|
*/
|
||||||
public void testReadFiles() throws IOException
|
public void testReadFiles()
|
||||||
{
|
{
|
||||||
String[] expected = POI_FILES;
|
String[] expected = POI_FILES;
|
||||||
for (int i = 0; i < expected.length; i++)
|
for (int i = 0; i < expected.length; i++)
|
||||||
@ -166,7 +164,7 @@ public class TestBasic extends TestCase
|
|||||||
o = ex;
|
o = ex;
|
||||||
}
|
}
|
||||||
in.close();
|
in.close();
|
||||||
Assert.assertEquals(o.getClass(), expected[i]);
|
Assert.assertEquals(expected[i], o.getClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +221,7 @@ public class TestBasic extends TestCase
|
|||||||
Assert.assertNotNull(s.getProperties());
|
Assert.assertNotNull(s.getProperties());
|
||||||
Assert.assertEquals(17, s.getPropertyCount());
|
Assert.assertEquals(17, s.getPropertyCount());
|
||||||
Assert.assertEquals("Titel", s.getProperty(2));
|
Assert.assertEquals("Titel", s.getProperty(2));
|
||||||
Assert.assertEquals(1764, s.getSize());
|
Assert.assertEquals(1748, s.getSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
@ -22,6 +21,9 @@ import junit.framework.Assert;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hpsf.ClassID;
|
import org.apache.poi.hpsf.ClassID;
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Tests ClassID structure.</p>
|
* <p>Tests ClassID structure.</p>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2004 Apache Software Foundation
|
||||||
|
|
||||||
@ -27,16 +26,18 @@ import java.io.UnsupportedEncodingException;
|
|||||||
import junit.framework.Assert;
|
import junit.framework.Assert;
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
import org.apache.poi.hpsf.HPSFException;
|
import org.apache.poi.hpsf.HPSFException;
|
||||||
import org.apache.poi.hpsf.MarkUnsupportedException;
|
import org.apache.poi.hpsf.MarkUnsupportedException;
|
||||||
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
||||||
import org.apache.poi.hpsf.PropertySet;
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
import org.apache.poi.hpsf.PropertySetFactory;
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
import org.apache.poi.hpsf.SummaryInformation;
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.Variant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Test case for OLE2 files with empty properties. An empty property's type
|
* <p>Test case for OLE2 files with empty properties. An empty property's type
|
||||||
* is {@link Variant.VT_EMPTY}.</p>
|
* is {@link Variant#VT_EMPTY}.</p>
|
||||||
*
|
*
|
||||||
* @author Rainer Klute <a
|
* @author Rainer Klute <a
|
||||||
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
* href="mailto:klute@rainer-klute.de"><klute@rainer-klute.de></a>
|
||||||
@ -96,10 +97,8 @@ public class TestEmptyProperties extends TestCase
|
|||||||
/**
|
/**
|
||||||
* <p>Checks the names of the files in the POI filesystem. They
|
* <p>Checks the names of the files in the POI filesystem. They
|
||||||
* are expected to be in a certain order.</p>
|
* are expected to be in a certain order.</p>
|
||||||
*
|
|
||||||
* @exception IOException if an I/O exception occurs
|
|
||||||
*/
|
*/
|
||||||
public void testReadFiles() throws IOException
|
public void testReadFiles()
|
||||||
{
|
{
|
||||||
String[] expected = POI_FILES;
|
String[] expected = POI_FILES;
|
||||||
for (int i = 0; i < expected.length; i++)
|
for (int i = 0; i < expected.length; i++)
|
||||||
|
827
src/testcases/org/apache/poi/hpsf/basic/TestMetaDataIPI.java
Normal file
827
src/testcases/org/apache/poi/hpsf/basic/TestMetaDataIPI.java
Normal file
@ -0,0 +1,827 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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.basic;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Random;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hpsf.CustomProperties;
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.MarkUnsupportedException;
|
||||||
|
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
||||||
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
|
||||||
|
import org.apache.poi.hpsf.WritingNotSupportedException;
|
||||||
|
import org.apache.poi.poifs.filesystem.DirectoryEntry;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
/**
|
||||||
|
* Basing on: src/examples/src/org/apache/poi/hpsf/examples/ModifyDocumentSummaryInformation.java
|
||||||
|
* This class tests reading and writing of meta data. No actual document is created. All information
|
||||||
|
* is stored in a virtal document in a ByteArrayOutputStream
|
||||||
|
* @author Matthias Günter
|
||||||
|
* @since 2006-03-03
|
||||||
|
* @version $Id: TestEmptyProperties.java 353563 2004-06-22 16:16:33Z klute $
|
||||||
|
*/
|
||||||
|
public class TestMetaDataIPI extends TestCase{
|
||||||
|
|
||||||
|
private ByteArrayOutputStream bout= null; //our store
|
||||||
|
private POIFSFileSystem poifs=null;
|
||||||
|
DirectoryEntry dir = null;
|
||||||
|
DocumentSummaryInformation dsi=null;
|
||||||
|
SummaryInformation si=null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Standard constructor
|
||||||
|
* @param s
|
||||||
|
*/
|
||||||
|
public TestMetaDataIPI(String s ){
|
||||||
|
super(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup is used to get the document ready. Gets the DocumentSummaryInformation and the
|
||||||
|
* SummaryInformation to reasonable values
|
||||||
|
*/
|
||||||
|
public void setUp(){
|
||||||
|
bout=new ByteArrayOutputStream();
|
||||||
|
poifs= new POIFSFileSystem();
|
||||||
|
dir = poifs.getRoot();
|
||||||
|
dsi=null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/* There is no document summary information yet. We have to create a
|
||||||
|
* new one. */
|
||||||
|
dsi = PropertySetFactory.newDocumentSummaryInformation();
|
||||||
|
assertNotNull(dsi);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (NoPropertySetStreamException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (MarkUnsupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (UnexpectedPropertySetTypeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
assertNotNull(dsi);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
si = new SummaryInformation(ps);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/* There is no document summary information yet. We have to create a
|
||||||
|
* new one. */
|
||||||
|
si = PropertySetFactory.newSummaryInformation();
|
||||||
|
assertNotNull(si);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (NoPropertySetStreamException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (MarkUnsupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (UnexpectedPropertySetTypeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
assertNotNull(dsi);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setting a lot of things to null.
|
||||||
|
*/
|
||||||
|
public void tearDown(){
|
||||||
|
bout=null;
|
||||||
|
poifs=null;
|
||||||
|
dir=null;
|
||||||
|
dsi=null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes the ByteArrayOutputStream and reads it into a ByteArrayInputStream.
|
||||||
|
* When finished writing information this method is used in the tests to
|
||||||
|
* start reading from the created document and then the see if the results match.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void closeAndReOpen(){
|
||||||
|
|
||||||
|
try {
|
||||||
|
dsi.write(dir, DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
si.write(dir,SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
} catch (WritingNotSupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
si=null;
|
||||||
|
dsi=null;
|
||||||
|
try {
|
||||||
|
|
||||||
|
poifs.writeFilesystem(bout);
|
||||||
|
bout.flush();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputStream is=new ByteArrayInputStream(bout.toByteArray());
|
||||||
|
assertNotNull(is);
|
||||||
|
POIFSFileSystem poifs=null;
|
||||||
|
try {
|
||||||
|
poifs = new POIFSFileSystem(is);
|
||||||
|
} catch (IOException e) {
|
||||||
|
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
is.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
assertNotNull(poifs);
|
||||||
|
/* Read the document summary information. */
|
||||||
|
DirectoryEntry dir = poifs.getRoot();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
fail();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (NoPropertySetStreamException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (MarkUnsupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (UnexpectedPropertySetTypeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry)
|
||||||
|
dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
dis.close();
|
||||||
|
si = new SummaryInformation(ps);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/* There is no document summary information yet. We have to create a
|
||||||
|
* new one. */
|
||||||
|
si = PropertySetFactory.newSummaryInformation();
|
||||||
|
assertNotNull(si);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (NoPropertySetStreamException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (MarkUnsupportedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
} catch (UnexpectedPropertySetTypeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the most important information in DocumentSummaryInformation and Summary Information and rereads it
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testOne(){
|
||||||
|
|
||||||
|
//DocumentSummaryInformation
|
||||||
|
dsi.setCompany("xxxCompanyxxx");
|
||||||
|
dsi.setManager("xxxManagerxxx");
|
||||||
|
dsi.setCategory("xxxCategoryxxx");
|
||||||
|
|
||||||
|
//SummaryInformation
|
||||||
|
si.setTitle("xxxTitlexxx");
|
||||||
|
si.setAuthor("xxxAuthorxxx");
|
||||||
|
si.setComments("xxxCommentsxxx");
|
||||||
|
si.setKeywords("xxxKeyWordsxxx");
|
||||||
|
si.setSubject("xxxSubjectxxx");
|
||||||
|
|
||||||
|
//Custom Properties (in DocumentSummaryInformation
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put("Key1", "Value1");
|
||||||
|
customProperties.put("Schlüssel2", "Wert2");
|
||||||
|
customProperties.put("Sample Integer", new Integer(12345));
|
||||||
|
customProperties.put("Sample Boolean", new Boolean(true));
|
||||||
|
Date date=new Date();
|
||||||
|
customProperties.put("Sample Date", date);
|
||||||
|
customProperties.put("Sample Double", new Double(-1.0001));
|
||||||
|
customProperties.put("Sample Negative Integer", new Integer(-100000));
|
||||||
|
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
//start reading
|
||||||
|
closeAndReOpen();
|
||||||
|
|
||||||
|
//testing
|
||||||
|
assertNotNull(dsi);
|
||||||
|
assertNotNull(si);
|
||||||
|
|
||||||
|
assertEquals("Category","xxxCategoryxxx",dsi.getCategory());
|
||||||
|
assertEquals("Company","xxxCompanyxxx",dsi.getCompany());
|
||||||
|
assertEquals("Manager","xxxManagerxxx",dsi.getManager());
|
||||||
|
|
||||||
|
assertEquals("","xxxAuthorxxx",si.getAuthor());
|
||||||
|
assertEquals("","xxxTitlexxx",si.getTitle());
|
||||||
|
assertEquals("","xxxCommentsxxx",si.getComments());
|
||||||
|
assertEquals("","xxxKeyWordsxxx",si.getKeywords());
|
||||||
|
assertEquals("","xxxSubjectxxx",si.getSubject());
|
||||||
|
|
||||||
|
|
||||||
|
/* Read the custom properties. If there are no custom properties yet,
|
||||||
|
* the application has to create a new CustomProperties object. It will
|
||||||
|
* serve as a container for custom properties. */
|
||||||
|
customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
String a1=(String) customProperties.get("Key1");
|
||||||
|
assertEquals("Key1","Value1",a1);
|
||||||
|
String a2=(String) customProperties.get("Schlüssel2");
|
||||||
|
assertEquals("Schlüssel2","Wert2",a2);
|
||||||
|
Integer a3=(Integer) customProperties.get("Sample Integer");
|
||||||
|
assertEquals("Sample Number",new Integer(12345),a3);
|
||||||
|
Boolean a4=(Boolean) customProperties.get("Sample Boolean");
|
||||||
|
assertEquals("Sample Boolean",new Boolean(true),a4);
|
||||||
|
Date a5=(Date) customProperties.get("Sample Date");
|
||||||
|
assertEquals("Custom Date:",date,a5);
|
||||||
|
|
||||||
|
Double a6=(Double) customProperties.get("Sample Double");
|
||||||
|
assertEquals("Custom Float",new Double(-1.0001),a6);
|
||||||
|
|
||||||
|
Integer a7=(Integer) customProperties.get("Sample Negative Integer");
|
||||||
|
assertEquals("Neg", new Integer(-100000),a7);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* multiplies a string
|
||||||
|
* @param s Input String
|
||||||
|
* @return the multiplied String
|
||||||
|
*/
|
||||||
|
public String elongate(String s){
|
||||||
|
StringBuffer sb=new StringBuffer();
|
||||||
|
for (int i=0;i<10000;i++){
|
||||||
|
sb.append(s);
|
||||||
|
sb.append(" ");
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test very long input in each of the fields (approx 30-60KB each)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testTwo(){
|
||||||
|
|
||||||
|
String company=elongate("company");
|
||||||
|
String manager=elongate("manager");
|
||||||
|
String category=elongate("category");
|
||||||
|
String title=elongate("title");
|
||||||
|
String author=elongate("author");
|
||||||
|
String comments=elongate("comments");
|
||||||
|
String keywords=elongate("keywords");
|
||||||
|
String subject=elongate("subject");
|
||||||
|
String p1=elongate("p1");
|
||||||
|
String p2=elongate("p2");
|
||||||
|
String k1=elongate("k1");
|
||||||
|
String k2=elongate("k2");
|
||||||
|
|
||||||
|
dsi.setCompany(company);
|
||||||
|
dsi.setManager(manager);
|
||||||
|
dsi.setCategory(category);
|
||||||
|
|
||||||
|
si.setTitle(title);
|
||||||
|
si.setAuthor(author);
|
||||||
|
si.setComments(comments);
|
||||||
|
si.setKeywords(keywords);
|
||||||
|
si.setSubject(subject);
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put(k1, p1);
|
||||||
|
customProperties.put(k2, p2);
|
||||||
|
customProperties.put("Sample Number", new Integer(12345));
|
||||||
|
customProperties.put("Sample Boolean", new Boolean(true));
|
||||||
|
Date date=new Date();
|
||||||
|
customProperties.put("Sample Date", date);
|
||||||
|
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
|
||||||
|
closeAndReOpen();
|
||||||
|
|
||||||
|
assertNotNull(dsi);
|
||||||
|
assertNotNull(si);
|
||||||
|
/* Change the category to "POI example". Any former category value will
|
||||||
|
* be lost. If there has been no category yet, it will be created. */
|
||||||
|
assertEquals("Category",category,dsi.getCategory());
|
||||||
|
assertEquals("Company",company,dsi.getCompany());
|
||||||
|
assertEquals("Manager",manager,dsi.getManager());
|
||||||
|
|
||||||
|
assertEquals("",author,si.getAuthor());
|
||||||
|
assertEquals("",title,si.getTitle());
|
||||||
|
assertEquals("",comments,si.getComments());
|
||||||
|
assertEquals("",keywords,si.getKeywords());
|
||||||
|
assertEquals("",subject,si.getSubject());
|
||||||
|
|
||||||
|
|
||||||
|
/* Read the custom properties. If there are no custom properties
|
||||||
|
* yet, the application has to create a new CustomProperties object.
|
||||||
|
* It will serve as a container for custom properties. */
|
||||||
|
customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
String a1=(String) customProperties.get(k1);
|
||||||
|
assertEquals("Key1",p1,a1);
|
||||||
|
String a2=(String) customProperties.get(k2);
|
||||||
|
assertEquals("Schlüssel2",p2,a2);
|
||||||
|
Integer a3=(Integer) customProperties.get("Sample Number");
|
||||||
|
assertEquals("Sample Number",new Integer(12345),a3);
|
||||||
|
Boolean a4=(Boolean) customProperties.get("Sample Boolean");
|
||||||
|
assertEquals("Sample Boolean",new Boolean(true),a4);
|
||||||
|
Date a5=(Date) customProperties.get("Sample Date");
|
||||||
|
assertEquals("Custom Date:",date,a5);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds strange characters to the string
|
||||||
|
* @param s Input String
|
||||||
|
* @return the multiplied String
|
||||||
|
*/
|
||||||
|
public String strangize(String s){
|
||||||
|
StringBuffer sb=new StringBuffer();
|
||||||
|
String[] umlaute= {"ä","ü","ö","Ü","$","Ö","Ü","É","Ö","@","ç","&"};
|
||||||
|
char j=0;
|
||||||
|
Random rand=new Random();
|
||||||
|
for (int i=0;i<5;i++){
|
||||||
|
sb.append(s);
|
||||||
|
sb.append(" ");
|
||||||
|
j=(char) rand.nextInt(220);
|
||||||
|
j+=33;
|
||||||
|
// System.out.println(j);
|
||||||
|
sb.append(">");
|
||||||
|
sb.append(new Character(j));
|
||||||
|
sb.append("=");
|
||||||
|
sb.append(umlaute[rand.nextInt(umlaute.length)]);
|
||||||
|
sb.append("<");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests with strange characters in keys and data (Umlaute etc.)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testThree(){
|
||||||
|
|
||||||
|
String company=strangize("company");
|
||||||
|
String manager=strangize("manager");
|
||||||
|
String category=strangize("category");
|
||||||
|
String title=strangize("title");
|
||||||
|
String author=strangize("author");
|
||||||
|
String comments=strangize("comments");
|
||||||
|
String keywords=strangize("keywords");
|
||||||
|
String subject=strangize("subject");
|
||||||
|
String p1=strangize("p1");
|
||||||
|
String p2=strangize("p2");
|
||||||
|
String k1=strangize("k1");
|
||||||
|
String k2=strangize("k2");
|
||||||
|
|
||||||
|
dsi.setCompany(company);
|
||||||
|
dsi.setManager(manager);
|
||||||
|
dsi.setCategory(category);
|
||||||
|
|
||||||
|
si.setTitle(title);
|
||||||
|
si.setAuthor(author);
|
||||||
|
si.setComments(comments);
|
||||||
|
si.setKeywords(keywords);
|
||||||
|
si.setSubject(subject);
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put(k1, p1);
|
||||||
|
customProperties.put(k2, p2);
|
||||||
|
customProperties.put("Sample Number", new Integer(12345));
|
||||||
|
customProperties.put("Sample Boolean", new Boolean(false));
|
||||||
|
Date date=new Date(0);
|
||||||
|
customProperties.put("Sample Date", date);
|
||||||
|
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
|
||||||
|
closeAndReOpen();
|
||||||
|
|
||||||
|
assertNotNull(dsi);
|
||||||
|
assertNotNull(si);
|
||||||
|
/* Change the category to "POI example". Any former category value will
|
||||||
|
* be lost. If there has been no category yet, it will be created. */
|
||||||
|
assertEquals("Category",category,dsi.getCategory());
|
||||||
|
assertEquals("Company",company,dsi.getCompany());
|
||||||
|
assertEquals("Manager",manager,dsi.getManager());
|
||||||
|
|
||||||
|
assertEquals("",author,si.getAuthor());
|
||||||
|
assertEquals("",title,si.getTitle());
|
||||||
|
assertEquals("",comments,si.getComments());
|
||||||
|
assertEquals("",keywords,si.getKeywords());
|
||||||
|
assertEquals("",subject,si.getSubject());
|
||||||
|
|
||||||
|
|
||||||
|
/* Read the custom properties. If there are no custom properties yet,
|
||||||
|
* the application has to create a new CustomProperties object. It will
|
||||||
|
* serve as a container for custom properties. */
|
||||||
|
customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
// System.out.println(k1);
|
||||||
|
String a1=(String) customProperties.get(k1);
|
||||||
|
assertEquals("Key1",p1,a1);
|
||||||
|
String a2=(String) customProperties.get(k2);
|
||||||
|
assertEquals("Schlüssel2",p2,a2);
|
||||||
|
Integer a3=(Integer) customProperties.get("Sample Number");
|
||||||
|
assertEquals("Sample Number",new Integer(12345),a3);
|
||||||
|
Boolean a4=(Boolean) customProperties.get("Sample Boolean");
|
||||||
|
assertEquals("Sample Boolean",new Boolean(false),a4);
|
||||||
|
Date a5=(Date) customProperties.get("Sample Date");
|
||||||
|
assertEquals("Custom Date:",date,a5);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterative testing: writing, reading etc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testFour(){
|
||||||
|
for (int i=1;i<100;i++){
|
||||||
|
setUp();
|
||||||
|
testThree();
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* adds strange characters to the string with the adding of unicode characters
|
||||||
|
* @param s Input String
|
||||||
|
* @return the multiplied String
|
||||||
|
*/
|
||||||
|
public String strangizeU(String s){
|
||||||
|
|
||||||
|
StringBuffer sb=new StringBuffer();
|
||||||
|
String[] umlaute= {"ä","ü","ö","Ü","$","Ö","Ü","É","Ö","@","ç","&"};
|
||||||
|
char j=0;
|
||||||
|
Random rand=new Random();
|
||||||
|
for (int i=0;i<5;i++){
|
||||||
|
sb.append(s);
|
||||||
|
sb.append(" ");
|
||||||
|
j=(char) rand.nextInt(220);
|
||||||
|
j+=33;
|
||||||
|
// System.out.println(j);
|
||||||
|
sb.append(">");
|
||||||
|
sb.append(new Character(j));
|
||||||
|
sb.append("=");
|
||||||
|
sb.append(umlaute[rand.nextInt(umlaute.length)]);
|
||||||
|
sb.append("<");
|
||||||
|
}
|
||||||
|
sb.append("äöü\uD840\uDC00");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Unicode test
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testUnicode(){
|
||||||
|
String company=strangizeU("company");
|
||||||
|
String manager=strangizeU("manager");
|
||||||
|
String category=strangizeU("category");
|
||||||
|
String title=strangizeU("title");
|
||||||
|
String author=strangizeU("author");
|
||||||
|
String comments=strangizeU("comments");
|
||||||
|
String keywords=strangizeU("keywords");
|
||||||
|
String subject=strangizeU("subject");
|
||||||
|
String p1=strangizeU("p1");
|
||||||
|
String p2=strangizeU("p2");
|
||||||
|
String k1=strangizeU("k1");
|
||||||
|
String k2=strangizeU("k2");
|
||||||
|
|
||||||
|
dsi.setCompany(company);
|
||||||
|
dsi.setManager(manager);
|
||||||
|
dsi.setCategory(category);
|
||||||
|
|
||||||
|
si.setTitle(title);
|
||||||
|
si.setAuthor(author);
|
||||||
|
si.setComments(comments);
|
||||||
|
si.setKeywords(keywords);
|
||||||
|
si.setSubject(subject);
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put(k1, p1);
|
||||||
|
customProperties.put(k2, p2);
|
||||||
|
customProperties.put("Sample Number", new Integer(12345));
|
||||||
|
customProperties.put("Sample Boolean", new Boolean(true));
|
||||||
|
Date date=new Date();
|
||||||
|
customProperties.put("Sample Date", date);
|
||||||
|
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
|
||||||
|
closeAndReOpen();
|
||||||
|
|
||||||
|
assertNotNull(dsi);
|
||||||
|
assertNotNull(si);
|
||||||
|
/* Change the category to "POI example". Any former category value will
|
||||||
|
* be lost. If there has been no category yet, it will be created. */
|
||||||
|
assertEquals("Category",category,dsi.getCategory());
|
||||||
|
assertEquals("Company",company,dsi.getCompany());
|
||||||
|
assertEquals("Manager",manager,dsi.getManager());
|
||||||
|
|
||||||
|
assertEquals("",author,si.getAuthor());
|
||||||
|
assertEquals("",title,si.getTitle());
|
||||||
|
assertEquals("",comments,si.getComments());
|
||||||
|
assertEquals("",keywords,si.getKeywords());
|
||||||
|
assertEquals("",subject,si.getSubject());
|
||||||
|
|
||||||
|
|
||||||
|
/* Read the custom properties. If there are no custom properties yet,
|
||||||
|
* the application has to create a new CustomProperties object. It will
|
||||||
|
* serve as a container for custom properties. */
|
||||||
|
customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
// System.out.println(k1);
|
||||||
|
String a1=(String) customProperties.get(k1);
|
||||||
|
assertEquals("Key1",p1,a1);
|
||||||
|
String a2=(String) customProperties.get(k2);
|
||||||
|
assertEquals("Schlüssel2",p2,a2);
|
||||||
|
Integer a3=(Integer) customProperties.get("Sample Number");
|
||||||
|
assertEquals("Sample Number",new Integer(12345),a3);
|
||||||
|
Boolean a4=(Boolean) customProperties.get("Sample Boolean");
|
||||||
|
assertEquals("Sample Boolean",new Boolean(true),a4);
|
||||||
|
Date a5=(Date) customProperties.get("Sample Date");
|
||||||
|
assertEquals("Custom Date:",date,a5);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterative testing of the unicode test
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testSix(){
|
||||||
|
for (int i=1;i<100;i++){
|
||||||
|
setUp();
|
||||||
|
testUnicode();
|
||||||
|
tearDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests conversion in custom fields and errors
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void testConvAndExistance(){
|
||||||
|
|
||||||
|
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
customProperties.put("int", new Integer(12345));
|
||||||
|
customProperties.put("negint", new Integer(-12345));
|
||||||
|
customProperties.put("long", new Long(12345));
|
||||||
|
customProperties.put("neglong", new Long(-12345));
|
||||||
|
customProperties.put("boolean", new Boolean(true));
|
||||||
|
customProperties.put("string", "a String");
|
||||||
|
//customProperties.put("float", new Float(12345.0)); is not valid
|
||||||
|
//customProperties.put("negfloat", new Float(-12345.1)); is not valid
|
||||||
|
customProperties.put("double", new Double(12345.2));
|
||||||
|
customProperties.put("negdouble", new Double(-12345.3));
|
||||||
|
//customProperties.put("char", new Character('a')); is not valid
|
||||||
|
|
||||||
|
Date date=new Date();
|
||||||
|
customProperties.put("date", date);
|
||||||
|
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
|
||||||
|
closeAndReOpen();
|
||||||
|
|
||||||
|
assertNotNull(dsi);
|
||||||
|
assertNotNull(si);
|
||||||
|
/* Change the category to "POI example". Any former category value will
|
||||||
|
* be lost. If there has been no category yet, it will be created. */
|
||||||
|
assertNull(dsi.getCategory());
|
||||||
|
assertNull(dsi.getCompany());
|
||||||
|
assertNull(dsi.getManager());
|
||||||
|
|
||||||
|
assertNull(si.getAuthor());
|
||||||
|
assertNull(si.getTitle());
|
||||||
|
assertNull(si.getComments());
|
||||||
|
assertNull(si.getKeywords());
|
||||||
|
assertNull(si.getSubject());
|
||||||
|
|
||||||
|
|
||||||
|
/* Read the custom properties. If there are no custom properties
|
||||||
|
* yet, the application has to create a new CustomProperties object.
|
||||||
|
* It will serve as a container for custom properties. */
|
||||||
|
customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert some custom properties into the container. */
|
||||||
|
|
||||||
|
Integer a3=(Integer) customProperties.get("int");
|
||||||
|
assertEquals("int",new Integer(12345),a3);
|
||||||
|
|
||||||
|
a3=(Integer) customProperties.get("negint");
|
||||||
|
assertEquals("negint",new Integer(-12345),a3);
|
||||||
|
|
||||||
|
Long al=(Long) customProperties.get("neglong");
|
||||||
|
assertEquals("neglong",new Long(-12345),al);
|
||||||
|
|
||||||
|
al=(Long) customProperties.get("long");
|
||||||
|
assertEquals("long",new Long(12345),al);
|
||||||
|
|
||||||
|
Boolean a4=(Boolean) customProperties.get("boolean");
|
||||||
|
assertEquals("boolean",new Boolean(true),a4);
|
||||||
|
|
||||||
|
Date a5=(Date) customProperties.get("date");
|
||||||
|
assertEquals("Custom Date:",date,a5);
|
||||||
|
|
||||||
|
Double d=(Double) customProperties.get("double");
|
||||||
|
assertEquals("int",new Double(12345.2),d);
|
||||||
|
|
||||||
|
d=(Double) customProperties.get("negdouble");
|
||||||
|
assertEquals("string",new Double(-12345.3),d);
|
||||||
|
|
||||||
|
String s=(String) customProperties.get("string");
|
||||||
|
assertEquals("sring","a String",s);
|
||||||
|
|
||||||
|
Object o=null;
|
||||||
|
|
||||||
|
o=customProperties.get("string");
|
||||||
|
if (!(o instanceof String)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
o=customProperties.get("boolean");
|
||||||
|
if (!(o instanceof Boolean)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
o=customProperties.get("int");
|
||||||
|
if (!(o instanceof Integer)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
o=customProperties.get("negint");
|
||||||
|
if (!(o instanceof Integer)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
o=customProperties.get("long");
|
||||||
|
if (!(o instanceof Long)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
o=customProperties.get("neglong");
|
||||||
|
if (!(o instanceof Long)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
o=customProperties.get("double");
|
||||||
|
if (!(o instanceof Double)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
o=customProperties.get("negdouble");
|
||||||
|
if (!(o instanceof Double)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
o=customProperties.get("date");
|
||||||
|
if (!(o instanceof Date)){
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@ -1,6 +1,5 @@
|
|||||||
|
|
||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -27,10 +26,12 @@ import junit.framework.Assert;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
import org.apache.poi.hpsf.Constants;
|
import org.apache.poi.hpsf.Constants;
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
import org.apache.poi.hpsf.HPSFException;
|
import org.apache.poi.hpsf.HPSFException;
|
||||||
import org.apache.poi.hpsf.PropertySet;
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
import org.apache.poi.hpsf.PropertySetFactory;
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
import org.apache.poi.hpsf.Section;
|
import org.apache.poi.hpsf.Section;
|
||||||
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -102,7 +103,7 @@ public class TestUnicode extends TestCase
|
|||||||
Assert.assertEquals(s.getProperty(1),
|
Assert.assertEquals(s.getProperty(1),
|
||||||
new Integer(Constants.CP_UTF16));
|
new Integer(Constants.CP_UTF16));
|
||||||
Assert.assertEquals(s.getProperty(2),
|
Assert.assertEquals(s.getProperty(2),
|
||||||
new Long(4198897018L));
|
new Integer(-96070278));
|
||||||
Assert.assertEquals(s.getProperty(3),
|
Assert.assertEquals(s.getProperty(3),
|
||||||
"MCon_Info zu Office bei Schreiner");
|
"MCon_Info zu Office bei Schreiner");
|
||||||
Assert.assertEquals(s.getProperty(4),
|
Assert.assertEquals(s.getProperty(4),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* ====================================================================
|
/* ====================================================================
|
||||||
Copyright 2002-2004 Apache Software Foundation
|
Copyright 2002-2006 Apache Software Foundation
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@ -14,7 +14,6 @@
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
==================================================================== */
|
==================================================================== */
|
||||||
|
|
||||||
|
|
||||||
package org.apache.poi.hpsf.basic;
|
package org.apache.poi.hpsf.basic;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
@ -124,11 +123,8 @@ public class TestWrite extends TestCase
|
|||||||
* in.</p>
|
* in.</p>
|
||||||
*
|
*
|
||||||
* @exception IOException if an I/O exception occurs
|
* @exception IOException if an I/O exception occurs
|
||||||
* @exception UnsupportedVariantTypeException if HPSF does not yet support
|
|
||||||
* a variant type to be written
|
|
||||||
*/
|
*/
|
||||||
public void testNoFormatID()
|
public void testNoFormatID() throws IOException
|
||||||
throws IOException, UnsupportedVariantTypeException
|
|
||||||
{
|
{
|
||||||
final String dataDirName = System.getProperty("HPSF.testdata.path");
|
final String dataDirName = System.getProperty("HPSF.testdata.path");
|
||||||
final File dataDir = new File(dataDirName);
|
final File dataDir = new File(dataDirName);
|
||||||
@ -409,10 +405,19 @@ public class TestWrite extends TestCase
|
|||||||
check(Variant.VT_CF, new byte[]{0, 1, 2, 3, 4, 5}, codepage);
|
check(Variant.VT_CF, new byte[]{0, 1, 2, 3, 4, 5}, codepage);
|
||||||
check(Variant.VT_CF, new byte[]{0, 1, 2, 3, 4, 5, 6}, codepage);
|
check(Variant.VT_CF, new byte[]{0, 1, 2, 3, 4, 5, 6}, codepage);
|
||||||
check(Variant.VT_CF, new byte[]{0, 1, 2, 3, 4, 5, 6, 7}, codepage);
|
check(Variant.VT_CF, new byte[]{0, 1, 2, 3, 4, 5, 6, 7}, codepage);
|
||||||
check(Variant.VT_I2, new Integer(27), codepage);
|
check(Variant.VT_I4, new Integer(27), codepage);
|
||||||
check(Variant.VT_I4, new Long(28), codepage);
|
check(Variant.VT_I8, new Long(28), codepage);
|
||||||
check(Variant.VT_R8, new Double(29.0), codepage);
|
check(Variant.VT_R8, new Double(29.0), codepage);
|
||||||
|
check(Variant.VT_I4, new Integer(-27), codepage);
|
||||||
|
check(Variant.VT_I8, new Long(-28), codepage);
|
||||||
|
check(Variant.VT_R8, new Double(-29.0), codepage);
|
||||||
check(Variant.VT_FILETIME, new Date(), codepage);
|
check(Variant.VT_FILETIME, new Date(), codepage);
|
||||||
|
check(Variant.VT_I4, new Integer(Integer.MAX_VALUE), codepage);
|
||||||
|
check(Variant.VT_I4, new Integer(Integer.MIN_VALUE), codepage);
|
||||||
|
check(Variant.VT_I8, new Long(Long.MAX_VALUE), codepage);
|
||||||
|
check(Variant.VT_I8, new Long(Long.MIN_VALUE), codepage);
|
||||||
|
check(Variant.VT_R8, new Double(Double.MAX_VALUE), codepage);
|
||||||
|
check(Variant.VT_R8, new Double(Double.MIN_VALUE), codepage);
|
||||||
|
|
||||||
check(Variant.VT_LPSTR,
|
check(Variant.VT_LPSTR,
|
||||||
"", codepage);
|
"", codepage);
|
||||||
@ -602,8 +607,11 @@ public class TestWrite extends TestCase
|
|||||||
*
|
*
|
||||||
* @param variantType The property's variant type.
|
* @param variantType The property's variant type.
|
||||||
* @param value The property's value.
|
* @param value The property's value.
|
||||||
|
* @param codepage The codepage to use for writing and reading.
|
||||||
* @throws UnsupportedVariantTypeException if the variant is not supported.
|
* @throws UnsupportedVariantTypeException if the variant is not supported.
|
||||||
* @throws IOException if an I/O exception occurs.
|
* @throws IOException if an I/O exception occurs.
|
||||||
|
* @throws ReadingNotSupportedException
|
||||||
|
* @throws UnsupportedEncodingException
|
||||||
*/
|
*/
|
||||||
private void check(final long variantType, final Object value,
|
private void check(final long variantType, final Object value,
|
||||||
final int codepage)
|
final int codepage)
|
||||||
@ -779,7 +787,7 @@ public class TestWrite extends TestCase
|
|||||||
m.put(new Long(2), "String 2");
|
m.put(new Long(2), "String 2");
|
||||||
m.put(new Long(3), "String 3");
|
m.put(new Long(3), "String 3");
|
||||||
s.setDictionary(m);
|
s.setDictionary(m);
|
||||||
s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID);
|
s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]);
|
||||||
int codepage = Constants.CP_UNICODE;
|
int codepage = Constants.CP_UNICODE;
|
||||||
s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
|
s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
|
||||||
new Integer(codepage));
|
new Integer(codepage));
|
||||||
@ -831,7 +839,7 @@ public class TestWrite extends TestCase
|
|||||||
m.put(new Long(2), "String 2");
|
m.put(new Long(2), "String 2");
|
||||||
m.put(new Long(3), "String 3");
|
m.put(new Long(3), "String 3");
|
||||||
s.setDictionary(m);
|
s.setDictionary(m);
|
||||||
s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID);
|
s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[0]);
|
||||||
int codepage = 12345;
|
int codepage = 12345;
|
||||||
s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
|
s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2,
|
||||||
new Integer(codepage));
|
new Integer(codepage));
|
||||||
@ -902,8 +910,11 @@ public class TestWrite extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>In order to execute tests with characters beyond US-ASCII, this
|
* <p>In order to execute tests with characters beyond US-ASCII, this
|
||||||
* method checks whether the application has is runing in an environment
|
* method checks whether the application is runing in an environment
|
||||||
* where the default character set is 16-bit-capable.</p>
|
* where the default character set is 16-bit-capable.</p>
|
||||||
|
*
|
||||||
|
* @return <code>true</code> if the default character set is 16-bit-capable,
|
||||||
|
* else <code>false</code>.
|
||||||
*/
|
*/
|
||||||
private boolean hasProperDefaultCharset()
|
private boolean hasProperDefaultCharset()
|
||||||
{
|
{
|
||||||
@ -916,6 +927,9 @@ public class TestWrite extends TestCase
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Runs the test cases stand-alone.</p>
|
* <p>Runs the test cases stand-alone.</p>
|
||||||
|
*
|
||||||
|
* @param args The command-line parameters.
|
||||||
|
* @throws Throwable if anything goes wrong.
|
||||||
*/
|
*/
|
||||||
public static void main(final String[] args) throws Throwable
|
public static void main(final String[] args) throws Throwable
|
||||||
{
|
{
|
||||||
|
763
src/testcases/org/apache/poi/hpsf/basic/TestWriteWellKnown.java
Normal file
763
src/testcases/org/apache/poi/hpsf/basic/TestWriteWellKnown.java
Normal file
@ -0,0 +1,763 @@
|
|||||||
|
/* ====================================================================
|
||||||
|
Copyright 2002-2006 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.basic;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileFilter;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Map.Entry;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.apache.poi.hpsf.CustomProperties;
|
||||||
|
import org.apache.poi.hpsf.CustomProperty;
|
||||||
|
import org.apache.poi.hpsf.DocumentSummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.MarkUnsupportedException;
|
||||||
|
import org.apache.poi.hpsf.MutableProperty;
|
||||||
|
import org.apache.poi.hpsf.MutableSection;
|
||||||
|
import org.apache.poi.hpsf.NoPropertySetStreamException;
|
||||||
|
import org.apache.poi.hpsf.PropertySet;
|
||||||
|
import org.apache.poi.hpsf.PropertySetFactory;
|
||||||
|
import org.apache.poi.hpsf.SummaryInformation;
|
||||||
|
import org.apache.poi.hpsf.UnexpectedPropertySetTypeException;
|
||||||
|
import org.apache.poi.hpsf.Variant;
|
||||||
|
import org.apache.poi.hpsf.VariantSupport;
|
||||||
|
import org.apache.poi.hpsf.WritingNotSupportedException;
|
||||||
|
import org.apache.poi.hpsf.wellknown.SectionIDMap;
|
||||||
|
import org.apache.poi.poifs.filesystem.DirectoryEntry;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentEntry;
|
||||||
|
import org.apache.poi.poifs.filesystem.DocumentInputStream;
|
||||||
|
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tests HPSF's high-level writing functionality for the well-known property
|
||||||
|
* set "SummaryInformation" and "DocumentSummaryInformation".</p>
|
||||||
|
*
|
||||||
|
* @author Rainer Klute
|
||||||
|
* <a href="mailto:klute@rainer-klute.de">klute@rainer-klute.de</a>
|
||||||
|
* @since 2006-02-01
|
||||||
|
* @version $Id$
|
||||||
|
*/
|
||||||
|
public class TestWriteWellKnown extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
private static final String POI_FS = "TestWriteWellKnown.doc";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Constructor</p>
|
||||||
|
*
|
||||||
|
* @param name the test case's name
|
||||||
|
*/
|
||||||
|
public TestWriteWellKnown(final String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see TestCase#setUp()
|
||||||
|
*/
|
||||||
|
public void setUp()
|
||||||
|
{
|
||||||
|
VariantSupport.setLogUnsupportedTypes(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This test method checks whether DocumentSummary information streams
|
||||||
|
* can be read. This is done by opening all "Test*" files in the directrory
|
||||||
|
* pointed to by the "HPSF.testdata.path" system property, trying to extract
|
||||||
|
* the document summary information stream in the root directory and calling
|
||||||
|
* its get... methods.</p>
|
||||||
|
* @throws IOException
|
||||||
|
* @throws FileNotFoundException
|
||||||
|
* @throws MarkUnsupportedException
|
||||||
|
* @throws NoPropertySetStreamException
|
||||||
|
* @throws UnexpectedPropertySetTypeException
|
||||||
|
*/
|
||||||
|
public void testReadDocumentSummaryInformation()
|
||||||
|
throws FileNotFoundException, IOException,
|
||||||
|
NoPropertySetStreamException, MarkUnsupportedException,
|
||||||
|
UnexpectedPropertySetTypeException
|
||||||
|
{
|
||||||
|
final String dataDirName = System.getProperty("HPSF.testdata.path");
|
||||||
|
final File dataDir = new File(dataDirName);
|
||||||
|
final File[] docs = dataDir.listFiles(new FileFilter()
|
||||||
|
{
|
||||||
|
public boolean accept(final File file)
|
||||||
|
{
|
||||||
|
return file.isFile() && file.getName().startsWith("Test");
|
||||||
|
}});
|
||||||
|
for (int i = 0; i < docs.length; i++)
|
||||||
|
{
|
||||||
|
final File doc = docs[i];
|
||||||
|
System.out.println("Reading file " + doc);
|
||||||
|
|
||||||
|
/* Read a test document <em>doc</em> into a POI filesystem. */
|
||||||
|
final POIFSFileSystem poifs = new POIFSFileSystem(new FileInputStream(doc));
|
||||||
|
final DirectoryEntry dir = poifs.getRoot();
|
||||||
|
DocumentEntry dsiEntry = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dsiEntry = (DocumentEntry) dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* A missing document summary information stream is not an error
|
||||||
|
* and therefore silently ignored here.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a document summry information stream, read it from
|
||||||
|
* the POI filesystem.
|
||||||
|
*/
|
||||||
|
if (dsiEntry != null)
|
||||||
|
{
|
||||||
|
final DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
final PropertySet ps = new PropertySet(dis);
|
||||||
|
final DocumentSummaryInformation dsi = new DocumentSummaryInformation(ps);
|
||||||
|
|
||||||
|
/* Execute the get... methods. */
|
||||||
|
dsi.getByteCount();
|
||||||
|
dsi.getByteOrder();
|
||||||
|
dsi.getCategory();
|
||||||
|
dsi.getCompany();
|
||||||
|
dsi.getCustomProperties();
|
||||||
|
// FIXME dsi.getDocparts();
|
||||||
|
// FIXME dsi.getHeadingPair();
|
||||||
|
dsi.getHiddenCount();
|
||||||
|
dsi.getLineCount();
|
||||||
|
dsi.getLinksDirty();
|
||||||
|
dsi.getManager();
|
||||||
|
dsi.getMMClipCount();
|
||||||
|
dsi.getNoteCount();
|
||||||
|
dsi.getParCount();
|
||||||
|
dsi.getPresentationFormat();
|
||||||
|
dsi.getScale();
|
||||||
|
dsi.getSlideCount();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>This test method test the writing of properties in the well-known
|
||||||
|
* property set streams "SummaryInformation" and
|
||||||
|
* "DocumentSummaryInformation" by performing the following steps:</p>
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
*
|
||||||
|
* <li><p>Read a test document <em>doc1</em> into a POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Read the summary information stream and the document summary
|
||||||
|
* information stream from the POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write all properties supported by HPSF to the summary
|
||||||
|
* information (e.g. author, edit date, application name) and to the
|
||||||
|
* document summary information (e.g. company, manager).</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the summary information stream and the document summary
|
||||||
|
* information stream to the POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the POI filesystem to a (temporary) file <em>doc2</em>
|
||||||
|
* and close the latter.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Open <em>doc2</em> for reading and check summary information
|
||||||
|
* and document summary information. All properties written before must be
|
||||||
|
* found in the property streams of <em>doc2</em> and have the correct
|
||||||
|
* values.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Remove all properties supported by HPSF from the summary
|
||||||
|
* information (e.g. author, edit date, application name) and from the
|
||||||
|
* document summary information (e.g. company, manager).</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the summary information stream and the document summary
|
||||||
|
* information stream to the POI filesystem.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Write the POI filesystem to a (temporary) file <em>doc3</em>
|
||||||
|
* and close the latter.</p></li>
|
||||||
|
*
|
||||||
|
* <li><p>Open <em>doc3</em> for reading and check summary information
|
||||||
|
* and document summary information. All properties removed before must not
|
||||||
|
* be found in the property streams of <em>doc3</em>.</p></li> </ol>
|
||||||
|
*
|
||||||
|
* @throws IOException if some I/O error occurred.
|
||||||
|
* @throws MarkUnsupportedException
|
||||||
|
* @throws NoPropertySetStreamException
|
||||||
|
* @throws UnexpectedPropertySetTypeException
|
||||||
|
* @throws WritingNotSupportedException
|
||||||
|
*/
|
||||||
|
public void testWriteWellKnown() throws IOException,
|
||||||
|
NoPropertySetStreamException, MarkUnsupportedException,
|
||||||
|
UnexpectedPropertySetTypeException, WritingNotSupportedException
|
||||||
|
{
|
||||||
|
final String dataDirName = System.getProperty("HPSF.testdata.path");
|
||||||
|
final File dataDir = new File(dataDirName);
|
||||||
|
final File doc1 = new File(dataDir, POI_FS);
|
||||||
|
|
||||||
|
/* Read a test document <em>doc1</em> into a POI filesystem. */
|
||||||
|
POIFSFileSystem poifs = new POIFSFileSystem(new FileInputStream(doc1));
|
||||||
|
DirectoryEntry dir = poifs.getRoot();
|
||||||
|
DocumentEntry siEntry = (DocumentEntry) dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
DocumentEntry dsiEntry = (DocumentEntry) dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Read the summary information stream and the document summary
|
||||||
|
* information stream from the POI filesystem.
|
||||||
|
*
|
||||||
|
* Please note that the result consists of SummaryInformation and
|
||||||
|
* DocumentSummaryInformation instances which are in memory only. To
|
||||||
|
* make them permanent they have to be written to a POI filesystem
|
||||||
|
* explicitly (overwriting the former contents). Then the POI filesystem
|
||||||
|
* should be saved to a file.
|
||||||
|
*/
|
||||||
|
DocumentInputStream dis = new DocumentInputStream(siEntry);
|
||||||
|
PropertySet ps = new PropertySet(dis);
|
||||||
|
SummaryInformation si = new SummaryInformation(ps);
|
||||||
|
dis = new DocumentInputStream(dsiEntry);
|
||||||
|
ps = new PropertySet(dis);
|
||||||
|
DocumentSummaryInformation dsi = new DocumentSummaryInformation(ps);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write all properties supported by HPSF to the summary information
|
||||||
|
* (e.g. author, edit date, application name) and to the document
|
||||||
|
* summary information (e.g. company, manager).
|
||||||
|
*/
|
||||||
|
Calendar cal = new GregorianCalendar();
|
||||||
|
cal.set(2000, 6, 6, 6, 6, 6);
|
||||||
|
final long time1 = cal.getTimeInMillis();
|
||||||
|
cal.set(2001, 7, 7, 7, 7, 7);
|
||||||
|
final long time2 = cal.getTimeInMillis();
|
||||||
|
cal.set(2002, 8, 8, 8, 8, 8);
|
||||||
|
final long time3 = cal.getTimeInMillis();
|
||||||
|
|
||||||
|
int nr = 4711;
|
||||||
|
final String P_APPLICATION_NAME = "ApplicationName";
|
||||||
|
final String P_AUTHOR = "Author";
|
||||||
|
final int P_CHAR_COUNT = ++nr;
|
||||||
|
final String P_COMMENTS = "Comments";
|
||||||
|
final Date P_CREATE_DATE_TIME = new Date(time1);
|
||||||
|
final long P_EDIT_TIME = ++nr * 1000 * 10;
|
||||||
|
final String P_KEYWORDS = "Keywords";
|
||||||
|
final String P_LAST_AUTHOR = "LastAuthor";
|
||||||
|
final Date P_LAST_PRINTED = new Date(time2);
|
||||||
|
final Date P_LAST_SAVE_DATE_TIME = new Date(time3);
|
||||||
|
final int P_PAGE_COUNT = ++nr;
|
||||||
|
final String P_REV_NUMBER = "RevNumber";
|
||||||
|
final int P_SECURITY = 1;
|
||||||
|
final String P_SUBJECT = "Subject";
|
||||||
|
final String P_TEMPLATE = "Template";
|
||||||
|
// FIXME (byte array properties not yet implemented): final byte[] P_THUMBNAIL = new byte[123];
|
||||||
|
final String P_TITLE = "Title";
|
||||||
|
final int P_WORD_COUNT = ++nr;
|
||||||
|
|
||||||
|
final int P_BYTE_COUNT = ++nr;
|
||||||
|
final String P_CATEGORY = "Category";
|
||||||
|
final String P_COMPANY = "Company";
|
||||||
|
// FIXME (byte array properties not yet implemented): final byte[] P_DOCPARTS = new byte[123];
|
||||||
|
// FIXME (byte array properties not yet implemented): final byte[] P_HEADING_PAIR = new byte[123];
|
||||||
|
final int P_HIDDEN_COUNT = ++nr;
|
||||||
|
final int P_LINE_COUNT = ++nr;
|
||||||
|
final boolean P_LINKS_DIRTY = true;
|
||||||
|
final String P_MANAGER = "Manager";
|
||||||
|
final int P_MM_CLIP_COUNT = ++nr;
|
||||||
|
final int P_NOTE_COUNT = ++nr;
|
||||||
|
final int P_PAR_COUNT = ++nr;
|
||||||
|
final String P_PRESENTATION_FORMAT = "PresentationFormat";
|
||||||
|
final boolean P_SCALE = false;
|
||||||
|
final int P_SLIDE_COUNT = ++nr;
|
||||||
|
final Date now = new Date();
|
||||||
|
|
||||||
|
final Integer POSITIVE_INTEGER = new Integer(2222);
|
||||||
|
final Long POSITIVE_LONG = new Long(3333);
|
||||||
|
final Double POSITIVE_DOUBLE = new Double(4444);
|
||||||
|
final Integer NEGATIVE_INTEGER = new Integer(2222);
|
||||||
|
final Long NEGATIVE_LONG = new Long(3333);
|
||||||
|
final Double NEGATIVE_DOUBLE = new Double(4444);
|
||||||
|
|
||||||
|
final Integer MAX_INTEGER = new Integer(Integer.MAX_VALUE);
|
||||||
|
final Integer MIN_INTEGER = new Integer(Integer.MIN_VALUE);
|
||||||
|
final Long MAX_LONG = new Long(Long.MAX_VALUE);
|
||||||
|
final Long MIN_LONG = new Long(Long.MIN_VALUE);
|
||||||
|
final Double MAX_DOUBLE = new Double(Double.MAX_VALUE);
|
||||||
|
final Double MIN_DOUBLE = new Double(Double.MIN_VALUE);
|
||||||
|
|
||||||
|
si.setApplicationName(P_APPLICATION_NAME);
|
||||||
|
si.setAuthor(P_AUTHOR);
|
||||||
|
si.setCharCount(P_CHAR_COUNT);
|
||||||
|
si.setComments(P_COMMENTS);
|
||||||
|
si.setCreateDateTime(P_CREATE_DATE_TIME);
|
||||||
|
si.setEditTime(P_EDIT_TIME);
|
||||||
|
si.setKeywords(P_KEYWORDS);
|
||||||
|
si.setLastAuthor(P_LAST_AUTHOR);
|
||||||
|
si.setLastPrinted(P_LAST_PRINTED);
|
||||||
|
si.setLastSaveDateTime(P_LAST_SAVE_DATE_TIME);
|
||||||
|
si.setPageCount(P_PAGE_COUNT);
|
||||||
|
si.setRevNumber(P_REV_NUMBER);
|
||||||
|
si.setSecurity(P_SECURITY);
|
||||||
|
si.setSubject(P_SUBJECT);
|
||||||
|
si.setTemplate(P_TEMPLATE);
|
||||||
|
// FIXME (byte array properties not yet implemented): si.setThumbnail(P_THUMBNAIL);
|
||||||
|
si.setTitle(P_TITLE);
|
||||||
|
si.setWordCount(P_WORD_COUNT);
|
||||||
|
|
||||||
|
dsi.setByteCount(P_BYTE_COUNT);
|
||||||
|
dsi.setCategory(P_CATEGORY);
|
||||||
|
dsi.setCompany(P_COMPANY);
|
||||||
|
// FIXME (byte array properties not yet implemented): dsi.setDocparts(P_DOCPARTS);
|
||||||
|
// FIXME (byte array properties not yet implemented): dsi.setHeadingPair(P_HEADING_PAIR);
|
||||||
|
dsi.setHiddenCount(P_HIDDEN_COUNT);
|
||||||
|
dsi.setLineCount(P_LINE_COUNT);
|
||||||
|
dsi.setLinksDirty(P_LINKS_DIRTY);
|
||||||
|
dsi.setManager(P_MANAGER);
|
||||||
|
dsi.setMMClipCount(P_MM_CLIP_COUNT);
|
||||||
|
dsi.setNoteCount(P_NOTE_COUNT);
|
||||||
|
dsi.setParCount(P_PAR_COUNT);
|
||||||
|
dsi.setPresentationFormat(P_PRESENTATION_FORMAT);
|
||||||
|
dsi.setScale(P_SCALE);
|
||||||
|
dsi.setSlideCount(P_SLIDE_COUNT);
|
||||||
|
|
||||||
|
CustomProperties customProperties = dsi.getCustomProperties();
|
||||||
|
if (customProperties == null)
|
||||||
|
customProperties = new CustomProperties();
|
||||||
|
customProperties.put("Schlüssel ä", "Wert ä");
|
||||||
|
customProperties.put("Schlüssel äö", "Wert äö");
|
||||||
|
customProperties.put("Schlüssel äöü", "Wert äöü");
|
||||||
|
customProperties.put("Schlüssel äöüß", "Wert äöüß");
|
||||||
|
customProperties.put("positive_Integer", POSITIVE_INTEGER);
|
||||||
|
customProperties.put("positive_Long", POSITIVE_LONG);
|
||||||
|
customProperties.put("positive_Double", POSITIVE_DOUBLE);
|
||||||
|
customProperties.put("negative_Integer", NEGATIVE_INTEGER);
|
||||||
|
customProperties.put("negative_Long", NEGATIVE_LONG);
|
||||||
|
customProperties.put("negative_Double", NEGATIVE_DOUBLE);
|
||||||
|
customProperties.put("Boolean", new Boolean(true));
|
||||||
|
customProperties.put("Date", now);
|
||||||
|
customProperties.put("max_Integer", MAX_INTEGER);
|
||||||
|
customProperties.put("min_Integer", MIN_INTEGER);
|
||||||
|
customProperties.put("max_Long", MAX_LONG);
|
||||||
|
customProperties.put("min_Long", MIN_LONG);
|
||||||
|
customProperties.put("max_Double", MAX_DOUBLE);
|
||||||
|
customProperties.put("min_Double", MIN_DOUBLE);
|
||||||
|
dsi.setCustomProperties(customProperties);
|
||||||
|
|
||||||
|
/* Write the summary information stream and the document summary
|
||||||
|
* information stream to the POI filesystem. */
|
||||||
|
si.write(dir, siEntry.getName());
|
||||||
|
dsi.write(dir, dsiEntry.getName());
|
||||||
|
|
||||||
|
/* Write the POI filesystem to a (temporary) file <em>doc2</em>
|
||||||
|
* and close the latter. */
|
||||||
|
final File doc2 = File.createTempFile("POI_HPSF_Test.", ".tmp");
|
||||||
|
doc2.deleteOnExit();
|
||||||
|
OutputStream out = new FileOutputStream(doc2);
|
||||||
|
poifs.writeFilesystem(out);
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open <em>doc2</em> for reading and check summary information and
|
||||||
|
* document summary information. All properties written before must be
|
||||||
|
* found in the property streams of <em>doc2</em> and have the correct
|
||||||
|
* values.
|
||||||
|
*/
|
||||||
|
poifs = new POIFSFileSystem(new FileInputStream(doc2));
|
||||||
|
dir = poifs.getRoot();
|
||||||
|
siEntry = (DocumentEntry) dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
dsiEntry = (DocumentEntry) dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
|
||||||
|
dis = new DocumentInputStream(siEntry);
|
||||||
|
ps = new PropertySet(dis);
|
||||||
|
si = new SummaryInformation(ps);
|
||||||
|
dis = new DocumentInputStream(dsiEntry);
|
||||||
|
ps = new PropertySet(dis);
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
|
||||||
|
assertEquals(P_APPLICATION_NAME, si.getApplicationName());
|
||||||
|
assertEquals(P_AUTHOR, si.getAuthor());
|
||||||
|
assertEquals(P_CHAR_COUNT, si.getCharCount());
|
||||||
|
assertEquals(P_COMMENTS, si.getComments());
|
||||||
|
assertEquals(P_CREATE_DATE_TIME, si.getCreateDateTime());
|
||||||
|
assertEquals(P_EDIT_TIME, si.getEditTime());
|
||||||
|
assertEquals(P_KEYWORDS, si.getKeywords());
|
||||||
|
assertEquals(P_LAST_AUTHOR, si.getLastAuthor());
|
||||||
|
assertEquals(P_LAST_PRINTED, si.getLastPrinted());
|
||||||
|
assertEquals(P_LAST_SAVE_DATE_TIME, si.getLastSaveDateTime());
|
||||||
|
assertEquals(P_PAGE_COUNT, si.getPageCount());
|
||||||
|
assertEquals(P_REV_NUMBER, si.getRevNumber());
|
||||||
|
assertEquals(P_SECURITY, si.getSecurity());
|
||||||
|
assertEquals(P_SUBJECT, si.getSubject());
|
||||||
|
assertEquals(P_TEMPLATE, si.getTemplate());
|
||||||
|
// FIXME (byte array properties not yet implemented): assertEquals(P_THUMBNAIL, si.getThumbnail());
|
||||||
|
assertEquals(P_TITLE, si.getTitle());
|
||||||
|
assertEquals(P_WORD_COUNT, si.getWordCount());
|
||||||
|
|
||||||
|
assertEquals(P_BYTE_COUNT, dsi.getByteCount());
|
||||||
|
assertEquals(P_CATEGORY, dsi.getCategory());
|
||||||
|
assertEquals(P_COMPANY, dsi.getCompany());
|
||||||
|
// FIXME (byte array properties not yet implemented): assertEquals(P_, dsi.getDocparts());
|
||||||
|
// FIXME (byte array properties not yet implemented): assertEquals(P_, dsi.getHeadingPair());
|
||||||
|
assertEquals(P_HIDDEN_COUNT, dsi.getHiddenCount());
|
||||||
|
assertEquals(P_LINE_COUNT, dsi.getLineCount());
|
||||||
|
assertEquals(P_LINKS_DIRTY, dsi.getLinksDirty());
|
||||||
|
assertEquals(P_MANAGER, dsi.getManager());
|
||||||
|
assertEquals(P_MM_CLIP_COUNT, dsi.getMMClipCount());
|
||||||
|
assertEquals(P_NOTE_COUNT, dsi.getNoteCount());
|
||||||
|
assertEquals(P_PAR_COUNT, dsi.getParCount());
|
||||||
|
assertEquals(P_PRESENTATION_FORMAT, dsi.getPresentationFormat());
|
||||||
|
assertEquals(P_SCALE, dsi.getScale());
|
||||||
|
assertEquals(P_SLIDE_COUNT, dsi.getSlideCount());
|
||||||
|
|
||||||
|
final CustomProperties cps = dsi.getCustomProperties();
|
||||||
|
assertEquals(customProperties, cps);
|
||||||
|
assertNull(cps.get("No value available"));
|
||||||
|
assertEquals("Wert ä", cps.get("Schlüssel ä"));
|
||||||
|
assertEquals("Wert äö", cps.get("Schlüssel äö"));
|
||||||
|
assertEquals("Wert äöü", cps.get("Schlüssel äöü"));
|
||||||
|
assertEquals("Wert äöüß", cps.get("Schlüssel äöüß"));
|
||||||
|
assertEquals(POSITIVE_INTEGER, cps.get("positive_Integer"));
|
||||||
|
assertEquals(POSITIVE_LONG, cps.get("positive_Long"));
|
||||||
|
assertEquals(POSITIVE_DOUBLE, cps.get("positive_Double"));
|
||||||
|
assertEquals(NEGATIVE_INTEGER, cps.get("negative_Integer"));
|
||||||
|
assertEquals(NEGATIVE_LONG, cps.get("negative_Long"));
|
||||||
|
assertEquals(NEGATIVE_DOUBLE, cps.get("negative_Double"));
|
||||||
|
assertEquals(new Boolean(true), cps.get("Boolean"));
|
||||||
|
assertEquals(now, cps.get("Date"));
|
||||||
|
assertEquals(MAX_INTEGER, cps.get("max_Integer"));
|
||||||
|
assertEquals(MIN_INTEGER, cps.get("min_Integer"));
|
||||||
|
assertEquals(MAX_LONG, cps.get("max_Long"));
|
||||||
|
assertEquals(MIN_LONG, cps.get("min_Long"));
|
||||||
|
assertEquals(MAX_DOUBLE, cps.get("max_Double"));
|
||||||
|
assertEquals(MIN_DOUBLE, cps.get("min_Double"));
|
||||||
|
|
||||||
|
/* Remove all properties supported by HPSF from the summary
|
||||||
|
* information (e.g. author, edit date, application name) and from the
|
||||||
|
* document summary information (e.g. company, manager). */
|
||||||
|
si.removeApplicationName();
|
||||||
|
si.removeAuthor();
|
||||||
|
si.removeCharCount();
|
||||||
|
si.removeComments();
|
||||||
|
si.removeCreateDateTime();
|
||||||
|
si.removeEditTime();
|
||||||
|
si.removeKeywords();
|
||||||
|
si.removeLastAuthor();
|
||||||
|
si.removeLastPrinted();
|
||||||
|
si.removeLastSaveDateTime();
|
||||||
|
si.removePageCount();
|
||||||
|
si.removeRevNumber();
|
||||||
|
si.removeSecurity();
|
||||||
|
si.removeSubject();
|
||||||
|
si.removeTemplate();
|
||||||
|
si.removeThumbnail();
|
||||||
|
si.removeTitle();
|
||||||
|
si.removeWordCount();
|
||||||
|
|
||||||
|
dsi.removeByteCount();
|
||||||
|
dsi.removeCategory();
|
||||||
|
dsi.removeCompany();
|
||||||
|
dsi.removeCustomProperties();
|
||||||
|
dsi.removeDocparts();
|
||||||
|
dsi.removeHeadingPair();
|
||||||
|
dsi.removeHiddenCount();
|
||||||
|
dsi.removeLineCount();
|
||||||
|
dsi.removeLinksDirty();
|
||||||
|
dsi.removeManager();
|
||||||
|
dsi.removeMMClipCount();
|
||||||
|
dsi.removeNoteCount();
|
||||||
|
dsi.removeParCount();
|
||||||
|
dsi.removePresentationFormat();
|
||||||
|
dsi.removeScale();
|
||||||
|
dsi.removeSlideCount();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <li><p>Write the summary information stream and the document summary
|
||||||
|
* information stream to the POI filesystem. */
|
||||||
|
si.write(dir, siEntry.getName());
|
||||||
|
dsi.write(dir, dsiEntry.getName());
|
||||||
|
|
||||||
|
/*
|
||||||
|
* <li><p>Write the POI filesystem to a (temporary) file <em>doc3</em>
|
||||||
|
* and close the latter. */
|
||||||
|
final File doc3 = File.createTempFile("POI_HPSF_Test.", ".tmp");
|
||||||
|
doc3.deleteOnExit();
|
||||||
|
out = new FileOutputStream(doc3);
|
||||||
|
poifs.writeFilesystem(out);
|
||||||
|
out.close();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open <em>doc3</em> for reading and check summary information
|
||||||
|
* and document summary information. All properties removed before must not
|
||||||
|
* be found in the property streams of <em>doc3</em>.
|
||||||
|
*/
|
||||||
|
poifs = new POIFSFileSystem(new FileInputStream(doc3));
|
||||||
|
dir = poifs.getRoot();
|
||||||
|
siEntry = (DocumentEntry) dir.getEntry(SummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
dsiEntry = (DocumentEntry) dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
|
||||||
|
dis = new DocumentInputStream(siEntry);
|
||||||
|
ps = new PropertySet(dis);
|
||||||
|
si = new SummaryInformation(ps);
|
||||||
|
dis = new DocumentInputStream(dsiEntry);
|
||||||
|
ps = new PropertySet(dis);
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
|
||||||
|
assertEquals(null, si.getApplicationName());
|
||||||
|
assertEquals(null, si.getAuthor());
|
||||||
|
assertEquals(0, si.getCharCount());
|
||||||
|
assertTrue(si.wasNull());
|
||||||
|
assertEquals(null, si.getComments());
|
||||||
|
assertEquals(null, si.getCreateDateTime());
|
||||||
|
assertEquals(0, si.getEditTime());
|
||||||
|
assertTrue(si.wasNull());
|
||||||
|
assertEquals(null, si.getKeywords());
|
||||||
|
assertEquals(null, si.getLastAuthor());
|
||||||
|
assertEquals(null, si.getLastPrinted());
|
||||||
|
assertEquals(null, si.getLastSaveDateTime());
|
||||||
|
assertEquals(0, si.getPageCount());
|
||||||
|
assertTrue(si.wasNull());
|
||||||
|
assertEquals(null, si.getRevNumber());
|
||||||
|
assertEquals(0, si.getSecurity());
|
||||||
|
assertTrue(si.wasNull());
|
||||||
|
assertEquals(null, si.getSubject());
|
||||||
|
assertEquals(null, si.getTemplate());
|
||||||
|
assertEquals(null, si.getThumbnail());
|
||||||
|
assertEquals(null, si.getTitle());
|
||||||
|
assertEquals(0, si.getWordCount());
|
||||||
|
assertTrue(si.wasNull());
|
||||||
|
|
||||||
|
assertEquals(0, dsi.getByteCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(null, dsi.getCategory());
|
||||||
|
assertEquals(null, dsi.getCustomProperties());
|
||||||
|
// FIXME (byte array properties not yet implemented): assertEquals(null, dsi.getDocparts());
|
||||||
|
// FIXME (byte array properties not yet implemented): assertEquals(null, dsi.getHeadingPair());
|
||||||
|
assertEquals(0, dsi.getHiddenCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(0, dsi.getLineCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(false, dsi.getLinksDirty());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(null, dsi.getManager());
|
||||||
|
assertEquals(0, dsi.getMMClipCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(0, dsi.getNoteCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(0, dsi.getParCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(null, dsi.getPresentationFormat());
|
||||||
|
assertEquals(false, dsi.getScale());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
assertEquals(0, dsi.getSlideCount());
|
||||||
|
assertTrue(dsi.wasNull());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tests the simplified custom properties by reading them from the
|
||||||
|
* available test files.</p>
|
||||||
|
*
|
||||||
|
* @throws Throwable if anything goes wrong.
|
||||||
|
*/
|
||||||
|
public void testReadCustomPropertiesFromFiles() throws Throwable
|
||||||
|
{
|
||||||
|
final AllDataFilesTester.TestTask task = new AllDataFilesTester.TestTask()
|
||||||
|
{
|
||||||
|
public void runTest(final File file) throws FileNotFoundException,
|
||||||
|
IOException, NoPropertySetStreamException,
|
||||||
|
MarkUnsupportedException,
|
||||||
|
UnexpectedPropertySetTypeException
|
||||||
|
{
|
||||||
|
/* Read a test document <em>doc</em> into a POI filesystem. */
|
||||||
|
final POIFSFileSystem poifs = new POIFSFileSystem(new FileInputStream(file));
|
||||||
|
final DirectoryEntry dir = poifs.getRoot();
|
||||||
|
DocumentEntry dsiEntry = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dsiEntry = (DocumentEntry) dir.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException ex)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* A missing document summary information stream is not an error
|
||||||
|
* and therefore silently ignored here.
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If there is a document summry information stream, read it from
|
||||||
|
* the POI filesystem, else create a new one.
|
||||||
|
*/
|
||||||
|
DocumentSummaryInformation dsi;
|
||||||
|
if (dsiEntry != null)
|
||||||
|
{
|
||||||
|
final DocumentInputStream dis = new DocumentInputStream(dsiEntry);
|
||||||
|
final PropertySet ps = new PropertySet(dis);
|
||||||
|
dsi = new DocumentSummaryInformation(ps);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
dsi = PropertySetFactory.newDocumentSummaryInformation();
|
||||||
|
final CustomProperties cps = dsi.getCustomProperties();
|
||||||
|
|
||||||
|
if (cps == null)
|
||||||
|
/* The document does not have custom properties. */
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (final Iterator i = cps.entrySet().iterator(); i.hasNext();)
|
||||||
|
{
|
||||||
|
final Map.Entry e = (Entry) i.next();
|
||||||
|
final CustomProperty cp = (CustomProperty) e.getValue();
|
||||||
|
cp.getName();
|
||||||
|
cp.getValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
final String dataDirName = System.getProperty("HPSF.testdata.path");
|
||||||
|
final File dataDir = new File(dataDirName);
|
||||||
|
final File[] docs = dataDir.listFiles(new FileFilter()
|
||||||
|
{
|
||||||
|
public boolean accept(final File file)
|
||||||
|
{
|
||||||
|
return file.isFile() && file.getName().startsWith("Test");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (int i = 0; i < docs.length; i++)
|
||||||
|
{
|
||||||
|
task.runTest(docs[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tests basic custom property features.</p>
|
||||||
|
*/
|
||||||
|
public void testCustomerProperties()
|
||||||
|
{
|
||||||
|
final String KEY = "Schlüssel ä";
|
||||||
|
final String VALUE_1 = "Wert 1";
|
||||||
|
final String VALUE_2 = "Wert 2";
|
||||||
|
|
||||||
|
CustomProperty cp;
|
||||||
|
CustomProperties cps = new CustomProperties();
|
||||||
|
assertEquals(0, cps.size());
|
||||||
|
|
||||||
|
/* After adding a custom property the size must be 1 and it must be
|
||||||
|
* possible to extract the custom property from the map. */
|
||||||
|
cps.put(KEY, VALUE_1);
|
||||||
|
assertEquals(1, cps.size());
|
||||||
|
Object v1 = cps.get(KEY);
|
||||||
|
assertEquals(VALUE_1, v1);
|
||||||
|
|
||||||
|
/* After adding a custom property with the same name the size must still
|
||||||
|
* be one. */
|
||||||
|
cps.put(KEY, VALUE_2);
|
||||||
|
assertEquals(1, cps.size());
|
||||||
|
Object v2 = cps.get(KEY);
|
||||||
|
assertEquals(VALUE_2, v2);
|
||||||
|
|
||||||
|
/* Removing the custom property must return the remove property and
|
||||||
|
* reduce the size to 0. */
|
||||||
|
cp = (CustomProperty) cps.remove(KEY);
|
||||||
|
assertEquals(KEY, cp.getName());
|
||||||
|
assertEquals(VALUE_2, cp.getValue());
|
||||||
|
assertEquals(0, cps.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Tests reading custom properties from a section including reading
|
||||||
|
* custom properties which are not pure.</p>
|
||||||
|
*/
|
||||||
|
public void testGetCustomerProperties()
|
||||||
|
{
|
||||||
|
final int ID_1 = 2;
|
||||||
|
final int ID_2 = 3;
|
||||||
|
final String NAME_1 = "Schlüssel ä";
|
||||||
|
final String VALUE_1 = "Wert 1";
|
||||||
|
final Map dictionary = new HashMap();
|
||||||
|
|
||||||
|
DocumentSummaryInformation dsi = PropertySetFactory.newDocumentSummaryInformation();
|
||||||
|
CustomProperties cps;
|
||||||
|
MutableSection s;
|
||||||
|
|
||||||
|
/* A document summary information set stream by default does have custom properties. */
|
||||||
|
cps = dsi.getCustomProperties();
|
||||||
|
assertEquals(null, cps);
|
||||||
|
|
||||||
|
/* Test an empty custom properties set. */
|
||||||
|
s = new MutableSection();
|
||||||
|
s.setFormatID(SectionIDMap.DOCUMENT_SUMMARY_INFORMATION_ID[1]);
|
||||||
|
// s.setCodepage(Constants.CP_UNICODE);
|
||||||
|
dsi.addSection(s);
|
||||||
|
cps = dsi.getCustomProperties();
|
||||||
|
assertEquals(0, cps.size());
|
||||||
|
|
||||||
|
/* Add a custom property. */
|
||||||
|
MutableProperty p = new MutableProperty();
|
||||||
|
p.setID(ID_1);
|
||||||
|
p.setType(Variant.VT_LPWSTR);
|
||||||
|
p.setValue(VALUE_1);
|
||||||
|
s.setProperty(p);
|
||||||
|
dictionary.put(new Long(ID_1), NAME_1);
|
||||||
|
s.setDictionary(dictionary);
|
||||||
|
cps = dsi.getCustomProperties();
|
||||||
|
assertEquals(1, cps.size());
|
||||||
|
assertTrue(cps.isPure());
|
||||||
|
|
||||||
|
/* Add another custom property. */
|
||||||
|
s.setProperty(ID_2, Variant.VT_LPWSTR, VALUE_1);
|
||||||
|
dictionary.put(new Long(ID_2), NAME_1);
|
||||||
|
s.setDictionary(dictionary);
|
||||||
|
cps = dsi.getCustomProperties();
|
||||||
|
assertEquals(1, cps.size());
|
||||||
|
assertFalse(cps.isPure());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Runs the test cases stand-alone.</p>
|
||||||
|
*
|
||||||
|
* @param args The command-line parameters.
|
||||||
|
* @throws Throwable if anything goes wrong.
|
||||||
|
*/
|
||||||
|
public static void main(final String[] args) throws Throwable
|
||||||
|
{
|
||||||
|
System.setProperty("HPSF.testdata.path",
|
||||||
|
"./src/testcases/org/apache/poi/hpsf/data");
|
||||||
|
junit.textui.TestRunner.run(TestWriteWellKnown.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
0
src/testcases/org/apache/poi/hpsf/data/TestCorel.shw
Executable file → Normal file
0
src/testcases/org/apache/poi/hpsf/data/TestCorel.shw
Executable file → Normal file
0
src/testcases/org/apache/poi/hpsf/data/TestGermanWord90.doc
Executable file → Normal file
0
src/testcases/org/apache/poi/hpsf/data/TestGermanWord90.doc
Executable file → Normal file
0
src/testcases/org/apache/poi/hpsf/data/TestRobert_Flaherty.doc
Executable file → Normal file
0
src/testcases/org/apache/poi/hpsf/data/TestRobert_Flaherty.doc
Executable file → Normal file
BIN
src/testcases/org/apache/poi/hpsf/data/TestWriteWellKnown.doc
Normal file
BIN
src/testcases/org/apache/poi/hpsf/data/TestWriteWellKnown.doc
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user