You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@poi.apache.org by ye...@apache.org on 2009/01/29 13:44:35 UTC

svn commit: r738842 [4/7] - in /poi/trunk: ./ legal/ maven/ src/documentation/content/xdocs/ src/documentation/content/xdocs/oxml4j/ src/documentation/content/xdocs/spreadsheet/ src/examples/src/org/apache/poi/xssf/eventusermodel/examples/ src/ooxml/ja...

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,464 @@
+/* ====================================================================
+   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.openxml4j.opc;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.log4j.Logger;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.internal.ContentTypeManager;
+import org.apache.poi.openxml4j.opc.internal.FileHelper;
+import org.apache.poi.openxml4j.opc.internal.MemoryPackagePart;
+import org.apache.poi.openxml4j.opc.internal.PartMarshaller;
+import org.apache.poi.openxml4j.opc.internal.ZipContentTypeManager;
+import org.apache.poi.openxml4j.opc.internal.ZipHelper;
+import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPackagePropertiesMarshaller;
+import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
+import org.apache.poi.openxml4j.util.ZipEntrySource;
+import org.apache.poi.openxml4j.util.ZipFileZipEntrySource;
+import org.apache.poi.openxml4j.util.ZipInputStreamZipEntrySource;
+
+/**
+ * Physical zip package.
+ * 
+ * @author Julien Chable
+ * @version 0.2
+ */
+public final class ZipPackage extends Package {
+
+	private static Logger logger = Logger.getLogger("org.openxml4j");
+
+	/**
+	 * Zip archive, as either a file on disk,
+	 *  or a stream 
+	 */
+	private final ZipEntrySource zipArchive;
+
+	/**
+	 * Constructor. Creates a new ZipPackage.
+	 */
+	public ZipPackage() {
+		super(defaultPackageAccess);
+		this.zipArchive = null;
+	}
+
+	/**
+	 * Constructor. <b>Operation not supported.</b>
+	 * 
+	 * @param in
+	 *            Zip input stream to load.
+	 * @param access
+	 * @throws IllegalArgumentException
+	 *             If the specified input stream not an instance of
+	 *             ZipInputStream.
+	 */
+	ZipPackage(InputStream in, PackageAccess access) throws IOException {
+		super(access);
+		this.zipArchive = new ZipInputStreamZipEntrySource(
+				new ZipInputStream(in)
+		);
+	}
+
+	/**
+	 * Constructor. Opens a Zip based Open XML document.
+	 * 
+	 * @param path
+	 *            The path of the file to open or create.
+	 * @param access
+	 *            The package access mode.
+	 * @throws InvalidFormatException
+	 *             If the content type part parsing encounters an error.
+	 */
+	ZipPackage(String path, PackageAccess access) throws InvalidFormatException {
+		super(access);
+		
+		ZipFile zipFile = ZipHelper.openZipFile(path);
+		if (zipFile == null)
+			throw new InvalidOperationException(
+					"Can't open the specified file: '" + path + "'");
+		this.zipArchive = new ZipFileZipEntrySource(zipFile); 
+	}
+	
+	/**
+	 * Retrieves the parts from this package. We assume that the package has not
+	 * been yet inspect to retrieve all the parts, this method will open the
+	 * archive and look for all parts contain inside it. If the package part
+	 * list is not empty, it will be emptied.
+	 * 
+	 * @return All parts contain in this package.
+	 * @throws InvalidFormatException
+	 *             Throws if the package is not valid.
+	 */
+	@Override
+	protected PackagePart[] getPartsImpl() throws InvalidFormatException {
+		if (this.partList == null) {
+			// The package has just been created, we create an empty part
+			// list.
+			this.partList = new PackagePartCollection();
+		}
+
+		if (this.zipArchive == null) {
+			return this.partList.values().toArray(
+					new PackagePart[this.partList.values().size()]);
+		} else {
+			// First we need to parse the content type part
+			Enumeration<? extends ZipEntry> entries = this.zipArchive.getEntries();
+			while (entries.hasMoreElements()) {
+				ZipEntry entry = entries.nextElement();
+				if (entry.getName().equals(
+						ContentTypeManager.CONTENT_TYPES_PART_NAME)) {
+					try {
+						this.contentTypeManager = new ZipContentTypeManager(
+								getZipArchive().getInputStream(entry), this);
+					} catch (IOException e) {
+						throw new InvalidFormatException(e.getMessage());
+					}
+					break;
+				}
+			}
+
+			// At this point, we should have loaded the content type part
+			if (this.contentTypeManager == null) {
+				throw new InvalidFormatException(
+						"Package should contain a content type part [M1.13]");
+			}
+			
+			// Now create all the relationships
+			// (Need to create relationships before other
+			//  parts, otherwise we might create a part before
+			//  its relationship exists, and then it won't tie up)
+			entries = this.zipArchive.getEntries();
+			while (entries.hasMoreElements()) {
+				ZipEntry entry = (ZipEntry) entries.nextElement();
+				PackagePartName partName = buildPartName(entry);
+				if(partName == null) continue;
+				
+				// Only proceed for Relationships at this stage
+				String contentType = contentTypeManager.getContentType(partName);
+				if (contentType != null && contentType.equals(ContentTypes.RELATIONSHIPS_PART)) {
+					try {
+						partList.put(partName, new ZipPackagePart(this, entry,
+							partName, contentType));
+					} catch (InvalidOperationException e) {
+						throw new InvalidFormatException(e.getMessage());
+					}
+				}
+			}
+
+			// Then we can go through all the other parts
+			entries = this.zipArchive.getEntries();
+			while (entries.hasMoreElements()) {
+				ZipEntry entry = (ZipEntry) entries.nextElement();
+				PackagePartName partName = buildPartName(entry);
+				if(partName == null) continue;
+
+				String contentType = contentTypeManager
+						.getContentType(partName);
+				if (contentType != null && contentType.equals(ContentTypes.RELATIONSHIPS_PART)) {
+					// Already handled
+				}
+				else if (contentType != null) {
+					try {
+						partList.put(partName, new ZipPackagePart(this, entry,
+								partName, contentType));
+					} catch (InvalidOperationException e) {
+						throw new InvalidFormatException(e.getMessage());
+					}
+				} else {
+					throw new InvalidFormatException(
+							"The part "
+									+ partName.getURI().getPath()
+									+ " does not have any content type ! Rule: Package require content types when retrieving a part from a package. [M.1.14]");
+				}
+			}
+			
+			return (ZipPackagePart[]) partList.values().toArray(
+					new ZipPackagePart[partList.size()]);
+		}
+	}
+	
+	/**
+	 * Builds a PackagePartName for the given ZipEntry,
+	 *  or null if it's the content types / invalid part
+	 */
+	private PackagePartName buildPartName(ZipEntry entry) {
+		try {
+			// We get an error when we parse [Content_Types].xml
+			// because it's not a valid URI.
+			if (entry.getName().equals(
+					ContentTypeManager.CONTENT_TYPES_PART_NAME)) {
+				return null;
+			} else {
+				return PackagingURIHelper.createPartName(ZipHelper
+						.getOPCNameFromZipItemName(entry.getName()));
+			}
+		} catch (Exception e) {
+			// We assume we can continue, even in degraded mode ...
+			logger.warn("Entry "
+							+ entry.getName()
+							+ " is not valid, so this part won't be add to the package.");
+			return null;
+		}
+	}
+
+	/**
+	 * Create a new MemoryPackagePart from the specified URI and content type
+	 * 
+	 * 
+	 * aram partName The part URI.
+	 * 
+	 * @param contentType
+	 *            The part content type.
+	 * @return The newly created zip package part, else <b>null</b>.
+	 */
+	@Override
+	protected PackagePart createPartImpl(PackagePartName partName,
+			String contentType, boolean loadRelationships) {
+		if (contentType == null)
+			throw new IllegalArgumentException("contentType");
+
+		if (partName == null)
+			throw new IllegalArgumentException("partName");
+
+		try {
+			return new MemoryPackagePart(this, partName, contentType,
+					loadRelationships);
+		} catch (InvalidFormatException e) {
+			System.err.println(e);
+			return null;
+		}
+	}
+
+	/**
+	 * Delete a part from the package
+	 * 
+	 * @throws IllegalArgumentException
+	 *             Throws if the part URI is nulll or invalid.
+	 */
+	@Override
+	protected void removePartImpl(PackagePartName partName) {
+		if (partName == null)
+			throw new IllegalArgumentException("partUri");
+	}
+
+	/**
+	 * Flush the package. Do nothing.
+	 */
+	@Override
+	protected void flushImpl() {
+		// Do nothing
+	}
+
+	/**
+	 * Close and save the package.
+	 * 
+	 * @see #close()
+	 */
+	@Override
+	protected void closeImpl() throws IOException {
+		// Flush the package
+		flush();
+
+		// Save the content
+		if (this.originalPackagePath != null
+				&& !"".equals(this.originalPackagePath)) {
+			File targetFile = new File(this.originalPackagePath);
+			if (targetFile.exists()) {
+				// Case of a package previously open
+
+				File tempFile = File.createTempFile(
+						generateTempFileName(FileHelper
+								.getDirectory(targetFile)), ".tmp");
+
+				// Save the final package to a temporary file
+				try {
+					save(tempFile);
+					this.zipArchive.close(); // Close the zip archive to be
+					// able to delete it
+					FileHelper.copyFile(tempFile, targetFile);
+				} finally {
+					// Either the save operation succeed or not, we delete the
+					// temporary file
+					if (!tempFile.delete()) {
+						logger
+								.warn("The temporary file: '"
+										+ targetFile.getAbsolutePath()
+										+ "' cannot be deleted ! Make sure that no other application use it.");
+					}
+				}
+			} else {
+				throw new InvalidOperationException(
+						"Can't close a package not previously open with the open() method !");
+			}
+		}
+	}
+
+	/**
+	 * Create a unique identifier to be use as a temp file name.
+	 * 
+	 * @return A unique identifier use to be use as a temp file name.
+	 */
+	private synchronized String generateTempFileName(File directory) {
+		File tmpFilename;
+		do {
+			tmpFilename = new File(directory.getAbsoluteFile() + File.separator
+					+ "OpenXML4J" + System.nanoTime());
+		} while (tmpFilename.exists());
+		return FileHelper.getFilename(tmpFilename.getAbsoluteFile());
+	}
+
+	/**
+	 * Close the package without saving the document. Discard all the changes
+	 * made to this package.
+	 */
+	@Override
+	protected void revertImpl() {
+		try {
+			if (this.zipArchive != null)
+				this.zipArchive.close();
+		} catch (IOException e) {
+			// Do nothing, user dont have to know
+		}
+	}
+
+	/**
+	 * Implement the getPart() method to retrieve a part from its URI in the
+	 * current package
+	 * 
+	 * 
+	 * @see #getPart(URI)
+	 */
+	@Override
+	protected PackagePart getPartImpl(PackagePartName partName) {
+		if (partList.containsKey(partName)) {
+			return partList.get(partName);
+		}
+		return null;
+	}
+
+	/**
+	 * Save this package into the specified stream
+	 * 
+	 * 
+	 * @param outputStream
+	 *            The stream use to save this package.
+	 * 
+	 * @see #save(OutputStream)
+	 * @see #saveInZip(ZipOutputStream)
+	 */
+	@Override
+	public void saveImpl(OutputStream outputStream) {
+		// Check that the document was open in write mode
+		throwExceptionIfReadOnly();
+		ZipOutputStream zos = null;
+
+		try {
+			if (!(outputStream instanceof ZipOutputStream))
+				zos = new ZipOutputStream(outputStream);
+			else
+				zos = (ZipOutputStream) outputStream;
+
+			// If the core properties part does not exist in the part list,
+			// we save it as well
+			if (this.getPartsByRelationshipType(
+					PackageRelationshipTypes.CORE_PROPERTIES).size() == 0) {
+				logger.debug("Save core properties part");
+
+				// We have to save the core properties part ...
+				new ZipPackagePropertiesMarshaller().marshall(
+						this.packageProperties, zos);
+				// ... and to add its relationship ...
+				this.relationships.addRelationship(this.packageProperties
+						.getPartName().getURI(), TargetMode.INTERNAL,
+						PackageRelationshipTypes.CORE_PROPERTIES, null);
+				// ... and the content if it has not been added yet.
+				if (!this.contentTypeManager
+						.isContentTypeRegister(ContentTypes.CORE_PROPERTIES_PART)) {
+					this.contentTypeManager.addContentType(
+							this.packageProperties.getPartName(),
+							ContentTypes.CORE_PROPERTIES_PART);
+				}
+			}
+
+			// Save package relationships part.
+			logger.debug("Save package relationships");
+			ZipPartMarshaller.marshallRelationshipPart(this.getRelationships(),
+					PackagingURIHelper.PACKAGE_RELATIONSHIPS_ROOT_PART_NAME,
+					zos);
+
+			// Save content type part.
+			logger.debug("Save content types part");
+			this.contentTypeManager.save(zos);
+
+			// Save parts.
+			for (PackagePart part : getParts()) {
+				// If the part is a relationship part, we don't save it, it's
+				// the source part that will do the job.
+				if (part.isRelationshipPart())
+					continue;
+
+				logger.debug("Save part '"
+						+ ZipHelper.getZipItemNameFromOPCName(part
+								.getPartName().getName()) + "'");
+				PartMarshaller marshaller = partMarshallers
+						.get(part.contentType);
+				if (marshaller != null) {
+					if (!marshaller.marshall(part, zos)) {
+						throw new OpenXML4JException(
+								"The part "
+										+ part.getPartName().getURI()
+										+ " fail to be saved in the stream with marshaller "
+										+ marshaller);
+					}
+				} else {
+					if (!defaultPartMarshaller.marshall(part, zos))
+						throw new OpenXML4JException(
+								"The part "
+										+ part.getPartName().getURI()
+										+ " fail to be saved in the stream with marshaller "
+										+ defaultPartMarshaller);
+				}
+			}
+			zos.close();
+		} catch (Exception e) {
+			logger
+					.error("Fail to save: an error occurs while saving the package : "
+							+ e.getMessage());
+		}
+	}
+
+	/**
+	 * Get the zip archive
+	 * 
+	 * @return The zip archive.
+	 */
+	public ZipEntrySource getZipArchive() {
+		return zipArchive;
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackage.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,135 @@
+/* ====================================================================
+   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.openxml4j.opc;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
+
+/**
+ * Zip implementation of a PackagePart.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ * @see PackagePart
+ */
+public class ZipPackagePart extends PackagePart {
+
+	/**
+	 * The zip entry corresponding to this part.
+	 */
+	private ZipEntry zipEntry;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param container
+	 *            The container package.
+	 * @param partName
+	 *            Part name.
+	 * @param contentType
+	 *            Content type.
+	 * @throws InvalidFormatException
+	 *             Throws if the content of this part invalid.
+	 */
+	public ZipPackagePart(Package container, PackagePartName partName,
+			String contentType) throws InvalidFormatException {
+		super(container, partName, contentType);
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param container
+	 *            The container package.
+	 * @param zipEntry
+	 *            The zip entry corresponding to this part.
+	 * @param partName
+	 *            The part name.
+	 * @param contentType
+	 *            Content type.
+	 * @throws InvalidFormatException
+	 *             Throws if the content of this part is invalid.
+	 */
+	public ZipPackagePart(Package container, ZipEntry zipEntry,
+			PackagePartName partName, String contentType)
+			throws InvalidFormatException {
+		super(container, partName, contentType);
+		this.zipEntry = zipEntry;
+	}
+
+	/**
+	 * Get the zip entry of this part.
+	 * 
+	 * @return The zip entry in the zip structure coresponding to this part.
+	 */
+	public ZipEntry getZipArchive() {
+		return zipEntry;
+	}
+
+	/**
+	 * Implementation of the getInputStream() which return the inputStream of
+	 * this part zip entry.
+	 * 
+	 * @return Input stream of this part zip entry.
+	 */
+	@Override
+	protected InputStream getInputStreamImpl() throws IOException {
+		// We use the getInputStream() method from java.util.zip.ZipFile
+		// class which return an InputStream to this part zip entry.
+		return ((ZipPackage) container).getZipArchive()
+				.getInputStream(zipEntry);
+	}
+
+	/**
+	 * Implementation of the getOutputStream(). Return <b>null</b>. Normally
+	 * will never be called since the MemoryPackage is use instead.
+	 * 
+	 * @return <b>null</b>
+	 */
+	@Override
+	protected OutputStream getOutputStreamImpl() {
+		return null;
+	}
+
+	@Override
+	public boolean save(OutputStream os) throws OpenXML4JException {
+		return new ZipPartMarshaller().marshall(this, os);
+	}
+
+	@Override
+	public boolean load(InputStream ios) throws InvalidFormatException {
+		throw new InvalidOperationException("Method not implemented !");
+	}
+
+	@Override
+	public void close() {
+		throw new InvalidOperationException("Method not implemented !");
+	}
+
+	@Override
+	public void flush() {
+		throw new InvalidOperationException("Method not implemented !");
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/ZipPackagePart.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentType.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentType.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentType.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentType.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,224 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Hashtable;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+
+/**
+ * Represents a immutable MIME ContentType value (RFC 2616 �3.7)
+ * 
+ * media-type = type "/" subtype *( ";" parameter ) type = token<br>
+ * subtype = token<br>
+ * 
+ * Rule M1.13 : Package implementers shall only create and only recognize parts
+ * with a content type; format designers shall specify a content type for each
+ * part included in the format. Content types for package parts shall fit the
+ * definition and syntax for media types as specified in RFC 2616,��3.7.
+ * 
+ * Rule M1.14: Content types shall not use linear white space either between the
+ * type and subtype or between an attribute and its value. Content types also
+ * shall not have leading or trailing white spaces. Package implementers shall
+ * create only such content types and shall require such content types when
+ * retrieving a part from a package; format designers shall specify only such
+ * content types for inclusion in the format.
+ * 
+ * @author Julien Chable
+ * @version 0.1
+ * 
+ * @see http://www.ietf.org/rfc/rfc2045.txt
+ * @see http://www.ietf.org/rfc/rfc2616.txt
+ */
+public final class ContentType {
+
+	/**
+	 * Type in Type/Subtype.
+	 */
+	private String type;
+
+	/**
+	 * Subtype
+	 */
+	private String subType;
+
+	/**
+	 * Parameters
+	 */
+	private Hashtable<String, String> parameters;
+
+	/**
+	 * Media type compiled pattern for parameters.
+	 */
+	private final static Pattern patternMediaType;
+
+	static {
+		/*
+		 * token = 1*<any CHAR except CTLs or separators>
+		 * 
+		 * separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" |
+		 * <"> | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT
+		 * 
+		 * CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)>
+		 * 
+		 * CHAR = <any US-ASCII character (octets 0 - 127)>
+		 */
+		String token = "[\\x21-\\x7E&&[^\\(\\)<>@,;:\\\\/\"\\[\\]\\?={}\\x20\\x09]]";
+
+		/*
+		 * parameter = attribute "=" value
+		 * 
+		 * attribute = token
+		 * 
+		 * value = token | quoted-string
+		 */
+		// Keep for future use with parameter:
+		// String parameter = "(" + token + "+)=(\"?" + token + "+\"?)";
+		/*
+		 * Pattern for media type.
+		 * 
+		 * Don't allow comment, rule M1.15: The package implementer shall
+		 * require a content type that does not include comments and the format
+		 * designer shall specify such a content type.
+		 * 
+		 * comment = "(" *( ctext | quoted-pair | comment ) ")"
+		 * 
+		 * ctext = <any TEXT excluding "(" and ")">
+		 * 
+		 * TEXT = <any OCTET except CTLs, but including LWS>
+		 * 
+		 * LWS = [CRLF] 1*( SP | HT )
+		 * 
+		 * CR = <US-ASCII CR, carriage return (13)>
+		 * 
+		 * LF = <US-ASCII LF, linefeed (10)>
+		 * 
+		 * SP = <US-ASCII SP, space (32)>
+		 * 
+		 * HT = <US-ASCII HT, horizontal-tab (9)>
+		 * 
+		 * quoted-pair = "\" CHAR
+		 */
+
+		// Keep for future use with parameter:
+		// patternMediaType = Pattern.compile("^(" + token + "+)/(" + token
+		// + "+)(;" + parameter + ")*$");
+		patternMediaType = Pattern.compile("^(" + token + "+)/(" + token
+				+ "+)$");
+	}
+
+	/**
+	 * Constructor. Check the input with the RFC 2616 grammar.
+	 * 
+	 * @param contentType
+	 *            The content type to store.
+	 * @throws InvalidFormatException
+	 *             If the specified content type is not valid with RFC 2616.
+	 */
+	public ContentType(String contentType) throws InvalidFormatException {
+		// Conversion en US-ASCII
+		String contentTypeASCII = null;
+		try {
+			contentTypeASCII = new String(contentType.getBytes(), "US-ASCII");
+		} catch (UnsupportedEncodingException e) {
+			throw new InvalidFormatException(
+					"The specified content type is not an ASCII value.");
+		}
+
+		Matcher mMediaType = patternMediaType.matcher(contentTypeASCII);
+		if (!mMediaType.matches())
+			throw new InvalidFormatException(
+					"The specified content type '"
+							+ contentType
+							+ "' is not compliant with RFC 2616: malformed content type.");
+
+		// Type/subtype
+		if (mMediaType.groupCount() >= 2) {
+			this.type = mMediaType.group(1);
+			this.subType = mMediaType.group(2);
+			// Parameters
+			this.parameters = new Hashtable<String, String>(1);
+			for (int i = 4; i <= mMediaType.groupCount()
+					&& (mMediaType.group(i) != null); i += 2) {
+				this.parameters.put(mMediaType.group(i), mMediaType
+						.group(i + 1));
+			}
+		}
+	}
+
+	@Override
+	public final String toString() {
+		StringBuffer retVal = new StringBuffer();
+		retVal.append(this.getType());
+		retVal.append("/");
+		retVal.append(this.getSubType());
+		// Keep for future implementation if needed
+		// for (String key : parameters.keySet()) {
+		// retVal.append(";");
+		// retVal.append(key);
+		// retVal.append("=");
+		// retVal.append(parameters.get(key));
+		// }
+		return retVal.toString();
+	}
+
+	@Override
+	public boolean equals(Object obj) {
+		return (!(obj instanceof ContentType))
+				|| (this.toString().equalsIgnoreCase(obj.toString()));
+	}
+
+	@Override
+	public int hashCode() {
+		return this.toString().hashCode();
+	}
+
+	/* Getters */
+
+	/**
+	 * Get the subtype.
+	 * 
+	 * @return The subtype of this content type.
+	 */
+	public String getSubType() {
+		return this.subType;
+	}
+
+	/**
+	 * Get the type.
+	 * 
+	 * @return The type of this content type.
+	 */
+	public String getType() {
+		return this.type;
+	}
+
+	/**
+	 * Gets the value associated to the specified key.
+	 * 
+	 * @param key
+	 *            The key of the key/value pair.
+	 * @return The value associated to the specified key.
+	 */
+	public String getParameters(String key) {
+		return parameters.get(key);
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentType.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,498 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeMap;
+import java.util.Map.Entry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.log4j.Logger;
+import org.dom4j.Document;
+import org.dom4j.DocumentException;
+import org.dom4j.DocumentHelper;
+import org.dom4j.Element;
+import org.dom4j.Namespace;
+import org.dom4j.QName;
+import org.dom4j.io.SAXReader;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JRuntimeException;
+import org.apache.poi.openxml4j.opc.Package;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackagingURIHelper;
+
+/**
+ * Manage package content types ([Content_Types].xml part).
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ */
+public abstract class ContentTypeManager {
+
+	protected static Logger logger = Logger.getLogger("org.openxml4j");
+
+	/**
+	 * Reference to the package using this content type manager.
+	 */
+	protected Package container;
+
+	/**
+	 * Content type part name.
+	 */
+	public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
+
+	/**
+	 * Content type namespace
+	 */
+	public static final String TYPES_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/content-types";
+
+	/* Xml elements in content type part */
+
+	private static final String TYPES_TAG_NAME = "Types";
+
+	private static final String DEFAULT_TAG_NAME = "Default";
+
+	private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
+
+	private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
+
+	private static final String OVERRIDE_TAG_NAME = "Override";
+
+	private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
+
+	/**
+	 * Default content type tree. <Extension, ContentType>
+	 */
+	private TreeMap<String, String> defaultContentType;
+
+	/**
+	 * Override content type tree.
+	 */
+	private TreeMap<PackagePartName, String> overrideContentType;
+
+	/**
+	 * Constructor. Parses the content of the specified input stream.
+	 * 
+	 * @param archive
+	 *            If different of <i>null</i> then the content types part is
+	 *            retrieve and parse.
+	 * @throws InvalidFormatException
+	 *             If the content types part content is not valid.
+	 */
+	public ContentTypeManager(InputStream in, Package pkg)
+			throws InvalidFormatException {
+		this.container = pkg;
+		this.defaultContentType = new TreeMap<String, String>();
+		if (in != null) {
+			try {
+				parseContentTypesFile(in);
+			} catch (InvalidFormatException e) {
+				throw new InvalidFormatException(
+						"Can't read content types part !");
+			}
+		}
+	}
+
+	/**
+	 * Build association extention-> content type (will be stored in
+	 * [Content_Types].xml) for example ContentType="image/png" Extension="png"
+	 * 
+	 * [M2.8]: When adding a new part to a package, the package implementer
+	 * shall ensure that a content type for that part is specified in the
+	 * Content Types stream; the package implementer shall perform the steps
+	 * described in��9.1.2.3:
+	 * 
+	 * 1. Get the extension from the part name by taking the substring to the
+	 * right of the rightmost occurrence of the dot character (.) from the
+	 * rightmost segment.
+	 * 
+	 * 2. If a part name has no extension, a corresponding Override element
+	 * shall be added to the Content Types stream.
+	 * 
+	 * 3. Compare the resulting extension with the values specified for the
+	 * Extension attributes of the Default elements in the Content Types stream.
+	 * The comparison shall be case-insensitive ASCII.
+	 * 
+	 * 4. If there is a Default element with a matching Extension attribute,
+	 * then the content type of the new part shall be compared with the value of
+	 * the ContentType attribute. The comparison might be case-sensitive and
+	 * include every character regardless of the role it plays in the
+	 * content-type grammar of RFC 2616, or it might follow the grammar of RFC
+	 * 2616.
+	 * 
+	 * a. If the content types match, no further action is required.
+	 * 
+	 * b. If the content types do not match, a new Override element shall be
+	 * added to the Content Types stream. .
+	 * 
+	 * 5. If there is no Default element with a matching Extension attribute, a
+	 * new Default element or Override element shall be added to the Content
+	 * Types stream.
+	 * 
+	 * 
+	 * @param partUri
+	 *            the uri that will be stored
+	 * @return <b>false</b> if an error occured.
+	 */
+	public void addContentType(PackagePartName partName, String contentType) {
+		boolean defaultCTExists = false;
+		String extension = partName.getExtension().toLowerCase();
+		if ((extension.length() == 0)
+				|| (this.defaultContentType.containsKey(extension) && !(defaultCTExists = this.defaultContentType
+						.containsValue(contentType))))
+			this.addOverrideContentType(partName, contentType);
+		else if (!defaultCTExists)
+			this.addDefaultContentType(extension, contentType);
+	}
+
+	/**
+	 * Add an override content type for a specific part.
+	 * 
+	 * @param partName
+	 *            Name of the part.
+	 * @param contentType
+	 *            Content type of the part.
+	 */
+	private void addOverrideContentType(PackagePartName partName,
+			String contentType) {
+		if (overrideContentType == null)
+			overrideContentType = new TreeMap<PackagePartName, String>();
+		overrideContentType.put(partName, contentType);
+	}
+
+	/**
+	 * Add a content type associated with the specified extension.
+	 * 
+	 * @param extension
+	 *            The part name extension to bind to a content type.
+	 * @param contentType
+	 *            The content type associated with the specified extension.
+	 */
+	private void addDefaultContentType(String extension, String contentType) {
+		// Remark : Originally the latest parameter was :
+		// contentType.toLowerCase(). Change due to a request ID 1996748.
+		defaultContentType.put(extension.toLowerCase(), contentType);
+	}
+
+	/**
+	 * Delete a content type based on the specified part name. If the specified
+	 * part name is register with an override content type, then this content
+	 * type is remove, else the content type is remove in the default content
+	 * type list if it exists and if no part is associated with it yet.
+	 * 
+	 * Check rule M2.4: The package implementer shall require that the Content
+	 * Types stream contain one of the following for every part in the package:
+	 * One matching Default element One matching Override element Both a
+	 * matching Default element and a matching Override element, in which case
+	 * the Override element takes precedence.
+	 * 
+	 * @param partUri
+	 *            The part URI associated with the override content type to
+	 *            delete.
+	 * @exception InvalidOperationException
+	 *                Throws if
+	 */
+	public void removeContentType(PackagePartName partName)
+			throws InvalidOperationException {
+		if (partName == null)
+			throw new IllegalArgumentException("partName");
+
+		/* Override content type */
+		if (this.overrideContentType != null
+				&& (this.overrideContentType.get(partName) != null)) {
+			// Remove the override definition for the specified part.
+			this.overrideContentType.remove(partName);
+			return;
+		}
+
+		/* Default content type */
+		String extensionToDelete = partName.getExtension();
+		boolean deleteDefaultContentTypeFlag = true;
+		if (this.container != null) {
+			try {
+				for (PackagePart part : this.container.getParts()) {
+					if (!part.getPartName().equals(partName)
+							&& part.getPartName().getExtension()
+									.equalsIgnoreCase(extensionToDelete)) {
+						deleteDefaultContentTypeFlag = false;
+						break;
+					}
+				}
+			} catch (InvalidFormatException e) {
+				throw new InvalidOperationException(e.getMessage());
+			}
+		}
+
+		// Remove the default content type, no other part use this content type.
+		if (deleteDefaultContentTypeFlag) {
+			this.defaultContentType.remove(extensionToDelete);
+		}
+
+		/*
+		 * Check rule 2.4: The package implementer shall require that the
+		 * Content Types stream contain one of the following for every part in
+		 * the package: One matching Default element One matching Override
+		 * element Both a matching Default element and a matching Override
+		 * element, in which case the Override element takes precedence.
+		 */
+		if (this.container != null) {
+			try {
+				for (PackagePart part : this.container.getParts()) {
+					if (!part.getPartName().equals(partName)
+							&& this.getContentType(part.getPartName()) == null)
+						throw new InvalidOperationException(
+								"Rule M2.4 is not respected: Nor a default element or override element is associated with the part: "
+										+ part.getPartName().getName());
+				}
+			} catch (InvalidFormatException e) {
+				throw new InvalidOperationException(e.getMessage());
+			}
+		}
+	}
+
+	/**
+	 * Check if the specified content type is already register.
+	 * 
+	 * @param contentType
+	 *            The content type to check.
+	 * @return <code>true</code> if the specified content type is already
+	 *         register, then <code>false</code>.
+	 */
+	public boolean isContentTypeRegister(String contentType) {
+		if (contentType == null)
+			throw new IllegalArgumentException("contentType");
+
+		return (this.defaultContentType.values().contains(contentType) || (this.overrideContentType != null && this.overrideContentType
+				.values().contains(contentType)));
+	}
+
+	/**
+	 * Get the content type for the specified part, if any.
+	 * 
+	 * Rule [M2.9]: To get the content type of a part, the package implementer
+	 * shall perform the steps described in��9.1.2.4:
+	 * 
+	 * 1. Compare the part name with the values specified for the PartName
+	 * attribute of the Override elements. The comparison shall be
+	 * case-insensitive ASCII.
+	 * 
+	 * 2. If there is an Override element with a matching PartName attribute,
+	 * return the value of its ContentType attribute. No further action is
+	 * required.
+	 * 
+	 * 3. If there is no Override element with a matching PartName attribute,
+	 * then a. Get the extension from the part name by taking the substring to
+	 * the right of the rightmost occurrence of the dot character (.) from the
+	 * rightmost segment. b. Check the Default elements of the Content Types
+	 * stream, comparing the extension with the value of the Extension
+	 * attribute. The comparison shall be case-insensitive ASCII.
+	 * 
+	 * 4. If there is a Default element with a matching Extension attribute,
+	 * return the value of its ContentType attribute. No further action is
+	 * required.
+	 * 
+	 * 5. If neither Override nor Default elements with matching attributes are
+	 * found for the specified part name, the implementation shall not map this
+	 * part name to a part.
+	 * 
+	 * @param partUri
+	 *            The URI part to check.
+	 * @return The content type associated with the URI (in case of an override
+	 *         content type) or the extension (in case of default content type),
+	 *         else <code>null</code>.
+	 * 
+	 * @exception OpenXML4JRuntimeException
+	 *                Throws if the content type manager is not able to find the
+	 *                content from an existing part.
+	 */
+	public String getContentType(PackagePartName partName) {
+		if (partName == null)
+			throw new IllegalArgumentException("partName");
+
+		if ((this.overrideContentType != null)
+				&& this.overrideContentType.containsKey(partName))
+			return this.overrideContentType.get(partName);
+
+		String extension = partName.getExtension().toLowerCase();
+		if (this.defaultContentType.containsKey(extension))
+			return this.defaultContentType.get(extension);
+
+		/*
+		 * [M2.4] : The package implementer shall require that the Content Types
+		 * stream contain one of the following for every part in the package:
+		 * One matching Default element, One matching Override element, Both a
+		 * matching Default element and a matching Override element, in which
+		 * case the Override element takes precedence.
+		 */
+		if (this.container != null && this.container.getPart(partName) != null) {
+			throw new OpenXML4JRuntimeException(
+					"Rule M2.4 exception : this error should NEVER happen, if so please send a mail to the developers team, thanks !");
+		} else {
+			return null;
+		}
+	}
+
+	/**
+	 * Clear all content types.
+	 */
+	public void clearAll() {
+		this.defaultContentType.clear();
+		if (this.overrideContentType != null)
+			this.overrideContentType.clear();
+	}
+
+	/**
+	 * Clear all override content types.
+	 * 
+	 */
+	public void clearOverrideContentTypes() {
+		if (this.overrideContentType != null)
+			this.overrideContentType.clear();
+	}
+
+	/**
+	 * Parse the content types part.
+	 * 
+	 * @throws InvalidFormatException
+	 *             Throws if the content type doesn't exist or the XML format is
+	 *             invalid.
+	 */
+	private void parseContentTypesFile(InputStream in)
+			throws InvalidFormatException {
+		try {
+			SAXReader xmlReader = new SAXReader();
+			Document xmlContentTypetDoc = xmlReader.read(in);
+
+			// Default content types
+			List defaultTypes = xmlContentTypetDoc.getRootElement().elements(
+					DEFAULT_TAG_NAME);
+			Iterator elementIteratorDefault = defaultTypes.iterator();
+			while (elementIteratorDefault.hasNext()) {
+				Element element = (Element) elementIteratorDefault.next();
+				String extension = element.attribute(EXTENSION_ATTRIBUTE_NAME)
+						.getValue();
+				String contentType = element.attribute(
+						CONTENT_TYPE_ATTRIBUTE_NAME).getValue();
+				addDefaultContentType(extension, contentType);
+			}
+
+			// Overriden content types
+			List overrideTypes = xmlContentTypetDoc.getRootElement().elements(
+					OVERRIDE_TAG_NAME);
+			Iterator elementIteratorOverride = overrideTypes.iterator();
+			while (elementIteratorOverride.hasNext()) {
+				Element element = (Element) elementIteratorOverride.next();
+				URI uri = new URI(element.attribute(PART_NAME_ATTRIBUTE_NAME)
+						.getValue());
+				PackagePartName partName = PackagingURIHelper
+						.createPartName(uri);
+				String contentType = element.attribute(
+						CONTENT_TYPE_ATTRIBUTE_NAME).getValue();
+				addOverrideContentType(partName, contentType);
+			}
+		} catch (URISyntaxException urie) {
+			throw new InvalidFormatException(urie.getMessage());
+		} catch (DocumentException e) {
+			throw new InvalidFormatException(e.getMessage());
+		}
+	}
+
+	/**
+	 * Save the contents type part.
+	 * 
+	 * @param outStream
+	 *            The output stream use to save the XML content of the content
+	 *            types part.
+	 * @return <b>true</b> if the operation success, else <b>false</b>.
+	 */
+	public boolean save(OutputStream outStream) {
+		Document xmlOutDoc = DocumentHelper.createDocument();
+
+		// Building namespace
+		Namespace dfNs = Namespace.get("", TYPES_NAMESPACE_URI);
+		Element typesElem = xmlOutDoc
+				.addElement(new QName(TYPES_TAG_NAME, dfNs));
+
+		// Adding default types
+		for (Entry<String, String> entry : defaultContentType.entrySet()) {
+			appendDefaultType(typesElem, entry);
+		}
+
+		// Adding specific types if any exist
+		if (overrideContentType != null) {
+			for (Entry<PackagePartName, String> entry : overrideContentType
+					.entrySet()) {
+				appendSpecificTypes(typesElem, entry);
+			}
+		}
+		xmlOutDoc.normalize();
+
+		// Save content in the specified output stream
+		return this.saveImpl(xmlOutDoc, outStream);
+	}
+
+	/**
+	 * Use to append specific type XML elements, use by the save() method.
+	 * 
+	 * @param root
+	 *            XML parent element use to append this override type element.
+	 * @param entry
+	 *            The values to append.
+	 * @see #save(ZipOutputStream)
+	 */
+	private void appendSpecificTypes(Element root,
+			Entry<PackagePartName, String> entry) {
+		root.addElement(OVERRIDE_TAG_NAME).addAttribute(
+				PART_NAME_ATTRIBUTE_NAME,
+				((PackagePartName) entry.getKey()).getName()).addAttribute(
+				CONTENT_TYPE_ATTRIBUTE_NAME, (String) entry.getValue());
+	}
+
+	/**
+	 * Use to append default types XML elements, use by the save() metid.
+	 * 
+	 * @param root
+	 *            XML parent element use to append this default type element.
+	 * @param entry
+	 *            The values to append.
+	 * @see #save(ZipOutputStream)
+	 */
+	private void appendDefaultType(Element root, Entry<String, String> entry) {
+		root.addElement(DEFAULT_TAG_NAME).addAttribute(
+				EXTENSION_ATTRIBUTE_NAME, (String) entry.getKey())
+				.addAttribute(CONTENT_TYPE_ATTRIBUTE_NAME,
+						(String) entry.getValue());
+
+	}
+
+	/**
+	 * Specific implementation of the save method. Call by the save() method,
+	 * call before exiting.
+	 * 
+	 * @param out
+	 *            The output stream use to write the content type XML.
+	 */
+	public abstract boolean saveImpl(Document content, OutputStream out);
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ContentTypeManager.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/FileHelper.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/FileHelper.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/FileHelper.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/FileHelper.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,91 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+/**
+ * Provide useful method to manage file.
+ * 
+ * @author Julien Chable
+ * @version 0.1
+ */
+public final class FileHelper {
+
+	/**
+	 * Get the directory part of the specified file path.
+	 * 
+	 * @param f
+	 *            File to process.
+	 * @return The directory path from the specified
+	 */
+	public static File getDirectory(File f) {
+		if (f != null) {
+			String path = f.getPath();
+			int len = path.length();
+			int num2 = len;
+			while (--num2 >= 0) {
+				char ch1 = path.charAt(num2);
+				if (ch1 == File.separatorChar) {
+					return new File(path.substring(0, num2));
+				}
+			}
+		}
+		return null;
+	}
+
+	/**
+	 * Copy a file.
+	 * 
+	 * @param in
+	 *            The source file.
+	 * @param out
+	 *            The target location.
+	 * @throws IOException
+	 *             If an I/O error occur.
+	 */
+	public static void copyFile(File in, File out) throws IOException {
+		FileChannel sourceChannel = new FileInputStream(in).getChannel();
+		FileChannel destinationChannel = new FileOutputStream(out).getChannel();
+		sourceChannel.transferTo(0, sourceChannel.size(), destinationChannel);
+		sourceChannel.close();
+		destinationChannel.close();
+	}
+
+	/**
+	 * Get file name from the specified File object.
+	 */
+	public static String getFilename(File file) {
+		if (file != null) {
+			String path = file.getPath();
+			int len = path.length();
+			int num2 = len;
+			while (--num2 >= 0) {
+				char ch1 = path.charAt(num2);
+				if (ch1 == File.separatorChar)
+					return path.substring(num2 + 1, len);
+			}
+		}
+		return "";
+	}
+
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/FileHelper.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,126 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.Package;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.internal.marshallers.ZipPartMarshaller;
+
+/**
+ * Memory version of a package part. Use to
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ */
+public final class MemoryPackagePart extends PackagePart {
+
+	/**
+	 * Storage for the part data.
+	 */
+	protected byte[] data;
+
+	/**
+	 * Size of data.
+	 */
+	protected int length;
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param pack
+	 *            The owner package.
+	 * @param partName
+	 *            The part name.
+	 * @param contentType
+	 *            The content type.
+	 * @throws InvalidFormatException
+	 *             If the specified URI is not OPC compliant.
+	 */
+	public MemoryPackagePart(Package pack, PackagePartName partName,
+			String contentType) throws InvalidFormatException {
+		super(pack, partName, contentType);
+	}
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param pack
+	 *            The owner package.
+	 * @param partName
+	 *            The part name.
+	 * @param contentType
+	 *            The content type.
+	 * @param loadRelationships
+	 *            Specify if the relationships will be loaded.
+	 * @throws InvalidFormatException
+	 *             If the specified URI is not OPC compliant.
+	 */
+	public MemoryPackagePart(Package pack, PackagePartName partName,
+			String contentType, boolean loadRelationships)
+			throws InvalidFormatException {
+		super(pack, partName, new ContentType(contentType), loadRelationships);
+	}
+
+	@Override
+	protected InputStream getInputStreamImpl() {
+		// If this part has been created from scratch and/or the data buffer is
+		// not
+		// initialize, so we do it now.
+		if (data == null) {
+			data = new byte[0];
+		}
+		return new ByteArrayInputStream(data);
+	}
+
+	@Override
+	protected OutputStream getOutputStreamImpl() {
+		return new MemoryPackagePartOutputStream(this);
+	}
+
+	public void clear() {
+		data = null;
+		length = 0;
+	}
+
+	@Override
+	public boolean save(OutputStream os) throws OpenXML4JException {
+		return new ZipPartMarshaller().marshall(this, os);
+	}
+
+	@Override
+	public boolean load(InputStream ios) throws InvalidFormatException {
+		throw new InvalidFormatException("Method not implemented");
+	}
+
+	@Override
+	public void close() {
+		// Do nothing
+	}
+
+	@Override
+	public void flush() {
+		// Do nothing
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePart.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePartOutputStream.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePartOutputStream.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePartOutputStream.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePartOutputStream.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,96 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Build an output stream for MemoryPackagePart.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ */
+public final class MemoryPackagePartOutputStream extends OutputStream {
+
+	private MemoryPackagePart part;
+
+	private ByteArrayOutputStream buff;
+
+	public MemoryPackagePartOutputStream(MemoryPackagePart part) {
+		this.part = part;
+		buff = new ByteArrayOutputStream();
+	}
+
+	@Override
+	public void write(int b) throws IOException {
+		buff.write(b);
+	}
+
+	/**
+	 * Close this stream and flush the content.
+	 * @see #flush() 
+	 */
+	@Override
+	public void close() throws IOException {
+		this.flush();
+	}
+
+	/**
+	 * Flush this output stream. This method is called by the close() method.
+	 * Warning : don't call this method for output consistency.
+	 * @see #close()
+	 */
+	@Override
+	public void flush() throws IOException {
+		buff.flush();
+		if (part.data != null) {
+			byte[] newArray = new byte[part.data.length + buff.size()];
+			// copy the previous contents of part.data in newArray
+			System.arraycopy(part.data, 0, newArray, 0, part.data.length);
+
+			// append the newly added data
+			byte[] buffArr = buff.toByteArray();
+			System.arraycopy(buffArr, 0, newArray, part.data.length,
+					buffArr.length);
+
+			// save the result as new data
+			part.data = newArray;
+		} else {
+			// was empty, just fill it
+			part.data = buff.toByteArray();
+		}
+		
+		/* 
+		 * Clear this streams buffer, in case flush() is called a second time
+		 * Fix bug 1921637 - provided by Rainer Schwarze
+		 */
+		buff.reset();
+	}
+
+	@Override
+	public void write(byte[] b, int off, int len) throws IOException {
+		buff.write(b, off, len);
+	}
+
+	@Override
+	public void write(byte[] b) throws IOException {
+		buff.write(b);
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/MemoryPackagePartOutputStream.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,621 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.ParsePosition;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.InvalidOperationException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.ContentTypes;
+import org.apache.poi.openxml4j.opc.Package;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.PackagePartName;
+import org.apache.poi.openxml4j.opc.PackageProperties;
+import org.apache.poi.openxml4j.util.Nullable;
+
+/**
+ * Represents the core properties part of a package.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ */
+public class PackagePropertiesPart extends PackagePart implements
+		PackageProperties {
+
+	public final static String NAMESPACE_DC_URI = "http://purl.org/dc/elements/1.1/";
+
+	public final static String NAMESPACE_CP_URI = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
+
+	public final static String NAMESPACE_DCTERMS_URI = "http://purl.org/dc/terms/";
+
+	public final static String NAMESPACE_XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";
+
+	/**
+	 * Constructor.
+	 * 
+	 * @param pack
+	 *            Container package.
+	 * @param partName
+	 *            Name of this part.
+	 * @throws InvalidFormatException
+	 *             Throws if the content is invalid.
+	 */
+	public PackagePropertiesPart(Package pack, PackagePartName partName)
+			throws InvalidFormatException {
+		super(pack, partName, ContentTypes.CORE_PROPERTIES_PART);
+	}
+
+	/**
+	 * A categorization of the content of this package.
+	 * 
+	 * [Example: Example values for this property might include: Resume, Letter,
+	 * Financial Forecast, Proposal, Technical Presentation, and so on. This
+	 * value might be used by an application's user interface to facilitate
+	 * navigation of a large set of documents. end example]
+	 */
+	protected Nullable<String> category = new Nullable<String>();
+
+	/**
+	 * The status of the content.
+	 * 
+	 * [Example: Values might include "Draft", "Reviewed", and "Final". end
+	 * example]
+	 */
+	protected Nullable<String> contentStatus = new Nullable<String>();
+
+	/**
+	 * The type of content represented, generally defined by a specific use and
+	 * intended audience.
+	 * 
+	 * [Example: Values might include "Whitepaper", "Security Bulletin", and
+	 * "Exam". end example] [Note: This property is distinct from MIME content
+	 * types as defined in RFC 2616. end note]
+	 */
+	protected Nullable<String> contentType = new Nullable<String>();
+
+	/**
+	 * Date of creation of the resource.
+	 */
+	protected Nullable<Date> created = new Nullable<Date>();
+
+	/**
+	 * An entity primarily responsible for making the content of the resource.
+	 */
+	protected Nullable<String> creator = new Nullable<String>();
+
+	/**
+	 * An explanation of the content of the resource.
+	 * 
+	 * [Example: Values might include an abstract, table of contents, reference
+	 * to a graphical representation of content, and a free-text account of the
+	 * content. end example]
+	 */
+	protected Nullable<String> description = new Nullable<String>();
+
+	/**
+	 * An unambiguous reference to the resource within a given context.
+	 */
+	protected Nullable<String> identifier = new Nullable<String>();
+
+	/**
+	 * A delimited set of keywords to support searching and indexing. This is
+	 * typically a list of terms that are not available elsewhere in the
+	 * properties.
+	 */
+	protected Nullable<String> keywords = new Nullable<String>();
+
+	/**
+	 * The language of the intellectual content of the resource.
+	 * 
+	 * [Note: IETF RFC 3066 provides guidance on encoding to represent
+	 * languages. end note]
+	 */
+	protected Nullable<String> language = new Nullable<String>();
+
+	/**
+	 * The user who performed the last modification. The identification is
+	 * environment-specific.
+	 * 
+	 * [Example: A name, email address, or employee ID. end example] It is
+	 * recommended that this value be as concise as possible.
+	 */
+	protected Nullable<String> lastModifiedBy = new Nullable<String>();
+
+	/**
+	 * The date and time of the last printing.
+	 */
+	protected Nullable<Date> lastPrinted = new Nullable<Date>();
+
+	/**
+	 * Date on which the resource was changed.
+	 */
+	protected Nullable<Date> modified = new Nullable<Date>();
+
+	/**
+	 * The revision number.
+	 * 
+	 * [Example: This value might indicate the number of saves or revisions,
+	 * provided the application updates it after each revision. end example]
+	 */
+	protected Nullable<String> revision = new Nullable<String>();
+
+	/**
+	 * The topic of the content of the resource.
+	 */
+	protected Nullable<String> subject = new Nullable<String>();
+
+	/**
+	 * The name given to the resource.
+	 */
+	protected Nullable<String> title = new Nullable<String>();
+
+	/**
+	 * The version number. This value is set by the user or by the application.
+	 */
+	protected Nullable<String> version = new Nullable<String>();
+
+	/*
+	 * Getters and setters
+	 */
+
+	/**
+	 * Get the category property.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getCategoryProperty()
+	 */
+	public Nullable<String> getCategoryProperty() {
+		return category;
+	}
+
+	/**
+	 * Get content status.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getContentStatusProperty()
+	 */
+	public Nullable<String> getContentStatusProperty() {
+		return contentStatus;
+	}
+
+	/**
+	 * Get content type.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getContentTypeProperty()
+	 */
+	public Nullable<String> getContentTypeProperty() {
+		return contentType;
+	}
+
+	/**
+	 * Get created date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getCreatedProperty()
+	 */
+	public Nullable<Date> getCreatedProperty() {
+		return created;
+	}
+
+	/**
+	 * Get created date formated into a String.
+	 * 
+	 * @return A string representation of the created date.
+	 */
+	public String getCreatedPropertyString() {
+		return getDateValue(created);
+	}
+
+	/**
+	 * Get creator.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getCreatorProperty()
+	 */
+	public Nullable<String> getCreatorProperty() {
+		return creator;
+	}
+
+	/**
+	 * Get description.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getDescriptionProperty()
+	 */
+	public Nullable<String> getDescriptionProperty() {
+		return description;
+	}
+
+	/**
+	 * Get identifier.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getIdentifierProperty()
+	 */
+	public Nullable<String> getIdentifierProperty() {
+		return identifier;
+	}
+
+	/**
+	 * Get keywords.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getKeywordsProperty()
+	 */
+	public Nullable<String> getKeywordsProperty() {
+		return keywords;
+	}
+
+	/**
+	 * Get the language.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getLanguageProperty()
+	 */
+	public Nullable<String> getLanguageProperty() {
+		return language;
+	}
+
+	/**
+	 * Get the author of last modifications.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getLastModifiedByProperty()
+	 */
+	public Nullable<String> getLastModifiedByProperty() {
+		return lastModifiedBy;
+	}
+
+	/**
+	 * Get last printed date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getLastPrintedProperty()
+	 */
+	public Nullable<Date> getLastPrintedProperty() {
+		return lastPrinted;
+	}
+
+	/**
+	 * Get last printed date formated into a String.
+	 * 
+	 * @return A string representation of the last printed date.
+	 */
+	public String getLastPrintedPropertyString() {
+		return getDateValue(created);
+	}
+
+	/**
+	 * Get modified date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getModifiedProperty()
+	 */
+	public Nullable<Date> getModifiedProperty() {
+		return modified;
+	}
+
+	/**
+	 * Get modified date formated into a String.
+	 * 
+	 * @return A string representation of the modified date.
+	 */
+	public String getModifiedPropertyString() {
+		if (!modified.hasValue())
+			return getDateValue(new Nullable<Date>(new Date()));
+		else
+			return getDateValue(modified);
+	}
+
+	/**
+	 * Get revision.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getRevisionProperty()
+	 */
+	public Nullable<String> getRevisionProperty() {
+		return revision;
+	}
+
+	/**
+	 * Get subject.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getSubjectProperty()
+	 */
+	public Nullable<String> getSubjectProperty() {
+		return subject;
+	}
+
+	/**
+	 * Get title.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getTitleProperty()
+	 */
+	public Nullable<String> getTitleProperty() {
+		return title;
+	}
+
+	/**
+	 * Get version.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#getVersionProperty()
+	 */
+	public Nullable<String> getVersionProperty() {
+		return version;
+	}
+
+	/**
+	 * Set the category.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setCategoryProperty(java.lang.String)
+	 */
+	public void setCategoryProperty(String category) {
+		this.category = setStringValue(category);
+	}
+
+	/**
+	 * Set the content status.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setContentStatusProperty(java.lang.String)
+	 */
+	public void setContentStatusProperty(String contentStatus) {
+		this.contentStatus = setStringValue(contentStatus);
+	}
+
+	/**
+	 * Set the content type.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setContentTypeProperty(java.lang.String)
+	 */
+	public void setContentTypeProperty(String contentType) {
+		this.contentType = setStringValue(contentType);
+	}
+
+	/**
+	 * Set the created date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setCreatedProperty(org.apache.poi.openxml4j.util.Nullable)
+	 */
+	public void setCreatedProperty(String created) {
+		try {
+			this.created = setDateValue(created);
+		} catch (InvalidFormatException e) {
+			new IllegalArgumentException("created  : "
+					+ e.getLocalizedMessage());
+		}
+	}
+
+	/**
+	 * Set the created date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setCreatedProperty(org.apache.poi.openxml4j.util.Nullable)
+	 */
+	public void setCreatedProperty(Nullable<Date> created) {
+		if (created.hasValue())
+			this.created = created;
+	}
+
+	/**
+	 * Set the creator.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setCreatorProperty(java.lang.String)
+	 */
+	public void setCreatorProperty(String creator) {
+		this.creator = setStringValue(creator);
+	}
+
+	/**
+	 * Set the description.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setDescriptionProperty(java.lang.String)
+	 */
+	public void setDescriptionProperty(String description) {
+		this.description = setStringValue(description);
+	}
+
+	/**
+	 * Set identifier.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setIdentifierProperty(java.lang.String)
+	 */
+	public void setIdentifierProperty(String identifier) {
+		this.identifier = setStringValue(identifier);
+	}
+
+	/**
+	 * Set keywords.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setKeywordsProperty(java.lang.String)
+	 */
+	public void setKeywordsProperty(String keywords) {
+		this.keywords = setStringValue(keywords);
+	}
+
+	/**
+	 * Set language.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setLanguageProperty(java.lang.String)
+	 */
+	public void setLanguageProperty(String language) {
+		this.language = setStringValue(language);
+	}
+
+	/**
+	 * Set last modifications author.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setLastModifiedByProperty(java.lang.String)
+	 */
+	public void setLastModifiedByProperty(String lastModifiedBy) {
+		this.lastModifiedBy = setStringValue(lastModifiedBy);
+	}
+
+	/**
+	 * Set last printed date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setLastPrintedProperty(org.apache.poi.openxml4j.util.Nullable)
+	 */
+	public void setLastPrintedProperty(String lastPrinted) {
+		try {
+			this.lastPrinted = setDateValue(lastPrinted);
+		} catch (InvalidFormatException e) {
+			new IllegalArgumentException("lastPrinted  : "
+					+ e.getLocalizedMessage());
+		}
+	}
+
+	/**
+	 * Set last printed date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setLastPrintedProperty(org.apache.poi.openxml4j.util.Nullable)
+	 */
+	public void setLastPrintedProperty(Nullable<Date> lastPrinted) {
+		if (lastPrinted.hasValue())
+			this.lastPrinted = lastPrinted;
+	}
+
+	/**
+	 * Set last modification date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setModifiedProperty(org.apache.poi.openxml4j.util.Nullable)
+	 */
+	public void setModifiedProperty(String modified) {
+		try {
+			this.modified = setDateValue(modified);
+		} catch (InvalidFormatException e) {
+			new IllegalArgumentException("modified  : "
+					+ e.getLocalizedMessage());
+		}
+	}
+
+	/**
+	 * Set last modification date.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setModifiedProperty(org.apache.poi.openxml4j.util.Nullable)
+	 */
+	public void setModifiedProperty(Nullable<Date> modified) {
+		if (modified.hasValue())
+			this.modified = modified;
+	}
+
+	/**
+	 * Set revision.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setRevisionProperty(java.lang.String)
+	 */
+	public void setRevisionProperty(String revision) {
+		this.revision = setStringValue(revision);
+	}
+
+	/**
+	 * Set subject.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setSubjectProperty(java.lang.String)
+	 */
+	public void setSubjectProperty(String subject) {
+		this.subject = setStringValue(subject);
+	}
+
+	/**
+	 * Set title.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setTitleProperty(java.lang.String)
+	 */
+	public void setTitleProperty(String title) {
+		this.title = setStringValue(title);
+	}
+
+	/**
+	 * Set version.
+	 * 
+	 * @see org.apache.poi.openxml4j.opc.PackageProperties#setVersionProperty(java.lang.String)
+	 */
+	public void setVersionProperty(String version) {
+		this.version = setStringValue(version);
+	}
+
+	/**
+	 * Convert a strig value into a Nullable<String>
+	 */
+	private Nullable<String> setStringValue(String s) {
+		if (s == null || s.equals(""))
+			return new Nullable<String>();
+		else
+			return new Nullable<String>(s);
+	}
+
+	/**
+	 * Convert a string value represented a date into a Nullable<Date>.
+	 * 
+	 * @throws InvalidFormatException
+	 *             Throws if the date format isnot valid.
+	 */
+	private Nullable<Date> setDateValue(String s) throws InvalidFormatException {
+		if (s == null || s.equals(""))
+			return new Nullable<Date>();
+		else {
+			SimpleDateFormat df = new SimpleDateFormat(
+					"yyyy-MM-dd'T'HH:mm:ss'Z'");
+			Date d = df.parse(s, new ParsePosition(0));
+			if (d == null)
+				throw new InvalidFormatException("Date not well formated");
+			return new Nullable<Date>(d);
+		}
+	}
+
+	/**
+	 * Convert a Nullable<Date> into a String.
+	 * 
+	 * @param d
+	 *            The Date to convert.
+	 * @return The formated date or null.
+	 * @see java.util.SimpleDateFormat
+	 */
+	private String getDateValue(Nullable<Date> d) {
+		if (d == null || d.equals(""))
+			return "";
+		else {
+			SimpleDateFormat df = new SimpleDateFormat(
+					"yyyy-MM-dd'T'HH:mm:ss'Z'");
+			return df.format(d.getValue());
+		}
+	}
+
+	@Override
+	protected InputStream getInputStreamImpl() {
+		throw new InvalidOperationException("Operation not authorized");
+	}
+
+	@Override
+	protected OutputStream getOutputStreamImpl() {
+		throw new InvalidOperationException(
+				"Can't use output stream to set properties !");
+	}
+
+	@Override
+	public boolean save(OutputStream zos) throws OpenXML4JException {
+		throw new InvalidOperationException("Operation not authorized");
+	}
+
+	@Override
+	public boolean load(InputStream ios) throws InvalidFormatException {
+		throw new InvalidOperationException("Operation not authorized");
+	}
+
+	@Override
+	public void close() {
+		// Do nothing
+	}
+
+	@Override
+	public void flush() {
+		// Do nothing
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PackagePropertiesPart.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,49 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.OutputStream;
+
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.PackagePart;
+
+/**
+ * Object implemented this interface are considered as part marshaller. A part
+ * marshaller is responsible to marshall a part in order to be save in a
+ * package.
+ * 
+ * @author Julien Chable
+ * @version 0.1
+ */
+public interface PartMarshaller {
+
+	/**
+	 * Save the content of the package in the stream
+	 * 
+	 * @param part
+	 *            Part to marshall.
+	 * @param out
+	 *            The output stream into which the part will be marshall.
+	 * @return <b>false</b> if any marshall error occurs, else <b>true</b>
+	 * @throws OpenXML4JException
+	 *             Throws only if any other exceptions are thrown by inner
+	 *             methods.
+	 */
+	public boolean marshall(PackagePart part, OutputStream out)
+			throws OpenXML4JException;
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartMarshaller.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartUnmarshaller.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartUnmarshaller.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartUnmarshaller.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartUnmarshaller.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,50 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
+import org.apache.poi.openxml4j.opc.PackagePart;
+import org.apache.poi.openxml4j.opc.internal.unmarshallers.UnmarshallContext;
+
+/**
+ * Object implemented this interface are considered as part unmarshaller. A part
+ * unmarshaller is responsible to unmarshall a part in order to load it from a
+ * package.
+ * 
+ * @author Julien Chable
+ * @version 0.1
+ */
+public interface PartUnmarshaller {
+
+	/**
+	 * Save the content of the package in the stream
+	 * 
+	 * @param in
+	 *            The input stream from which the part will be unmarshall.
+	 * @return The part freshly unmarshall from the input stream.
+	 * @throws OpenXML4JException
+	 *             Throws only if any other exceptions are thrown by inner
+	 *             methods.
+	 */
+	public PackagePart unmarshall(UnmarshallContext context, InputStream in)
+			throws InvalidFormatException, IOException;
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/PartUnmarshaller.java
------------------------------------------------------------------------------
    svn:executable = *

Added: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
URL: http://svn.apache.org/viewvc/poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java?rev=738842&view=auto
==============================================================================
--- poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java (added)
+++ poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java Thu Jan 29 12:44:31 2009
@@ -0,0 +1,90 @@
+/* ====================================================================
+   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.openxml4j.opc.internal;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.dom4j.Document;
+import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
+import org.apache.poi.openxml4j.opc.Package;
+import org.apache.poi.openxml4j.opc.StreamHelper;
+
+/**
+ * Zip implementation of the ContentTypeManager.
+ * 
+ * @author Julien Chable
+ * @version 1.0
+ * @see ContentTypeManager
+ */
+public class ZipContentTypeManager extends ContentTypeManager {
+
+	/**
+	 * Delegate constructor to the super constructor.
+	 * 
+	 * @param in
+	 *            The input stream to parse to fill internal content type
+	 *            collections.
+	 * @throws InvalidFormatException
+	 *             If the content types part content is not valid.
+	 */
+	public ZipContentTypeManager(InputStream in, Package pkg)
+			throws InvalidFormatException {
+		super(in, pkg);
+	}
+
+	@Override
+	public boolean saveImpl(Document content, OutputStream out) {
+		ZipOutputStream zos = null;
+		if (out instanceof ZipOutputStream)
+			zos = (ZipOutputStream) out;
+		else
+			zos = new ZipOutputStream(out);
+
+		ZipEntry partEntry = new ZipEntry(CONTENT_TYPES_PART_NAME);
+		try {
+			// Referenced in ZIP
+			zos.putNextEntry(partEntry);
+			// Saving data in the ZIP file
+			ByteArrayOutputStream outTemp = new ByteArrayOutputStream();
+			StreamHelper.saveXmlInStream(content, out);
+			InputStream ins = new ByteArrayInputStream(outTemp.toByteArray());
+			byte[] buff = new byte[ZipHelper.READ_WRITE_FILE_BUFFER_SIZE];
+			while (ins.available() > 0) {
+				int resultRead = ins.read(buff);
+				if (resultRead == -1) {
+					// end of file reached
+					break;
+				} else {
+					zos.write(buff, 0, resultRead);
+				}
+			}
+			zos.closeEntry();
+		} catch (IOException ioe) {
+			logger.error("Cannot write: " + CONTENT_TYPES_PART_NAME
+					+ " in Zip !", ioe);
+			return false;
+		}
+		return true;
+	}
+}

Propchange: poi/trunk/src/ooxml/java/org/apache/poi/openxml4j/opc/internal/ZipContentTypeManager.java
------------------------------------------------------------------------------
    svn:executable = *



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org