Flushing before closing stream - fixed race condition in doc save test (not always reproducable

git-svn-id: https://svn.apache.org/repos/asf/incubator/odf/trunk@1702610 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
index 0435471..2ed8991 100644
--- a/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
+++ b/odfdom/src/main/java/org/odftoolkit/odfdom/pkg/OdfPackage.java
@@ -59,10 +59,7 @@
 import java.util.zip.Deflater;

 import java.util.zip.Inflater;

 import java.util.zip.ZipEntry;

-import java.util.zip.ZipException;

-import java.util.zip.ZipFile;

 import java.util.zip.ZipOutputStream;

-

 import javax.crypto.Cipher;

 import javax.crypto.Mac;

 import javax.crypto.spec.IvParameterSpec;

@@ -75,7 +72,6 @@
 import javax.xml.transform.TransformerConfigurationException;

 import javax.xml.transform.TransformerException;

 import javax.xml.transform.URIResolver;

-

 import org.apache.xerces.dom.DOMXSImplementationSourceImpl;

 import org.odftoolkit.odfdom.doc.OdfDocument;

 import org.odftoolkit.odfdom.doc.OdfDocument.OdfMediaType;

@@ -107,7 +103,7 @@
  * effect, when the OdfPackage is being made persisted by save().

  */

 public class OdfPackage implements Closeable {

-	

+

 	// Static parts of file references

 	private static final String DOUBLE_DOT = "..";

 	private static final String DOT = ".";

@@ -139,16 +135,16 @@
 	// save() will check 1) mPkgDoms, 2) if not check mMemoryFileCache

 	private HashMap<String, Document> mPkgDoms;

 	private HashMap<String, byte[]> mMemoryFileCache;

-	

+

 	private ErrorHandler mErrorHandler;

 	private String mManifestVersion;

 	private OdfManifestDom mManifestDom;

 	private String oldPwd;

 	private String newPwd;

-	

+

 	/* Commonly used files within the ODF Package */

 	public enum OdfFile {

-		

+

 		/**

 		 * The image directory is not defined by the OpenDocument standard,

 		 * nevertheless the most spread ODF application OpenOffice.org is using

@@ -169,22 +165,22 @@
 		 */

 		MEDIA_TYPE("mimetype");

 		private final String internalPath;

-		

+

 		OdfFile(String internalPath) {

 			this.internalPath = internalPath;

 		}

-		

+

 		public String getPath() {

 			return internalPath;

 		}

 	}

-	

+

 	static {

 		mCompressedFileTypes = new HashSet<String>();

 		String[] typelist = new String[] { "jpg", "gif", "png", "zip", "rar", "jpeg", "mpe", "mpg", "mpeg", "mpeg4", "mp4", "7z", "ari", "arj", "jar", "gz", "tar", "war", "mov", "avi" };

 		mCompressedFileTypes.addAll(Arrays.asList(typelist));

 	}

-	

+

 	/**

 	 * Creates the ODFPackage as an empty Package.

 	 */

@@ -216,14 +212,14 @@
 			}

 		}

 	}

-	

