| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.hpsf.basic; |
| |
| import static org.hamcrest.MatcherAssert.assertThat; |
| import static org.hamcrest.core.IsEqual.equalTo; |
| import static org.junit.jupiter.api.Assertions.assertArrayEquals; |
| import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; |
| import static org.junit.jupiter.api.Assertions.assertEquals; |
| import static org.junit.jupiter.api.Assertions.assertNotNull; |
| import static org.junit.jupiter.api.Assertions.assertNull; |
| import static org.junit.jupiter.api.Assertions.assertThrows; |
| import static org.junit.jupiter.api.Assertions.assertTrue; |
| import static org.junit.jupiter.api.Assertions.fail; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.UnsupportedEncodingException; |
| import java.nio.charset.Charset; |
| import java.util.ArrayList; |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import org.apache.poi.POIDataSamples; |
| import org.apache.poi.hpsf.ClassID; |
| import org.apache.poi.hpsf.ClassIDPredefined; |
| import org.apache.poi.hpsf.DocumentSummaryInformation; |
| import org.apache.poi.hpsf.HPSFException; |
| import org.apache.poi.hpsf.NoFormatIDException; |
| import org.apache.poi.hpsf.NoPropertySetStreamException; |
| import org.apache.poi.hpsf.Property; |
| import org.apache.poi.hpsf.PropertySet; |
| import org.apache.poi.hpsf.PropertySetFactory; |
| import org.apache.poi.hpsf.Section; |
| import org.apache.poi.hpsf.SummaryInformation; |
| import org.apache.poi.hpsf.UnsupportedVariantTypeException; |
| import org.apache.poi.hpsf.Variant; |
| import org.apache.poi.hpsf.VariantSupport; |
| import org.apache.poi.hpsf.WritingNotSupportedException; |
| import org.apache.poi.hpsf.wellknown.PropertyIDMap; |
| import org.apache.poi.poifs.eventfilesystem.POIFSReader; |
| import org.apache.poi.poifs.eventfilesystem.POIFSReaderListener; |
| import org.apache.poi.poifs.filesystem.DirectoryEntry; |
| import org.apache.poi.poifs.filesystem.DocumentInputStream; |
| import org.apache.poi.poifs.filesystem.DocumentNode; |
| import org.apache.poi.poifs.filesystem.DocumentOutputStream; |
| import org.apache.poi.poifs.filesystem.POIFSDocument; |
| import org.apache.poi.poifs.filesystem.POIFSFileSystem; |
| import org.apache.poi.util.CodePageUtil; |
| import org.apache.poi.util.IOUtils; |
| import org.apache.poi.util.LittleEndianConsts; |
| import org.apache.poi.util.TempFile; |
| import org.junit.jupiter.api.Assumptions; |
| import org.junit.jupiter.api.Test; |
| |
| /** |
| * Tests HPSF's writing functionality |
| */ |
| class TestWrite { |
| private static final POIDataSamples _samples = POIDataSamples.getHPSFInstance(); |
| private static final int CODEPAGE_DEFAULT = -1; |
| |
| private static final String POI_FS = "TestHPSFWritingFunctionality.doc"; |
| |
| private static final String IMPROPER_DEFAULT_CHARSET_MESSAGE = |
| "Your default character set is " + getDefaultCharsetName() + |
| ". However, this testcase must be run in an environment " + |
| "with a default character set supporting at least " + |
| "8-bit-characters. You can achieve this by setting the " + |
| "LANG environment variable to a proper value, e.g. " + |
| "\"de_DE\"."; |
| |
| /* |
| @BeforeClass |
| public static void setUpClass() { |
| VariantSupport.setLogUnsupportedTypes(false); |
| } |
| */ |
| |
| /** |
| * Writes an empty property set to a POIFS and reads it back in. |
| * |
| * @exception IOException if an I/O exception occurs |
| */ |
| @Test |
| void withoutAFormatID() throws Exception { |
| final File filename = TempFile.createTempFile(POI_FS, ".doc"); |
| |
| /* Create a mutable property set with a section that does not have the |
| * formatID set: */ |
| final PropertySet ps = new PropertySet(); |
| ps.clearSections(); |
| ps.addSection(new Section()); |
| |
| /* Write it to a POIFS and the latter to disk: */ |
| try (OutputStream out = new FileOutputStream(filename); |
| POIFSFileSystem poiFs = new POIFSFileSystem(); |
| ByteArrayOutputStream psStream = new ByteArrayOutputStream()) { |
| assertThrows(NoFormatIDException.class, () -> ps.write(psStream)); |
| poiFs.createDocument(new ByteArrayInputStream(psStream.toByteArray()), SummaryInformation.DEFAULT_STREAM_NAME); |
| poiFs.writeFilesystem(out); |
| } |
| } |
| |
| /** |
| * Writes an empty property set to a POIFS and reads it back in. |
| * |
| * @exception IOException if an I/O exception occurs |
| * @exception UnsupportedVariantTypeException if HPSF does not yet support |
| * a variant type to be written |
| */ |
| @Test |
| void writeEmptyPropertySet() |
| throws IOException, UnsupportedVariantTypeException { |
| final File dataDir = _samples.getFile(""); |
| final File filename = new File(dataDir, POI_FS); |
| filename.deleteOnExit(); |
| |
| /* Create a mutable property set and write it to a POIFS: */ |
| try (OutputStream out = new FileOutputStream(filename); |
| POIFSFileSystem poiFs = new POIFSFileSystem(); |
| ByteArrayOutputStream psStream = new ByteArrayOutputStream()) { |
| final PropertySet ps = new PropertySet(); |
| final Section s = ps.getSections().get(0); |
| s.setFormatID(SummaryInformation.FORMAT_ID); |
| ps.write(psStream); |
| poiFs.createDocument(new ByteArrayInputStream(psStream.toByteArray()), SummaryInformation.DEFAULT_STREAM_NAME); |
| poiFs.writeFilesystem(out); |
| } |
| |
| /* Read the POIFS: */ |
| final POIFSReader r = new POIFSReader(); |
| final List<PropertySet> psa = new ArrayList<>(); |
| |
| r.registerListener(getListener(psa), SummaryInformation.DEFAULT_STREAM_NAME); |
| r.read(filename); |
| assertEquals(1, psa.size()); |
| } |
| |
| /** |
| * <p>Writes a simple property set with a SummaryInformation section to a |
| * POIFS and reads it back in.</p> |
| * |
| * @exception IOException if an I/O exception occurs |
| * @exception UnsupportedVariantTypeException if HPSF does not yet support |
| * a variant type to be written |
| */ |
| @Test |
| void writeSimplePropertySet() |
| throws IOException, UnsupportedVariantTypeException { |
| final String AUTHOR = "Rainer Klute"; |
| final String TITLE = "Test Document"; |
| final File dataDir = _samples.getFile(""); |
| final File filename = new File(dataDir, POI_FS); |
| filename.deleteOnExit(); |
| try (OutputStream out = new FileOutputStream(filename); |
| POIFSFileSystem poiFs = new POIFSFileSystem()) { |
| |
| final PropertySet ps = new PropertySet(); |
| final Section si = new Section(); |
| si.setFormatID(SummaryInformation.FORMAT_ID); |
| ps.clearSections(); |
| ps.addSection(si); |
| |
| final Property p = new Property(); |
| p.setID(PropertyIDMap.PID_AUTHOR); |
| p.setType(Variant.VT_LPWSTR); |
| p.setValue(AUTHOR); |
| si.setProperty(p); |
| si.setProperty(PropertyIDMap.PID_TITLE, Variant.VT_LPSTR, TITLE); |
| |
| poiFs.createDocument(ps.toInputStream(), SummaryInformation.DEFAULT_STREAM_NAME); |
| poiFs.writeFilesystem(out); |
| } |
| |
| /* Read the POIFS: */ |
| final List<PropertySet> psa = new ArrayList<>(); |
| final POIFSReader r = new POIFSReader(); |
| r.registerListener(getListener(psa), SummaryInformation.DEFAULT_STREAM_NAME); |
| r.read(filename); |
| assertEquals(1, psa.size()); |
| assertTrue(psa.get(0).isSummaryInformation()); |
| |
| final Section s = psa.get(0).getSections().get(0); |
| Object p1 = s.getProperty(PropertyIDMap.PID_AUTHOR); |
| Object p2 = s.getProperty(PropertyIDMap.PID_TITLE); |
| assertEquals(AUTHOR, p1); |
| assertEquals(TITLE, p2); |
| } |
| |
| |
| |
| /** |
| * Writes a simple property set with two sections to a POIFS and reads it |
| * back in. |
| * |
| * @exception IOException if an I/O exception occurs |
| * @exception WritingNotSupportedException if HPSF does not yet support |
| * a variant type to be written |
| */ |
| @Test |
| void writeTwoSections() throws WritingNotSupportedException, IOException { |
| final String STREAM_NAME = "PropertySetStream"; |
| final String SECTION1 = "Section 1"; |
| final String SECTION2 = "Section 2"; |
| final ClassID FORMATID = ClassIDPredefined.EXCEL_V12.getClassID(); |
| |
| final File dataDir = _samples.getFile(""); |
| final File filename = new File(dataDir, POI_FS); |
| filename.deleteOnExit(); |
| |
| try (OutputStream out = new FileOutputStream(filename); |
| POIFSFileSystem poiFs = new POIFSFileSystem()) { |
| final PropertySet ps = new PropertySet(); |
| ps.clearSections(); |
| |
| final Section s1 = new Section(); |
| s1.setFormatID(FORMATID); |
| s1.setProperty(2, SECTION1); |
| ps.addSection(s1); |
| |
| final Section s2 = new Section(); |
| s2.setFormatID(FORMATID); |
| s2.setProperty(2, SECTION2); |
| ps.addSection(s2); |
| |
| poiFs.createDocument(ps.toInputStream(), STREAM_NAME); |
| poiFs.writeFilesystem(out); |
| } |
| |
| /* Read the POIFS: */ |
| final PropertySet[] psa = new PropertySet[1]; |
| final POIFSReader r = new POIFSReader(); |
| final POIFSReaderListener listener = (event) -> { |
| assertDoesNotThrow(() -> psa[0] = PropertySetFactory.create(event.getStream())); |
| }; |
| |
| r.registerListener(listener,STREAM_NAME); |
| r.read(filename); |
| |
| assertNotNull(psa[0]); |
| Section s = (psa[0].getSections().get(0)); |
| assertEquals(s.getFormatID(), FORMATID); |
| Object p = s.getProperty(2); |
| assertEquals(SECTION1, p); |
| s = (psa[0].getSections().get(1)); |
| p = s.getProperty(2); |
| assertEquals(SECTION2, p); |
| } |
| |
| private static POIFSReaderListener getListener(List<PropertySet> psa) { |
| return event -> assertDoesNotThrow(() -> psa.add(PropertySetFactory.create(event.getStream()))); |
| } |
| |
| /** |
| * Writes and reads back various variant types and checks whether the |
| * stuff that has been read back equals the stuff that was written. |
| */ |
| @Test |
| void variantTypes() throws Exception { |
| final int codepage = CODEPAGE_DEFAULT; |
| Assumptions.assumeTrue(hasProperDefaultCharset(), IMPROPER_DEFAULT_CHARSET_MESSAGE); |
| |
| check(Variant.VT_EMPTY, null, codepage); |
| check(Variant.VT_BOOL, Boolean.TRUE, codepage); |
| check(Variant.VT_BOOL, Boolean.FALSE, codepage); |
| check( Variant.VT_CF, new byte[] { 8, 0, 0, 0, 1, 0, 0, 0, 1, 2, 3, 4 }, codepage ); |
| check(Variant.VT_I4, 27, codepage); |
| check(Variant.VT_I8, 28L, codepage); |
| check(Variant.VT_R8, 29.0d, codepage); |
| check(Variant.VT_I4, -27, codepage); |
| check(Variant.VT_I8, -28L, codepage); |
| check(Variant.VT_R8, -29.0d, codepage); |
| check(Variant.VT_FILETIME, new Date(), codepage); |
| check(Variant.VT_I4, Integer.MAX_VALUE, codepage); |
| check(Variant.VT_I4, Integer.MIN_VALUE, codepage); |
| check(Variant.VT_I8, Long.MAX_VALUE, codepage); |
| check(Variant.VT_I8, Long.MIN_VALUE, codepage); |
| check(Variant.VT_R8, Double.MAX_VALUE, codepage); |
| check(Variant.VT_R8, Double.MIN_VALUE, codepage); |
| checkString(Variant.VT_LPSTR, "\u00e4\u00f6\u00fc\u00df\u00c4\u00d6\u00dc", codepage); |
| checkString(Variant.VT_LPWSTR, "\u00e4\u00f6\u00fc\u00df\u00c4\u00d6\u00dc", codepage); |
| } |
| |
| |
| |
| /** |
| * Writes and reads back strings using several different codepages and |
| * checks whether the stuff that has been read back equals the stuff that |
| * was written. |
| */ |
| @Test |
| void codepages() throws UnsupportedVariantTypeException, IOException |
| { |
| final int[] validCodepages = {CODEPAGE_DEFAULT, CodePageUtil.CP_UTF8, CodePageUtil.CP_UNICODE, CodePageUtil.CP_WINDOWS_1252}; |
| for (final int cp : validCodepages) { |
| if (cp == -1 && !hasProperDefaultCharset()) |
| { |
| System.err.println(IMPROPER_DEFAULT_CHARSET_MESSAGE + |
| " This testcase is skipped for the default codepage."); |
| continue; |
| } |
| |
| final long t = (cp == CodePageUtil.CP_UNICODE) ? Variant.VT_LPWSTR : Variant.VT_LPSTR; |
| checkString(t, "\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc\u00df", cp); |
| if (cp == CodePageUtil.CP_UTF16 || cp == CodePageUtil.CP_UTF8) { |
| check(t, "\u79D1\u5B78", cp); |
| } |
| } |
| |
| final int[] invalidCodepages = new int[] {0, 1, 2, 4711, 815}; |
| for (int cp : invalidCodepages) { |
| assertThrows(UnsupportedEncodingException.class, |
| () -> checkString(Variant.VT_LPSTR, "\u00e4\u00f6\u00fc\u00c4\u00d6\u00dc\u00df", cp), |
| "UnsupportedEncodingException for codepage " + cp + " expected."); |
| } |
| |
| } |
| |
| |
| |
| /** |
| * Tests whether writing 8-bit characters to a Unicode property succeeds. |
| */ |
| @Test |
| void unicodeWrite8Bit() throws WritingNotSupportedException, IOException, NoPropertySetStreamException { |
| final String TITLE = "This is a sample title"; |
| final PropertySet mps = new PropertySet(); |
| final Section ms = mps.getSections().get(0); |
| ms.setFormatID(SummaryInformation.FORMAT_ID); |
| final Property p = new Property(); |
| p.setID(PropertyIDMap.PID_TITLE); |
| p.setType(Variant.VT_LPSTR); |
| p.setValue(TITLE); |
| ms.setProperty(p); |
| |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| mps.write(out); |
| out.close(); |
| byte[] bytes = out.toByteArray(); |
| |
| PropertySet psr = new PropertySet(bytes); |
| assertTrue(psr.isSummaryInformation()); |
| Section sr = psr.getSections().get(0); |
| String title = (String) sr.getProperty(PropertyIDMap.PID_TITLE); |
| assertEquals(TITLE, title); |
| } |
| |
| private void checkString(final long variantType, final String value, final int codepage) |
| throws UnsupportedVariantTypeException, IOException { |
| for (int i=0; i<value.length(); i++) { |
| check(variantType, value.substring(0, i), codepage); |
| } |
| } |
| |
| /** |
| * Writes a property and reads it back in. |
| * |
| * @param variantType The property's variant type. |
| * @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 IOException if an I/O exception occurs. |
| */ |
| private void check(final long variantType, final Object value, final int codepage) |
| throws UnsupportedVariantTypeException, IOException |
| { |
| final ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| VariantSupport.write(out, variantType, value, codepage); |
| out.close(); |
| final byte[] b = out.toByteArray(); |
| final Object objRead = |
| VariantSupport.read(b, 0, b.length + LittleEndianConsts.INT_SIZE, variantType, codepage); |
| if (objRead instanceof byte[]) { |
| assertArrayEquals((byte[])value, (byte[])objRead); |
| } else if (value != null && !value.equals(objRead)) { |
| assertEquals(value, objRead); |
| } |
| } |
| |
| /** |
| * <p>Tests writing and reading back a proper dictionary.</p> |
| */ |
| @Test |
| void dictionary() throws IOException, HPSFException { |
| final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); |
| copy.deleteOnExit(); |
| |
| /* Write: */ |
| final OutputStream out = new FileOutputStream(copy); |
| final POIFSFileSystem poiFs = new POIFSFileSystem(); |
| final PropertySet ps1 = new PropertySet(); |
| final Section s = ps1.getSections().get(0); |
| final Map<Long,String> m = new HashMap<>(3, 1.0f); |
| m.put(1L, "String 1"); |
| m.put(2L, "String 2"); |
| m.put(3L, "String 3"); |
| s.setDictionary(m); |
| s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]); |
| int codepage = CodePageUtil.CP_UNICODE; |
| s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); |
| poiFs.createDocument(ps1.toInputStream(), "Test"); |
| poiFs.writeFilesystem(out); |
| poiFs.close(); |
| out.close(); |
| |
| /* Read back: */ |
| final List<POIFile> psf = Util.readPropertySets(copy); |
| assertEquals(1, psf.size()); |
| final byte[] bytes = psf.get(0).getBytes(); |
| final InputStream in = new ByteArrayInputStream(bytes); |
| final PropertySet ps2 = PropertySetFactory.create(in); |
| |
| /* Check if the result is a DocumentSummaryInformation stream, as |
| * specified. */ |
| assertTrue(ps2.isDocumentSummaryInformation()); |
| |
| /* Compare the property set stream with the corresponding one |
| * from the origin file and check whether they are equal. */ |
| assertEquals(ps1, ps2); |
| } |
| |
| /** |
| * Tests that when using POIFS, we can do an in-place write |
| * without needing to stream in + out the whole kitchen sink |
| */ |
| @Test |
| void inPlacePOIFSWrite() throws Exception { |
| // We need to work on a File for in-place changes, so create a temp one |
| final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); |
| copy.deleteOnExit(); |
| |
| // Copy a test file over to our temp location |
| try (FileOutputStream out = new FileOutputStream(copy); |
| InputStream inp = _samples.openResourceAsStream("TestShiftJIS.doc")) { |
| IOUtils.copy(inp, out); |
| } |
| |
| // Open the copy in read/write mode |
| try (POIFSFileSystem fs = new POIFSFileSystem(copy, false)) { |
| DirectoryEntry root = fs.getRoot(); |
| |
| // Read the properties in there |
| DocumentNode sinfDoc = (DocumentNode) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME); |
| DocumentNode dinfDoc = (DocumentNode) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME); |
| |
| InputStream sinfStream = new DocumentInputStream(sinfDoc); |
| SummaryInformation sinf = (SummaryInformation) PropertySetFactory.create(sinfStream); |
| sinfStream.close(); |
| assertEquals(131077, sinf.getOSVersion()); |
| |
| InputStream dinfStream = new DocumentInputStream(dinfDoc); |
| DocumentSummaryInformation dinf = (DocumentSummaryInformation) PropertySetFactory.create(dinfStream); |
| dinfStream.close(); |
| assertEquals(131077, dinf.getOSVersion()); |
| |
| |
| // Check they start as we expect |
| assertEquals("Reiichiro Hori", sinf.getAuthor()); |
| assertEquals("Microsoft Word 9.0", sinf.getApplicationName()); |
| assertEquals("\u7b2c1\u7ae0", sinf.getTitle()); |
| |
| assertEquals("", dinf.getCompany()); |
| assertNull(dinf.getManager()); |
| |
| |
| // Do an in-place replace via an InputStream |
| assertNotNull(sinfDoc); |
| assertNotNull(dinfDoc); |
| |
| new POIFSDocument(sinfDoc).replaceContents(sinf.toInputStream()); |
| new POIFSDocument(dinfDoc).replaceContents(dinf.toInputStream()); |
| |
| |
| // Check it didn't get changed |
| sinfDoc = (DocumentNode) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME); |
| dinfDoc = (DocumentNode) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME); |
| |
| InputStream sinfStream2 = new DocumentInputStream(sinfDoc); |
| sinf = (SummaryInformation) PropertySetFactory.create(sinfStream2); |
| sinfStream2.close(); |
| assertEquals(131077, sinf.getOSVersion()); |
| |
| InputStream dinfStream2 = new DocumentInputStream(dinfDoc); |
| dinf = (DocumentSummaryInformation) PropertySetFactory.create(dinfStream2); |
| dinfStream2.close(); |
| assertEquals(131077, dinf.getOSVersion()); |
| } |
| |
| // Start again! |
| try (FileOutputStream out = new FileOutputStream(copy); |
| InputStream inp = _samples.openResourceAsStream("TestShiftJIS.doc")) { |
| IOUtils.copy(inp, out); |
| } |
| |
| try (POIFSFileSystem fs = new POIFSFileSystem(copy, false)) { |
| DirectoryEntry root = fs.getRoot(); |
| |
| // Read the properties in once more |
| DocumentNode sinfDoc = (DocumentNode)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME); |
| DocumentNode dinfDoc = (DocumentNode)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME); |
| |
| InputStream sinfStream3 = new DocumentInputStream(sinfDoc); |
| SummaryInformation sinf = (SummaryInformation)PropertySetFactory.create(sinfStream3); |
| sinfStream3.close(); |
| assertEquals(131077, sinf.getOSVersion()); |
| |
| InputStream dinfStream3 = new DocumentInputStream(dinfDoc); |
| DocumentSummaryInformation dinf = (DocumentSummaryInformation)PropertySetFactory.create(dinfStream3); |
| dinfStream3.close(); |
| assertEquals(131077, dinf.getOSVersion()); |
| |
| |
| // Have them write themselves in-place with no changes, as an OutputStream |
| OutputStream soufStream = new DocumentOutputStream(sinfDoc); |
| sinf.write(soufStream); |
| soufStream.close(); |
| OutputStream doufStream = new DocumentOutputStream(dinfDoc); |
| dinf.write(doufStream); |
| doufStream.close(); |
| |
| // And also write to some bytes for checking |
| ByteArrayOutputStream sinfBytes = new ByteArrayOutputStream(); |
| sinf.write(sinfBytes); |
| ByteArrayOutputStream dinfBytes = new ByteArrayOutputStream(); |
| dinf.write(dinfBytes); |
| |
| |
| // Check that the filesystem can give us back the same bytes |
| sinfDoc = (DocumentNode)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME); |
| dinfDoc = (DocumentNode)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME); |
| |
| InputStream sinfStream4 = new DocumentInputStream(sinfDoc); |
| byte[] sinfData = IOUtils.toByteArray(sinfStream4); |
| sinfStream4.close(); |
| InputStream dinfStream4 = new DocumentInputStream(dinfDoc); |
| byte[] dinfData = IOUtils.toByteArray(dinfStream4); |
| dinfStream4.close(); |
| assertThat(sinfBytes.toByteArray(), equalTo(sinfData)); |
| assertThat(dinfBytes.toByteArray(), equalTo(dinfData)); |
| |
| |
| // Read back in as-is |
| InputStream sinfStream5 = new DocumentInputStream(sinfDoc); |
| sinf = (SummaryInformation)PropertySetFactory.create(sinfStream5); |
| sinfStream5.close(); |
| assertEquals(131077, sinf.getOSVersion()); |
| |
| InputStream dinfStream5 = new DocumentInputStream(dinfDoc); |
| dinf = (DocumentSummaryInformation)PropertySetFactory.create(dinfStream5); |
| dinfStream5.close(); |
| assertEquals(131077, dinf.getOSVersion()); |
| |
| assertEquals("Reiichiro Hori", sinf.getAuthor()); |
| assertEquals("Microsoft Word 9.0", sinf.getApplicationName()); |
| assertEquals("\u7b2c1\u7ae0", sinf.getTitle()); |
| |
| assertEquals("", dinf.getCompany()); |
| assertNull(dinf.getManager()); |
| |
| |
| // Now alter a few of them |
| sinf.setAuthor("Changed Author"); |
| sinf.setTitle("Le titre \u00e9tait chang\u00e9"); |
| dinf.setManager("Changed Manager"); |
| |
| |
| // Save this into the filesystem |
| OutputStream soufStream2 = new DocumentOutputStream(sinfDoc); |
| sinf.write(soufStream2); |
| soufStream2.close(); |
| OutputStream doufStream2 = new DocumentOutputStream(dinfDoc); |
| dinf.write(doufStream2); |
| doufStream2.close(); |
| |
| |
| // Read them back in again |
| sinfDoc = (DocumentNode)root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME); |
| InputStream sinfStream6 = new DocumentInputStream(sinfDoc); |
| sinf = (SummaryInformation)PropertySetFactory.create(sinfStream6); |
| sinfStream6.close(); |
| assertEquals(131077, sinf.getOSVersion()); |
| |
| dinfDoc = (DocumentNode)root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME); |
| InputStream dinfStream6 = new DocumentInputStream(dinfDoc); |
| dinf = (DocumentSummaryInformation)PropertySetFactory.create(dinfStream6); |
| dinfStream6.close(); |
| assertEquals(131077, dinf.getOSVersion()); |
| |
| assertEquals("Changed Author", sinf.getAuthor()); |
| assertEquals("Microsoft Word 9.0", sinf.getApplicationName()); |
| assertEquals("Le titre \u00e9tait chang\u00e9", sinf.getTitle()); |
| |
| assertEquals("", dinf.getCompany()); |
| assertEquals("Changed Manager", dinf.getManager()); |
| |
| |
| // Close the whole filesystem, and open it once more |
| fs.writeFilesystem(); |
| } |
| |
| try (POIFSFileSystem fs = new POIFSFileSystem(copy)) { |
| DirectoryEntry root = fs.getRoot(); |
| |
| // Re-check on load |
| DocumentNode sinfDoc = (DocumentNode) root.getEntry(SummaryInformation.DEFAULT_STREAM_NAME); |
| InputStream sinfStream7 = new DocumentInputStream(sinfDoc); |
| SummaryInformation sinf = (SummaryInformation) PropertySetFactory.create(sinfStream7); |
| sinfStream7.close(); |
| assertEquals(131077, sinf.getOSVersion()); |
| |
| DocumentNode dinfDoc = (DocumentNode) root.getEntry(DocumentSummaryInformation.DEFAULT_STREAM_NAME); |
| InputStream dinfStream7 = new DocumentInputStream(dinfDoc); |
| DocumentSummaryInformation dinf = (DocumentSummaryInformation) PropertySetFactory.create(dinfStream7); |
| dinfStream7.close(); |
| assertEquals(131077, dinf.getOSVersion()); |
| |
| assertEquals("Changed Author", sinf.getAuthor()); |
| assertEquals("Microsoft Word 9.0", sinf.getApplicationName()); |
| assertEquals("Le titre \u00e9tait chang\u00e9", sinf.getTitle()); |
| |
| assertEquals("", dinf.getCompany()); |
| assertEquals("Changed Manager", dinf.getManager()); |
| } |
| |
| // Tidy up |
| assertTrue(copy.delete()); |
| } |
| |
| |
| /** |
| * Tests writing and reading back a proper dictionary with an invalid |
| * codepage. (HPSF writes Unicode dictionaries only.) |
| */ |
| @Test |
| void dictionaryWithInvalidCodepage() throws IOException, HPSFException { |
| final File copy = TempFile.createTempFile("Test-HPSF", "ole2"); |
| copy.deleteOnExit(); |
| |
| /* Write: */ |
| |
| final PropertySet ps1 = new PropertySet(); |
| final Section s = ps1.getSections().get(0); |
| final Map<Long,String> m = new HashMap<>(3, 1.0f); |
| m.put(1L, "String 1"); |
| m.put(2L, "String 2"); |
| m.put(3L, "String 3"); |
| |
| try (OutputStream out = new FileOutputStream(copy); |
| POIFSFileSystem poiFs = new POIFSFileSystem()) { |
| s.setDictionary(m); |
| s.setFormatID(DocumentSummaryInformation.FORMAT_ID[0]); |
| int codepage = 12345; |
| s.setProperty(PropertyIDMap.PID_CODEPAGE, Variant.VT_I2, codepage); |
| assertThrows(UnsupportedEncodingException.class, () -> poiFs.createDocument(ps1.toInputStream(), "Test")); |
| poiFs.writeFilesystem(out); |
| } |
| } |
| |
| /** |
| * <p>Returns the display name of the default character set.</p> |
| * |
| * @return the display name of the default character set. |
| */ |
| private static String getDefaultCharsetName() { |
| final String charSetName = System.getProperty("file.encoding"); |
| final Charset charSet = Charset.forName(charSetName); |
| return charSet.displayName(Locale.ROOT); |
| } |
| |
| /** |
| * <p>In order to execute tests with characters beyond US-ASCII, this |
| * method checks whether the application is runing in an environment |
| * 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() { |
| final String charSetName = System.getProperty("file.encoding"); |
| final Charset charSet = Charset.forName(charSetName); |
| return charSet.newEncoder().canEncode('\u00e4'); |
| } |
| } |