- /* ====================================================================
- 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.examples.hpsf;
-
- import java.io.File;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.PrintStream;
- import java.io.UnsupportedEncodingException;
-
- import org.apache.poi.hpsf.DocumentSummaryInformation;
- import org.apache.poi.hpsf.HPSFException;
- import org.apache.poi.hpsf.HPSFRuntimeException;
- import org.apache.poi.hpsf.PropertySet;
- import org.apache.poi.hpsf.PropertySetFactory;
- import org.apache.poi.hpsf.SummaryInformation;
- import org.apache.poi.hpsf.WritingNotSupportedException;
- import org.apache.poi.poifs.eventfilesystem.POIFSReader;
- import org.apache.poi.poifs.eventfilesystem.POIFSReaderEvent;
- import org.apache.poi.poifs.filesystem.DirectoryEntry;
- import org.apache.poi.poifs.filesystem.DocumentInputStream;
- import org.apache.poi.poifs.filesystem.EntryUtils;
- import org.apache.poi.poifs.filesystem.POIFSDocumentPath;
- import org.apache.poi.poifs.filesystem.POIFSFileSystem;
- import org.apache.poi.util.TempFile;
-
- /**
- * <p>This class copies a POI file system to a new file and compares the copy
- * with the original.</p>
- * <p>
- * <p>Property set streams are copied logically, i.e. the application
- * establishes a {@link org.apache.poi.hpsf.PropertySet} of an original property
- * set, creates a {@link org.apache.poi.hpsf.PropertySet} and writes the
- * {@link org.apache.poi.hpsf.PropertySet} to the destination POI file
- * system. - Streams which are no property set streams are copied bit by
- * bit.</p>
- * <p>
- * <p>The comparison of the POI file systems is done logically. That means that
- * the two disk files containing the POI file systems do not need to be
- * exactly identical. However, both POI file systems must contain the same
- * files, and most of these files must be bitwise identical. Property set
- * streams, however, are compared logically: they must have the same sections
- * with the same attributes, and the sections must contain the same properties.
- * Details like the ordering of the properties do not matter.</p>
- */
- @SuppressWarnings({"java:S106","java:S4823"})
- public final class CopyCompare {
- private CopyCompare() {}
-
- private static final ThreadLocal<PrintStream> out = ThreadLocal.withInitial(() -> System.out);
-
- /**
- * Runs the example program. The application expects one or two arguments:
- *
- * <ol>
- * <li>The first argument is the disk file name of the POI filesystem to copy.</li>
- * <li>The second argument is optional. If it is given, it is the name of
- * a disk file the copy of the POI filesystem will be written to. If it is
- * not given, the copy will be written to a temporary file which will be
- * deleted at the end of the program.</li>
- * </ol>
- *
- * @param args Command-line arguments.
- * @throws IOException if any I/O exception occurs.
- * @throws UnsupportedEncodingException if a character encoding is not
- * supported.
- */
- public static void main(final String[] args) throws IOException {
- String originalFileName = null;
- String copyFileName = null;
-
- // Check the command-line arguments.
- if (args.length == 1) {
- originalFileName = args[0];
- File f = TempFile.createTempFile("CopyOfPOIFileSystem-", ".ole2");
- f.deleteOnExit();
- copyFileName = f.getAbsolutePath();
- } else if (args.length == 2) {
- originalFileName = args[0];
- copyFileName = args[1];
- } else {
- System.err.println("Usage: CopyCompare originPOIFS [copyPOIFS]");
- System.exit(1);
- }
-
-
- // Read the origin POIFS using the eventing API.
- final POIFSReader r = new POIFSReader();
- try (final POIFSFileSystem poiFs = new POIFSFileSystem();
- OutputStream fos = new FileOutputStream(copyFileName)) {
- r.registerListener(e -> handleEvent(poiFs, e));
- r.setNotifyEmptyDirectories(true);
-
- r.read(new File(originalFileName));
-
- // Write the new POIFS to disk.
- poiFs.writeFilesystem(fos);
- }
-
- // Read all documents from the original POI file system and compare them with
- // the equivalent document from the copy.
- try (POIFSFileSystem opfs = new POIFSFileSystem(new File(originalFileName));
- POIFSFileSystem cpfs = new POIFSFileSystem(new File(copyFileName))) {
- final DirectoryEntry oRoot = opfs.getRoot();
- final DirectoryEntry cRoot = cpfs.getRoot();
- out.get().println(EntryUtils.areDirectoriesIdentical(oRoot, cRoot) ? "Equal" : "Not equal");
- }
- }
-
- public static void setOut(PrintStream ps) {
- out.set(ps);
- }
-
- private interface InputStreamSupplier {
- InputStream get() throws IOException, WritingNotSupportedException;
- }
-
- /**
- * The method is called by POI's eventing API for each file in the origin POIFS.
- */
- public static void handleEvent(final POIFSFileSystem poiFs, final POIFSReaderEvent event) {
- // The following declarations are shortcuts for accessing the "event" object.
- final DocumentInputStream stream = event.getStream();
-
- try {
-
- // Find out whether the current document is a property set stream or not.
- InputStreamSupplier su;
- if (stream != null && PropertySet.isPropertySetStream(stream)) {
- // Yes, the current document is a property set stream. Let's create
- // a PropertySet instance from it.
- PropertySet ps = PropertySetFactory.create(stream);
-
- // Copy the property set to the destination POI file system.
- final PropertySet mps;
- if (ps instanceof DocumentSummaryInformation) {
- mps = new DocumentSummaryInformation(ps);
- } else if (ps instanceof SummaryInformation) {
- mps = new SummaryInformation(ps);
- } else {
- mps = new PropertySet(ps);
- }
- su = mps::toInputStream;
- } else {
- // No, the current document is not a property set stream.
- // We copy it unmodified to the destination POIFS.
- su = event::getStream;
- }
-
- try (InputStream is = su.get()) {
- final POIFSDocumentPath path = event.getPath();
-
- // Ensures that the directory hierarchy for a document in a POI fileystem is in place.
- // Get the root directory. It does not have to be created since it always exists in a POIFS.
- DirectoryEntry de = poiFs.getRoot();
- if (File.separator.equals(path.toString())) {
- de.setStorageClsid(event.getStorageClassId());
- }
-
- for (int i=0; i<path.length(); i++) {
- String subDir = path.getComponent(i);
- if (de.hasEntry(subDir)) {
- de = (DirectoryEntry)de.getEntry(subDir);
- } else {
- de = de.createDirectory(subDir);
- if (i == path.length()-1) {
- de.setStorageClsid(event.getStorageClassId());
- }
- }
- }
-
- if (event.getName() != null) {
- de.createDocument(event.getName(), is);
- }
- }
-
- } catch (HPSFException | IOException ex) {
- // According to the definition of the processPOIFSReaderEvent method we cannot pass checked
- // exceptions to the caller.
- throw new HPSFRuntimeException("Could not read file " + event.getPath() + "/" + event.getName(), ex);
- }
- }
- }
|