+

 	/**

 	 * Creates an OdfPackage from the OpenDocument provided by a File.

 	 * <p>

 	 * OdfPackage relies on the file being available for read access over the

 	 * whole lifecycle of OdfPackage.

 	 * </p>

-	 * 

+	 *

 	 * @param pkgFile

 	 *            - a file representing the ODF document

 	 * @param baseURI

@@ -244,17 +240,17 @@
 		oldPwd = password;

 		newPwd = oldPwd;

 		mBaseURI = baseURI;

-		

+

 		InputStream packageStream = new FileInputStream(pkgFile);

 		try {

 			initializeZip(packageStream);

 		} finally {

 			close(packageStream);

 		}

-		

+

 		// initializeZip(pkgFile);

 	}

-	

+

 	/**

 	 * Creates an OdfPackage from the OpenDocument provided by a InputStream.

 	 * <p>

@@ -262,7 +258,7 @@
 	 * read access needed by OdfPackage, the InputStream is cached. This usually

 	 * takes more time compared to the other constructors.

 	 * </p>

-	 * 

+	 *

 	 * @param packageStream

 	 *            - an inputStream representing the ODF package

 	 * @param baseURI

@@ -284,14 +280,14 @@
 		newPwd = oldPwd;

 		initializeZip(packageStream);

 	}

-	

+

 	/**

 	 * Loads an OdfPackage from the given documentURL.

 	 * <p>

 	 * OdfPackage relies on the file being available for read access over the

 	 * whole lifecycle of OdfPackage.

 	 * </p>

-	 * 

+	 *

 	 * @param path

 	 *            - the documentURL to the ODF package

 	 * @return the OpenDocument document represented as an OdfPackage

@@ -302,14 +298,14 @@
 		File pkgFile = new File(path);

 		return new OdfPackage(pkgFile, getBaseURLFromFile(pkgFile), null, null);

 	}

-	

+

 	/**

 	 * Loads an OdfPackage from the OpenDocument provided by a File.

 	 * <p>

 	 * OdfPackage relies on the file being available for read access over the

 	 * whole lifecycle of OdfPackage.

 	 * </p>

-	 * 

+	 *

 	 * @param pkgFile

 	 *            - the ODF Package

 	 * @return the OpenDocument document represented as an OdfPackage

@@ -319,7 +315,7 @@
 	public static OdfPackage loadPackage(File pkgFile) throws Exception {

 		return new OdfPackage(pkgFile, getBaseURLFromFile(pkgFile), null, null);

 	}

-	

+

 	/**

 	 * Creates an OdfPackage from the given InputStream.

 	 * <p>

@@ -327,7 +323,7 @@
 	 * read access needed by OdfPackage, the InputStream is cached. This usually

 	 * takes more time compared to the other loadPackage methods.

 	 * </p>

-	 * 

+	 *

 	 * @param packageStream

 	 *            - an inputStream representing the ODF package

 	 * @return the OpenDocument document represented as an OdfPackage

@@ -337,14 +333,14 @@
 	public static OdfPackage loadPackage(InputStream packageStream) throws Exception {

 		return new OdfPackage(packageStream, null, null, null);

 	}

-	

+

 	/**

 	 * Creates an OdfPackage from the given InputStream.

 	 * <p>

 	 * OdfPackage relies on the file being available for read access over the

 	 * whole lifecycle of OdfPackage.

 	 * </p>

-	 * 

+	 *

 	 * @param packageStream

 	 *            - an inputStream representing the ODF package

 	 * @param baseURI

@@ -362,14 +358,14 @@
 	public static OdfPackage loadPackage(InputStream packageStream, String baseURI, ErrorHandler errorHandler) throws Exception {

 		return new OdfPackage(packageStream, baseURI, null, errorHandler);

 	}

-	

+

 	/**

 	 * Loads an OdfPackage from the given File.

 	 * <p>

 	 * OdfPackage relies on the file being available for read access over the

 	 * whole lifecycle of OdfPackage.

 	 * </p>

-	 * 

+	 *

 	 * @param pkgFile

 	 *            - the ODF Package. A baseURL is being generated based on its

 	 *            location.

@@ -382,14 +378,14 @@
 	public static OdfPackage loadPackage(File pkgFile, ErrorHandler errorHandler) throws Exception {

 		return new OdfPackage(pkgFile, getBaseURLFromFile(pkgFile), null, errorHandler);

 	}

-	

+

 	/**

 	 * Loads an OdfPackage from the given File.

 	 * <p>

 	 * OdfPackage relies on the file being available for read access over the

 	 * whole lifecycle of OdfPackage.

 	 * </p>

-	 * 

+	 *

 	 * @param pkgFile

 	 *            - the ODF Package. A baseURL is being generated based on its

 	 *            location.

@@ -404,7 +400,7 @@
 	public static OdfPackage loadPackage(File pkgFile, String password, ErrorHandler errorHandler) throws Exception {

 		return new OdfPackage(pkgFile, getBaseURLFromFile(pkgFile), password, errorHandler);

 	}

-	

+

 	// Initialize using memory

 	private void initializeZip(InputStream odfStream) throws Exception {

 		ByteArrayOutputStream tempBuf = new ByteArrayOutputStream();

@@ -421,7 +417,7 @@
 		mZipFile = new ZipHelper(this, mTempByteBuf);

 		readZip();

 	}

-	

+

 	// // Initialize using ZipFile

 	// private void initializeZip(File pkgFile) throws Exception {

 	// try {

@@ -437,7 +433,7 @@
 	// }

 	// readZip();

 	// }

-	

+

 	private void readZip() throws Exception {

 		mZipEntries = new HashMap<String, ZipEntry>();

 		String firstEntryName = mZipFile.entriesToMap(mZipEntries);

@@ -450,10 +446,10 @@
 		} else {

 			// initialize the files of the package (fileEnties of Manifest)

 			parseManifest();

-			

+

 			// initialize the package media type

 			initializeMediaType(firstEntryName);

-			

+

 			// ToDo: Remove all META-INF/* files from the fileEntries of

 			// Manifest

 			mOriginalZipEntries = new HashMap<String, ZipEntry>();

@@ -479,10 +475,10 @@
 			}

 		}

 	}

-	

+

 	/**

 	 * Validates if all file entries exist in the ZIP and vice versa

-	 * 

+	 *

 	 * @throws SAXException

 	 */

 	private void validateManifest() throws SAXException {

@@ -490,7 +486,7 @@
 		Set manifestPaths = mManifestEntries.keySet();

 		Set<String> sharedPaths = new HashSet<String>(zipPaths);

 		sharedPaths.retainAll(manifestPaths);

-		

+

 		if (sharedPaths.size() < zipPaths.size()) {

 			Set<String> zipPathSuperset = new HashSet<String>(mZipEntries.keySet());

 			zipPathSuperset.removeAll(sharedPaths);

@@ -510,7 +506,7 @@
 			zipPathSubset.removeAll(sharedPaths);

 			// removing root directory

 			zipPathSubset.remove(SLASH);

-			

+

 			// No directory are listed in a ZIP removing all directory with

 			// content

 			Iterator<String> manifestOnlyPaths = zipPathSubset.iterator();

@@ -536,10 +532,10 @@
 			}

 		}

 	}

-	

+

 	/**

 	 * Removes directories without a mimetype (all none documents)

-	 * 

+	 *

 	 * @throws SAXException

 	 */

 	private void removeDirectory(String path) throws SAXException {

@@ -555,11 +551,11 @@
 			}

 		}

 	}

-	

+

 	/**

 	 * Reads the uncompressed "mimetype" file, which contains the package

 	 * media/mimte type

-	 * 

+	 *

 	 * @throws SAXException

 	 */

 	private void initializeMediaType(String firstEntryName) throws SAXException {

@@ -614,9 +610,9 @@
 			}

 		}

 	}

-	

+

 	private void validateMimeTypeEntry(ZipEntry mimetypeEntry, String firstEntryName) throws SAXException {

-		

+

 		if (mimetypeEntry.getMethod() != ZipEntry.STORED) {

 			logValidationError(OdfPackageConstraint.MIMETYPE_IS_COMPRESSED, getBaseURI());

 		}

@@ -627,7 +623,7 @@
 			logValidationError(OdfPackageConstraint.MIMETYPE_NOT_FIRST_IN_PACKAGE, getBaseURI());

 		}

 	}

-	

+

 	/** @returns the media type of the root document from the manifest.xml */

 	private String getMediaTypeFromManifest() {

 		OdfFileEntry rootDocumentEntry = mManifestEntries.get(SLASH);

@@ -637,7 +633,7 @@
 			return null;

 		}

 	}

-	

+

 	/** @returns the media type of the root document from the manifest.xml */

 	private String getMediaTypeFromEntry(ZipEntry mimetypeEntry) {

 		String entryMediaType = null;

@@ -659,12 +655,12 @@
 		}

 		return entryMediaType;

 	}

-	

+

 	/**

 	 * Insert an Odf document into the package at the given path. The path has

 	 * to be a directory and will receive the MIME type of the

 	 * OdfPackageDocument.

-	 * 

+	 *

 	 * @param doc

 	 *            the OdfPackageDocument to be inserted.

 	 * @param internalPath

@@ -676,18 +672,18 @@
 		updateFileEntry(ensureFileEntryExistence(internalPath), doc.getMediaTypeString());

 		mPkgDocuments.put(internalPath, doc);

 	}

-	

+

 	/**

 	 * Set the baseURI for this ODF package. NOTE: Should only be set during

 	 * saving the package.

-	 * 

+	 *

 	 * @param baseURI

 	 *            defining the location of the package

 	 */

 	void setBaseURI(String baseURI) {

 		mBaseURI = baseURI;

 	}

-	

+

 	/**

 	 * @return The URI to the ODF package, usually the URL, where this ODF

 	 *         package is located. If the package has not URI NULL is returned.

@@ -697,10 +693,10 @@
 	public String getBaseURI() {

 		return mBaseURI;

 	}

-	

+

 	/**

 	 * Returns on ODF documents based a given mediatype.

-	 * 

+	 *

 	 * @param internalPath

 	 *            path relative to the package root, where the document should

 	 *            be inserted.

@@ -732,7 +728,7 @@
 		}

 		return doc;

 	}

-	

+

 	/**

 	 * @deprecated This method is only added temporary as workaround for the IBM

 	 *             fork using different DOC classes. Until the registering of

@@ -747,7 +743,7 @@
 		internalPath = normalizeDirectoryPath(internalPath);

 		return mPkgDocuments.get(internalPath);

 	}

-	

+

 	/**

 	 * @param dom

 	 *            the DOM tree that has been parsed and should be added to the

@@ -761,7 +757,7 @@
 		internalPath = normalizeFilePath(internalPath);

 		this.insert(dom, internalPath, null);

 	}

-	

+

 	/**

 	 * @param internalPath

 	 *            path relative to the package root, where the document should

@@ -772,7 +768,7 @@
 		internalPath = normalizeFilePath(internalPath);

 		return this.mPkgDoms.get(internalPath);

 	}

-	

+

 	/**

 	 * @return a map with all open W3C XML documents with their internal package

 	 *         path as key.

@@ -780,11 +776,11 @@
 	Map<String, Document> getCachedDoms() {

 		return this.mPkgDoms;

 	}

-	

+

 	/**

 	 * Removes a document from the package via its path. Independent if it was

 	 * already opened or not.

-	 * 

+	 *

 	 * @param internalPath

 	 *            path relative to the package root, where the document should

 	 *            be removed.

@@ -795,7 +791,7 @@
 		try {

 			// get all files of the package

 			Set<String> allPackageFileNames = getFilePaths();

-			

+

 			// If the document is the root document

 			// the "/" representing the root document is outside the

 			// manifest.xml in the API an empty path

@@ -822,28 +818,28 @@
 		} catch (Exception ex) {

 			Logger.getLogger(OdfPackageDocument.class.getName()).log(Level.SEVERE, null, ex);

 		}

-		

+

 	}

-	

+

 	/** @return all currently opened OdfPackageDocument of this OdfPackage */

 	Set<String> getCachedPackageDocuments() {

 		return mPkgDocuments.keySet();

 	}

-	

+

 	public OdfPackageDocument getRootDocument() {

 		return mPkgDocuments.get(OdfPackageDocument.ROOT_DOCUMENT_PATH);

 	}

-	

+

 	public OdfManifestDom getManifestDom() {

 		return mManifestDom;

 	}

-	

+

 	/**

 	 * Get the media type of the ODF file or document (ie. a directory). A

 	 * directory with a mediatype can be loaded as

 	 * <code>OdfPackageDocument</code>. Note: A directoy is represented by in

 	 * the package as directory with media type

-	 * 

+	 *

 	 * @param internalPath

 	 *            within the package of the file or document.

 	 * @return the mediaType for the resource of the given path

@@ -863,7 +859,7 @@
 		}

 		return mediaType;

 	}

-	

+

 	private String getMediaTypeFromEntry(String internalPath) {

 		OdfFileEntry entry = getFileEntry(internalPath);

 		// if the document is not in the package, the return is NULL

@@ -873,32 +869,32 @@
 			return null;

 		}

 	}

-	

+

 	/**

 	 * Get the media type of the ODF package (equal to media type of ODF root

 	 * document)

-	 * 

+	 *

 	 * @return the mediaType string of this ODF package

 	 */

 	public String getMediaTypeString() {

 		return mMediaType;

 	}

-	

+

 	/**

 	 * Set the media type of the ODF package (equal to media type of ODF root

 	 * document)

-	 * 

+	 *

 	 * @param mediaType

 	 *            string of this ODF package

 	 */

 	void setMediaTypeString(String mediaType) {

 		mMediaType = mediaType;

 	}

-	

+

 	/**

 	 * Get an OdfFileEntry for the internalPath NOTE: This method should be

 	 * better moved to a DOM inherited Manifest class

-	 * 

+	 *

 	 * @param internalPath

 	 *            The relative package path within the ODF package

 	 * @return The manifest file entry will be returned.

@@ -907,19 +903,19 @@
 		internalPath = normalizeFilePath(internalPath);

 		return mManifestEntries.get(internalPath);

 	}

-	

+

 	/**

 	 * Get a OdfFileEntries from the manifest file (i.e. /META/manifest.xml")

-	 * 

+	 *

 	 * @return The paths of the manifest file entries will be returned.

 	 */

 	public Set<String> getFilePaths() {

 		return mManifestEntries.keySet();

 	}

-	

+

 	/**

 	 * Check existence of a file in the package.

-	 * 

+	 *

 	 * @param internalPath

 	 *            The relative package documentURL within the ODF package

 	 * @return True if there is an entry and a file for the given documentURL

@@ -928,10 +924,10 @@
 		internalPath = normalizeFilePath(internalPath);

 		return mManifestEntries.containsKey(internalPath);

 	}

-	

+

 	/**

 	 * Save the package to given documentURL.

-	 * 

+	 *

 	 * @param odfPath

 	 *            - the path to the ODF package destination

 	 * @throws java.lang.Exception

@@ -941,11 +937,11 @@
 		File f = new File(odfPath);

 		save(f);

 	}

-	

+

 	/**

 	 * Save package to a given File. After saving it is still necessary to close

 	 * the package to have again full access about the file.

-	 * 

+	 *

 	 * @param pkgFile

 	 *            - the File to save the ODF package to

 	 * @throws java.lang.Exception

@@ -963,15 +959,15 @@
 		FileOutputStream fos = new FileOutputStream(pkgFile);

 		save(fos, baseURL);

 	}

-	

+

 	public void save(OutputStream odfStream) throws Exception {

 		save(odfStream, null);

 	}

-	

+

 	/**

 	 * Sets the password of this package. if password is not null, package will

 	 * be encrypted when save.

-	 * 

+	 *

 	 * @param password

 	 *            password

 	 * @since 0.8.9

@@ -979,10 +975,10 @@
 	public void setPassword(String password) {

 		newPwd = password;

 	}

-	

+

 	/**

 	 * Save an ODF document to the OutputStream.

-	 * 

+	 *

 	 * @param odfStream

 	 *            - the OutputStream to insert content to

 	 * @param baseURL

@@ -1040,15 +1036,15 @@
 			data = getBytes(OdfFile.MANIFEST.getPath());

 			createZipEntry(OdfFile.MANIFEST.getPath(), data, zos, modTime, crc);

 		} finally {

+            zos.flush();

 			zos.close();

 		}

-		odfStream.flush();

 		// } catch (IOException ex) {

 		// Logger.getLogger(OdfPackage.class.getName()).log(Level.SEVERE, null,

 		// ex);

 		// }

 	}

-	

+

 	private void createZipEntry(String path, byte[] data, ZipOutputStream zos, long modTime, CRC32 crc) throws IOException {

 		ZipEntry ze = null;

 		// try {

@@ -1104,10 +1100,10 @@
 		// ex);

 		// }

 	}

-	

+

 	/**

 	 * Determines if a file have to be encrypted.

-	 * 

+	 *

 	 * @param internalPath

 	 *            the file location

 	 * @return true if the file needs encrypted, false, otherwise

@@ -1123,17 +1119,17 @@
 			return false;

 		}

 	}

-	

+

 	/**

 	 * Determines if a file have to be compressed.

-	 * 

+	 *

 	 * @param internalPath

 	 *            the file location

 	 * @return true if the file needs compression, false, otherwise

 	 */

 	private boolean fileNeedsCompression(String internalPath) {

 		boolean result = true;

-		

+

 		// ODF spec does not allow compression of "./mimetype" file

 		if (internalPath.equals(OdfPackage.OdfFile.MEDIA_TYPE.getPath())) {

 			return false;

@@ -1147,7 +1143,7 @@
 		}

 		return result;

 	}

-	

+

 	private void close(Closeable closeable) throws SAXException, IOException {

 		if (closeable != null) {

 			try {

@@ -1159,7 +1155,7 @@
 			}

 		}

 	}

-	

+

 	private void handleIOException(IOException ex, boolean warningOnly) throws SAXException, IOException {

 		if (mErrorHandler != null) {

 			SAXParseException se = new SAXParseException(ex.getMessage(), null, ex);

@@ -1181,7 +1177,7 @@
 		}

 		throw ex; // No error handler? Just throw the original IOException

 	}

-	

+

 	/**

 	 * Close the OdfPackage after it is no longer needed. Even after saving it

 	 * is still necessary to close the package to have again full access about

@@ -1208,7 +1204,7 @@
 		mBaseURI = null;

 		mResolver = null;

 	}

-	

+

 	/**

 	 * Parse the Manifest file

 	 */

@@ -1249,7 +1245,7 @@
 		// ex);

 		// }

 	}

-	

+

 	XMLReader getXMLReader() throws ParserConfigurationException, SAXException {

 		// create sax parser

 		SAXParserFactory saxFactory = new org.apache.xerces.jaxp.SAXParserFactoryImpl();

@@ -1260,7 +1256,7 @@
 		} catch (Exception ex) {

 			Logger.getLogger(OdfPackage.class.getName()).log(Level.SEVERE, null, ex);

 		}

-		

+

 		SAXParser parser = saxFactory.newSAXParser();

 		XMLReader xmlReader = parser.getXMLReader();

 		// More details at

@@ -1274,7 +1270,7 @@
 		xmlReader.setFeature("http://xml.org/sax/features/xmlns-uris", true);

 		return xmlReader;

 	}

-	

+

 	// Add the given path and all its subdirectories to the internalPath list

 	// to be written later to the manifest

 	private void createSubEntries(String internalPath) {

@@ -1295,10 +1291,10 @@
 			}

 		}

 	}

-	

+

 	/**

 	 * Insert DOM tree into OdfPackage. An existing file will be replaced.

-	 * 

+	 *

 	 * @param fileDOM

 	 *            - XML DOM tree to be inserted as file.

 	 * @param internalPath

@@ -1325,11 +1321,11 @@
 		// remove byte array version of new DOM

 		mMemoryFileCache.remove(internalPath);

 	}

-	

+

 	/**

 	 * Embed an OdfPackageDocument to the current OdfPackage. All the file

 	 * entries of child document will be inserted.

-	 * 

+	 *

 	 * @param sourceDocument

 	 *            the OdfPackageDocument to be embedded.

 	 * @param internalPath

@@ -1340,7 +1336,7 @@
 		internalPath = normalizeDirectoryPath(internalPath);

 		// opened DOM of descendant Documents will be flashed to the their pkg

 		flushDoms(sourceDocument);

-		

+

 		// Gets the OdfDocument's manifest entry info, no matter it is a

 		// independent document or an embeddedDocument.

 		Map<String, OdfFileEntry> entryMapToCopy;

@@ -1388,11 +1384,11 @@
 		sourceDocument.setPackage(this);

 		cacheDocument(sourceDocument, internalPath);

 	}

-	

+

 	/**

 	 * Insert all open DOMs of XML files beyond parent document to the package.

 	 * The XML files will be updated in the package after calling save.

-	 * 

+	 *

 	 * @param parentDocument

 	 *            the document, which XML files shall be serialized

 	 */

@@ -1419,7 +1415,7 @@
 			}

 		}

 	}

-	

+

 	/** Get all the file entries from a sub directory */

 	private Map<String, OdfFileEntry> getSubDirectoryEntries(OdfPackage destinationPackage, String directory) {

 		directory = normalizeDirectoryPath(directory);

@@ -1442,21 +1438,21 @@
 		}

 		return subEntries;

 	}

-	

+

 	/**

 	 * Method returns the paths of all document within the package.

-	 * 

+	 *

 	 * @return A set of paths of all documents of the package, including the

 	 *         root document.

 	 */

 	public Set<String> getDocumentPaths() {

 		return getDocumentPaths(null, null);

 	}

-	

+

 	/**

 	 * Method returns the paths of all document within the package matching the

 	 * given criteria.

-	 * 

+	 *

 	 * @param mediaTypeString

 	 *            limits the desired set of document paths to documents of the

 	 *            given mediaType

@@ -1466,11 +1462,11 @@
 	public Set<String> getDocumentPaths(String mediaTypeString) {

 		return getDocumentPaths(mediaTypeString, null);

 	}

-	

+

 	/**

 	 * Method returns the paths of all document within the package matching the

 	 * given criteria.

-	 * 

+	 *

 	 * @param mediaTypeString

 	 *            limits the desired set of document paths to documents of the

 	 *            given mediaType

@@ -1505,7 +1501,7 @@
 		}

 		return innerDocuments;

 	}

-	

+

 	/**

 	 * Adding a manifest:file-entry to be saved in manifest.xml. In addition,

 	 * sub directories will be added as well to the manifest.

@@ -1531,7 +1527,7 @@
 		}

 		return fileEntry;

 	}

-	

+

 	/**

 	 * update file entry setting.

 	 */

@@ -1543,10 +1539,10 @@
 		// reset size to be unset

 		fileEntry.setSize(null);

 	}

-	

+

 	/**

 	 * Gets org.w3c.dom.Document for XML file contained in package.

-	 * 

+	 *

 	 * @param internalPath

 	 *            to a file within the Odf Package (eg. content.xml)

 	 * @return an org.w3c.dom.Document

@@ -1558,46 +1554,46 @@
 	 * @throws TransformerException

 	 */

 	public Document getDom(String internalPath) throws SAXException, ParserConfigurationException, IllegalArgumentException, TransformerConfigurationException, TransformerException, IOException {

-		

+

 		Document doc = mPkgDoms.get(internalPath);

 		if (doc != null) {

 			return doc;

 		}

-		

+

 		InputStream is = getInputStream(internalPath);

-		

+

 		// We depend on Xerces. So we just go ahead and create a Xerces DBF,

 		// without

 		// forcing everything else to do so.

 		DocumentBuilderFactory factory = new org.apache.xerces.jaxp.DocumentBuilderFactoryImpl();

 		factory.setNamespaceAware(true);

 		factory.setValidating(false);

-		

+

 		DocumentBuilder builder = factory.newDocumentBuilder();

 		builder.setEntityResolver(getEntityResolver());

-		

+

 		String uri = getBaseURI() + internalPath;

-		

+

 		if (mErrorHandler != null) {

 			builder.setErrorHandler(mErrorHandler);

 		}

-		

+

 		InputSource ins = new InputSource(is);

 		ins.setSystemId(uri);

-		

+

 		doc = builder.parse(ins);

-		

+

 		if (doc != null) {

 			mPkgDoms.put(internalPath, doc);

 			mMemoryFileCache.remove(internalPath);

 		}

 		return doc;

 	}

-	

+

 	/**

 	 * Inserts an external file into an OdfPackage. An existing file will be

 	 * replaced.

-	 * 

+	 *

 	 * @param sourceURI

 	 *            - the source URI to the file to be inserted into the package.

 	 * @param internalPath

@@ -1619,11 +1615,11 @@
 		}

 		insert(is, internalPath, mediaType);

 	}

-	

+

 	/**

 	 * Inserts InputStream into an OdfPackage. An existing file will be

 	 * replaced.

-	 * 

+	 *

 	 * @param fileStream

 	 *            - the stream of the file to be inserted into the ODF package.

 	 * @param internalPath

@@ -1650,12 +1646,12 @@
 			insert(data, internalPath, mediaType);

 		}

 	}

-	

+

 	/**

 	 * Inserts a byte array into OdfPackage. An existing file will be replaced.

 	 * If the byte array is NULL a directory with the given mimetype will be

 	 * created.

-	 * 

+	 *

 	 * @param fileBytes

 	 *            - data of the file stream to be stored in package. If NULL a

 	 *            directory with the given mimetype will be created.

@@ -1684,16 +1680,16 @@
 		}

 		updateFileEntry(ensureFileEntryExistence(internalPath), mediaTypeString);

 	}

-	

+

 	// changed to package access as the manifest interiors are an implementation

 	// detail

 	Map<String, OdfFileEntry> getManifestEntries() {

 		return mManifestEntries;

 	}

-	

+

 	/**

 	 * Get package (sub-) content as byte array

-	 * 

+	 *

 	 * @param internalPath

 	 *            relative documentURL to the package content

 	 * @return the unzipped package content as byte array

@@ -1724,7 +1720,7 @@
 			// if the path's file was cached to memory (second high priority)

 		} else if (mManifestEntries.containsKey(internalPath) && mMemoryFileCache.get(internalPath) != null) {

 			data = mMemoryFileCache.get(internalPath);

-			

+

 			// if the path's file was cached to disc (lowest priority)

 		}

 		// if not available, check if file exists in ZIP

@@ -1765,7 +1761,7 @@
 		}

 		return data;

 	}

-	

+

 	// encrypt data and update manifest.

 	private byte[] encryptData(byte[] data, OdfFileEntry fileEntry) {

 		byte[] encryptedData = null;

@@ -1773,14 +1769,14 @@
 			// 1.The original uncompressed, unencrypted size is

 			// contained in the manifest:size.

 			fileEntry.setSize(data.length);

-			

+

 			// 2.Compress with the "deflate" algorithm

 			Deflater compresser = new Deflater(Deflater.DEFLATED, true);

 			compresser.setInput(data);

 			compresser.finish();

 			byte[] compressedData = new byte[data.length];

 			int compressedDataLength = compresser.deflate(compressedData);

-			

+

 			// 3. The start key is generated: the byte sequence

 			// representing the password in UTF-8 is used to

 			// generate a 20-byte SHA1 digest.

@@ -1794,14 +1790,14 @@
 			md.update(compressedData, 0, (compressedDataLength > 1024 ? 1024 : compressedDataLength));

 			byte[] checksumBytes = new byte[20];

 			md.digest(checksumBytes, 0, 20);

-			

+

 			// 5. For each file, a 16-byte salt is generated by a random

 			// generator.

 			// The salt is a BASE64 encoded binary sequence.

 			SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");

 			byte[] salt = new byte[16];

 			secureRandom.nextBytes(salt);

-			

+

 			// char passChars[] = new String(passBytes, "UTF-8").toCharArray();

 			/*

 			 * char passChars[] = new char[20]; for (int i = 0; i <

@@ -1820,7 +1816,7 @@
 			 * raw = skey.getEncoded(); // algorithm-name="Blowfish CFB"

 			 * SecretKeySpec skeySpec = new SecretKeySpec(raw, "Blowfish");

 			 */

-			

+

 			byte[] dk = derivePBKDF2Key(passBytes, salt, 1024, 16);

 			SecretKeySpec key = new SecretKeySpec(dk, "Blowfish");

 			// 8.The files are encrypted: The random number

@@ -1840,7 +1836,7 @@
 			IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

 			cipher.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec);

 			encryptedData = cipher.doFinal(compressedData, 0, compressedDataLength);

-			

+

 			// 9.update file entry encryption data.

 			String checksum = new Base64Binary(checksumBytes).toString();

 			FileEntryElement fileEntryElement = fileEntry.getOdfElement();

@@ -1866,12 +1862,12 @@
 				encryptionDataElement.removeChild(startKeyGenerationElement);

 			}

 			encryptionDataElement.newStartKeyGenerationElement("SHA1").setKeySizeAttribute(20);

-			

+

 			// System.out.println("full-path=\""+ path +"\"");

 			// System.out.println("size=\""+ data.length +"\"");

 			// System.out.println("checksum=\""+ checksum +"\"");

 			// System.out.println("compressedData ="+compressedDataLength);

-			

+

 		} catch (Exception e) {

 			// throws NoSuchAlgorithmException,

 			// InvalidKeySpecException, NoSuchPaddingException,

@@ -1882,7 +1878,7 @@
 		}

 		return encryptedData;

 	}

-	

+

 	private byte[] decryptData(byte[] data, OdfFileEntry manifestEntry, EncryptionDataElement encryptionDataElement) {

 		byte[] decompressData = null;

 		try {

@@ -1908,12 +1904,12 @@
 			 */

 			byte[] dk = derivePBKDF2Key(passBytes, salt, 1024, 16);

 			SecretKeySpec key = new SecretKeySpec(dk, "Blowfish");

-			

+

 			Cipher cipher = Cipher.getInstance("Blowfish/CFB/NoPadding");

 			IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

 			cipher.init(Cipher.DECRYPT_MODE, key, ivParameterSpec);

 			byte[] decryptedData = cipher.doFinal(data);

-			

+

 			// valid checksum

 			md.reset();

 			md.update(decryptedData, 0, (decryptedData.length > 1024 ? 1024 : decryptedData.length));

@@ -1935,7 +1931,7 @@
 		}

 		return decompressData;

 	}

-	

+

 	// derive PBKDF2Key (reference http://www.ietf.org/rfc/rfc2898.txt)

 	byte[] derivePBKDF2Key(byte[] password, byte[] salt, int iterationCount, int keyLength) throws NoSuchAlgorithmException, InvalidKeyException {

 		SecretKeySpec keyspec = new SecretKeySpec(password, "HmacSHA1");

@@ -1984,7 +1980,7 @@
 		}

 		return T;

 	}

-	

+

 	// Serializes a DOM tree into a byte array.

 	// Providing the counterpart of the generic Namespace handling of

 	// OdfFileDom.

@@ -2010,12 +2006,12 @@
 		writer.write(dom, output);

 		return baos.toByteArray();

 	}

-	

+

 	/**

 	 * Get the latest version of package content as InputStream, as it would be

 	 * saved. This might not be the original version once loaded from the

 	 * package.

-	 * 

+	 *

 	 * @param internalPath

 	 *            of the desired stream.

 	 * @return Inputstream of the ODF file within the package for the given

@@ -2039,12 +2035,12 @@
 		}

 		return null;

 	}

-	

+

 	/**

 	 * Get the latest version of package content as InputStream, as it would be

 	 * saved. This might not be the original version once loaded from the

 	 * package.

-	 * 

+	 *

 	 * @param internalPath

 	 *            of the desired stream.

 	 * @param useOriginal

@@ -2069,10 +2065,10 @@
 		}

 		return stream;

 	}

-	

+

 	/**

 	 * Gets the InputStream containing whole OdfPackage.

-	 * 

+	 *

 	 * @return the ODF package as input stream

 	 * @throws java.lang.Exception

 	 *             - if the package could not be read

@@ -2080,11 +2076,11 @@
 	public InputStream getInputStream() throws Exception {

 		final PipedOutputStream os = new PipedOutputStream();

 		final PipedInputStream is = new PipedInputStream();

-		

+

 		is.connect(os);

-		

+

 		Thread thread1 = new Thread() {

-			

+

 			@Override

 			public void run() {

 				try {

@@ -2093,9 +2089,9 @@
 				}

 			}

 		};

-		

+

 		Thread thread2 = new Thread() {

-			

+

 			@Override

 			public void run() {

 				try {

@@ -2108,17 +2104,17 @@
 				}

 			}

 		};

-		

+

 		thread1.start();

 		thread2.start();

-		

+

 		return is;

 	}

-	

+

 	/**

 	 * Insert the OutputStream for into OdfPackage. An existing file will be

 	 * replaced.

-	 * 

+	 *

 	 * @param internalPath

 	 *            - relative documentURL where the DOM tree should be inserted

 	 *            as XML file

@@ -2129,11 +2125,11 @@
 	public OutputStream insertOutputStream(String internalPath) throws Exception {

 		return insertOutputStream(internalPath, null);

 	}

-	

+

 	/**

 	 * Insert the OutputStream - to be filled after method - when stream is

 	 * closed into OdfPackage. An existing file will be replaced.

-	 * 

+	 *

 	 * @param internalPath

 	 *            - relative documentURL where the DOM tree should be inserted

 	 *            as XML file

@@ -2148,9 +2144,9 @@
 		final String fPath = internalPath;

 		final OdfFileEntry fFileEntry = getFileEntry(internalPath);

 		final String fMediaType = mediaType;

-		

+

 		ByteArrayOutputStream baos = new ByteArrayOutputStream() {

-			

+

 			@Override

 			public void close() {

 				try {

@@ -2168,10 +2164,10 @@
 		};

 		return baos;

 	}

-	

+

 	/**

 	 * Removes a single file from the package.

-	 * 

+	 *

 	 * @param internalPath

 	 *            of the file relative to the package root

 	 */

@@ -2186,7 +2182,7 @@
 			manifestEle.getParentNode().removeChild(manifestEle);

 		}

 	}

-	

+

 	/**

 	 * Encoded XML Attributes

 	 */

@@ -2195,11 +2191,11 @@
 		encodedValue = APOSTROPHE_PATTERN.matcher(encodedValue).replaceAll(ENCODED_APOSTROPHE);

 		return encodedValue;

 	}

-	

+

 	/**

 	 * Get EntityResolver to be used in XML Parsers which can resolve content

 	 * inside the OdfPackage

-	 * 

+	 *

 	 * @return a SAX EntityResolver

 	 */

 	public EntityResolver getEntityResolver() {

@@ -2208,11 +2204,11 @@
 		}

 		return mResolver;

 	}

-	

+

 	/**

 	 * Get URIResolver to be used in XSL Transformations which can resolve

 	 * content inside the OdfPackage

-	 * 

+	 *

 	 * @return a TraX Resolver

 	 */

 	public URIResolver getURIResolver() {

@@ -2221,13 +2217,13 @@
 		}

 		return mResolver;

 	}

-	

+

 	private static String getBaseURLFromFile(File file) throws Exception {

 		String baseURL = Util.toExternalForm(file.getCanonicalFile().toURI());

 		baseURL = BACK_SLASH_PATTERN.matcher(baseURL).replaceAll(SLASH);

 		return baseURL;

 	}

-	

+

 	/**

 	 * Ensures that the given file path is not null nor empty and not an

 	 * external reference

@@ -2236,7 +2232,7 @@
 	 * <li>Any substring "/../", "/./" or "//" will be removed</li>

 	 * <li>A prefix "./" and "../" will be removed</li>

 	 * </ol>

-	 * 

+	 *

 	 * @throws IllegalArgumentException

 	 *             If the path is NULL, empty or an external path (e.g. starting

 	 *             with "../" is given). None relative URLs will NOT throw an

@@ -2252,7 +2248,7 @@
 			return normalizePath(internalPath);

 		}

 	}

-	

+

 	/**

 	 * Ensures the given directory path is not null nor an external reference to

 	 * resources outside the package. An empty path and slash "/" are both

@@ -2260,7 +2256,7 @@
 	 * "/" as root, the empty path aligns more adequate with the file system

 	 * concept. To ensure the given directory path within the package can be

 	 * used as a key (is unique for the Package) the path will be normalized.

-	 * 

+	 *

 	 * @see #normalizeFilePath(String) In addition to the file path

 	 *      normalization a trailing slash will be used for directories.

 	 */

@@ -2274,7 +2270,7 @@
 		}

 		return directoryPath;

 	}

-	

+

 	/** Normalizes both directory and file path */

 	static String normalizePath(String path) {

 		if (path == null) {

@@ -2302,7 +2298,7 @@
 		}

 		return path;

 	}

-	

+

 	/** Normalizes both directory and file path */

 	private static boolean mightBeExternalReference(String internalPath) {

 		boolean isExternalReference = false;

@@ -2317,7 +2313,7 @@
 		}

 		return isExternalReference;

 	}

-	

+

 	/**

 	 * Resolving the directory replacements (ie. "/../" and "/./") with a slash

 	 * "/"

@@ -2369,11 +2365,11 @@
 			return out.toString();

 		}

 	}

-	

+

 	/**

 	 * Checks if the given reference is a reference, which points outside the

 	 * ODF package

-	 * 

+	 *

 	 * @param internalPath

 	 *            the file reference to be checked

 	 * @return true if the reference is an package external reference

@@ -2385,7 +2381,7 @@
 			return mightBeExternalReference(normalizePath(internalPath));

 		}

 	}

-	

+

 	/**

 	 * Allow an application to register an error event handler.

 	 * <p>

@@ -2399,7 +2395,7 @@
 	 * Applications may register a new or different handler in the middle of a

 	 * parse, and the ODFDOM will begin using the new handler immediately.

 	 * </p>

-	 * 

+	 *

 	 * @param handler

 	 *            The error handler.

 	 * @see #getErrorHandler

@@ -2407,10 +2403,10 @@
 	public void setErrorHandler(ErrorHandler handler) {

 		mErrorHandler = handler;

 	}

-	

+

 	/**

 	 * Return the current error handler used for ODF validation.

-	 * 

+	 *

 	 * @return The current error handler, or null if none has been registered

 	 *         and validation is disabled.

 	 * @see #setErrorHandler

@@ -2418,7 +2414,7 @@
 	public ErrorHandler getErrorHandler() {

 		return mErrorHandler;

 	}

-	

+

 	void logValidationWarning(ValidationConstraint constraint, String baseURI, Object... o) throws SAXException {

 		// try{

 		if (mErrorHandler == null) {

@@ -2444,7 +2440,7 @@
 		// ex);

 		// }

 	}

-	

+

 	void logValidationError(ValidationConstraint constraint, String baseURI, Object... o) throws SAXException {

 		// try{

 		if (mErrorHandler == null) {

@@ -2470,7 +2466,7 @@
 		// ex);

 		// }

 	}

-	

+

 	/**

 	 * @param odfVersion

 	 *            parsed from the manifest

@@ -2478,7 +2474,7 @@
 	void setManifestVersion(String odfVersion) {

 		mManifestVersion = odfVersion;

 	}

-	

+

 	/**

 	 * @return the ODF version found in the manifest. Meant to be used to reuse

 	 *         when the manifest is recreated