source: trunk/docx4j/src/main/java/org/docx4j/openpackaging/contenttype/ContentTypeManager.java @ 1784

Revision 1784, 32.3 KB checked in by jharrop, 5 weeks ago (diff)

XmlSignature? part, which uses JAXB representation of xmldsig-core, contained in separate project.

  • Property svn:eol-style set to native
Line 
1/*
2 *  Copyright 2007-2008, Plutext Pty Ltd.
3 *   
4 *  This file is part of docx4j.
5
6    docx4j is licensed under the Apache License, Version 2.0 (the "License");
7    you may not use this file except in compliance with the License.
8
9    You may obtain a copy of the License at
10
11        http://www.apache.org/licenses/LICENSE-2.0
12
13    Unless required by applicable law or agreed to in writing, software
14    distributed under the License is distributed on an "AS IS" BASIS,
15    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16    See the License for the specific language governing permissions and
17    limitations under the License.
18
19 */
20/*
21 * Portions Copyright (c) 2006, Wygwam
22 * With respect to those portions:
23 *
24 * All rights reserved.
25 *
26 * Redistribution and use in source and binary forms, with or without modification,
27 * are permitted provided that the following conditions are met:
28 *
29 * - Redistributions of source code must retain the above copyright notice,
30 * this list of conditions and the following disclaimer.
31 * - Redistributions in binary form must reproduce the above copyright notice,
32 * this list of conditions and the following disclaimer in the documentation and/or
33 * other materials provided with the distribution.
34 * - Neither the name of Wygwam nor the names of its contributors may be
35 * used to endorse or promote products derived from this software without
36 * specific prior written permission.
37 *
38 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
39 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
40 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
41 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
42 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47 */
48
49package org.docx4j.openpackaging.contenttype;
50
51import java.io.ByteArrayOutputStream;
52import java.io.InputStream;
53import java.net.URI;
54import java.net.URISyntaxException;
55import java.util.Iterator;
56import java.util.Map;
57import java.util.TreeMap;
58import java.util.Map.Entry;
59
60import javax.xml.bind.JAXBElement;
61import javax.xml.bind.JAXBException;
62import javax.xml.bind.Marshaller;
63import javax.xml.bind.Unmarshaller;
64
65import org.apache.log4j.Logger;
66import org.docx4j.XmlUtils;
67import org.docx4j.jaxb.Context;
68import org.docx4j.jaxb.NamespacePrefixMapperUtils;
69import org.docx4j.openpackaging.exceptions.Docx4JException;
70import org.docx4j.openpackaging.exceptions.InvalidFormatException;
71import org.docx4j.openpackaging.exceptions.PartUnrecognisedException;
72import org.docx4j.openpackaging.packages.OpcPackage;
73import org.docx4j.openpackaging.packages.PresentationMLPackage;
74import org.docx4j.openpackaging.packages.SpreadsheetMLPackage;
75import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
76import org.docx4j.openpackaging.parts.CustomXmlDataStoragePropertiesPart;
77import org.docx4j.openpackaging.parts.DefaultXmlPart;
78import org.docx4j.openpackaging.parts.DocPropsCorePart;
79import org.docx4j.openpackaging.parts.DocPropsCustomPart;
80import org.docx4j.openpackaging.parts.DocPropsExtendedPart;
81import org.docx4j.openpackaging.parts.JaxbXmlPart;
82import org.docx4j.openpackaging.parts.Part;
83import org.docx4j.openpackaging.parts.PartName;
84import org.docx4j.openpackaging.parts.ThemePart;
85import org.docx4j.openpackaging.parts.VMLBinaryPart;
86import org.docx4j.openpackaging.parts.VMLPart;
87import org.docx4j.openpackaging.parts.DrawingML.Chart;
88import org.docx4j.openpackaging.parts.DrawingML.Drawing;
89import org.docx4j.openpackaging.parts.DrawingML.JaxbDmlPart;
90import org.docx4j.openpackaging.parts.PresentationML.JaxbPmlPart;
91import org.docx4j.openpackaging.parts.SpreadsheetML.JaxbSmlPart;
92import org.docx4j.openpackaging.parts.SpreadsheetML.WorkbookPart;
93import org.docx4j.openpackaging.parts.WordprocessingML.AlternativeFormatInputPart;
94import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPart;
95import org.docx4j.openpackaging.parts.WordprocessingML.CommentsPart;
96import org.docx4j.openpackaging.parts.WordprocessingML.DocumentSettingsPart;
97import org.docx4j.openpackaging.parts.WordprocessingML.EmbeddedPackagePart;
98import org.docx4j.openpackaging.parts.WordprocessingML.EndnotesPart;
99import org.docx4j.openpackaging.parts.WordprocessingML.FontTablePart;
100import org.docx4j.openpackaging.parts.WordprocessingML.FooterPart;
101import org.docx4j.openpackaging.parts.WordprocessingML.FootnotesPart;
102import org.docx4j.openpackaging.parts.WordprocessingML.GlossaryDocumentPart;
103import org.docx4j.openpackaging.parts.WordprocessingML.HeaderPart;
104import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
105import org.docx4j.openpackaging.parts.WordprocessingML.MetafileEmfPart;
106import org.docx4j.openpackaging.parts.WordprocessingML.MetafileWmfPart;
107import org.docx4j.openpackaging.parts.WordprocessingML.NumberingDefinitionsPart;
108import org.docx4j.openpackaging.parts.WordprocessingML.ObfuscatedFontPart;
109import org.docx4j.openpackaging.parts.WordprocessingML.StyleDefinitionsPart;
110import org.docx4j.openpackaging.parts.WordprocessingML.WebSettingsPart;
111import org.docx4j.openpackaging.parts.relationships.Namespaces;
112import org.docx4j.relationships.Relationship;
113import org.glox4j.openpackaging.packages.GloxPackage;
114
115
116/**
117 * Manage package content types ([Content_Types].xml ) .
118 *
119 * @author Julien Chable
120 * @version 1.0
121 */
122public class ContentTypeManager  {
123       
124        protected static Logger log = Logger.getLogger(ContentTypeManager.class);
125       
126        /**
127         * Content type part name.
128         */
129        public static final String CONTENT_TYPES_PART_NAME = "[Content_Types].xml";
130
131        /**
132         * Content type namespace
133         */
134        public static final String TYPES_NAMESPACE_URI = "http://schemas.openxmlformats.org/package/2006/content-types";
135
136       
137       
138        /* Xml elements in content type part */
139
140        private static final String TYPES_TAG_NAME = "Types";
141
142        private static final String DEFAULT_TAG_NAME = "Default";
143
144        private static final String EXTENSION_ATTRIBUTE_NAME = "Extension";
145
146        private static final String CONTENT_TYPE_ATTRIBUTE_NAME = "ContentType";
147
148        private static final String OVERRIDE_TAG_NAME = "Override";
149
150        private static final String PART_NAME_ATTRIBUTE_NAME = "PartName";
151
152        /**
153         * Default content type tree. <Extension, ContentType>
154         */
155        private TreeMap<String, CTDefault> defaultContentType;
156
157        /**
158         * Override content type tree.
159         */
160        private TreeMap<URI, CTOverride> overrideContentType;
161       
162        private static ObjectFactory ctFactory = new ObjectFactory();
163
164        public ContentTypeManager()  {
165                init();
166        }
167       
168        private void init() {
169                defaultContentType = new TreeMap<String, CTDefault>();
170                overrideContentType = new TreeMap<URI, CTOverride>();
171        }
172
173//      /**
174//       * Build association extention-> content type (will be stored in
175//       * [Content_Types].xml) for example ContentType="image/png" Extension="png"
176//       *
177//       * @param partUri
178//       *            the uri that will be stored
179//       * @return <b>false</b> if an error occured.
180//       */
181//      public void addContentType(PartName partName, String contentType) {
182//              boolean defaultCTExists = false;
183//              String extension = partName.getExtension();
184//              if ((extension.length() == 0)
185//                              || (this.defaultContentType.containsKey(extension)
186//                                              && !(defaultCTExists = this.defaultContentType.containsValue(contentType)))) {
187//                      this.addOverrideContentType(partName.getURI(), contentType);
188//              } else if (!defaultCTExists) {
189//                      this.addDefaultContentType(extension, contentType);
190//              }
191//      }
192
193        /**
194         * Add an override content type for a specific part.
195         *
196         * @param partUri
197         *            Uri of the part.
198         * @param contentType
199         *            Content type of the part.
200         */
201        public void addOverrideContentType(URI partUri, CTOverride contentType) {
202                log.debug("Registered " + partUri.toString() + " of type " + contentType.getContentType() );
203                overrideContentType.put(partUri, contentType);
204        }
205       
206        public void addOverrideContentType(URI partUri, String contentType) {
207
208                CTOverride overrideCT = ctFactory.createCTOverride();
209                overrideCT.setPartName( partUri.toASCIIString() );
210                overrideCT.setContentType(contentType );
211               
212                overrideContentType.put(partUri, overrideCT);
213               
214        }
215
216//      public String getOverrideContentType(URI partUri) {
217//              return overrideContentType.get(partUri);
218//      }
219
220
221        /* Given a content type, return the Part Name URI is it
222         * overridden by.
223         */ 
224        public URI getPartNameOverridenByContentType(String contentType) {
225               
226                // hmm, can there only be one instance of a given
227                // content type?
228               
229                Iterator i = overrideContentType.entrySet().iterator();
230                while (i.hasNext()) {
231                        Map.Entry e = (Map.Entry)i.next();
232                        if (e != null) {
233                                log.debug("Inspecting " + e.getValue());
234                                if ( ((CTOverride)e.getValue()).getContentType().equals(contentType) ) {
235                                        log.debug("Matched!");
236                                        return (URI)e.getKey(); 
237                                }
238                        } 
239                }               
240                return null;
241               
242        }
243       
244        /* Return a part of the appropriate sub class */
245        public  Part getPart(String partName, Relationship rel) throws URISyntaxException, PartUnrecognisedException,
246         InvalidFormatException {
247               
248                Part p;
249
250                // look for an override
251                CTOverride overrideCT = (CTOverride) overrideContentType.get(new URI(partName));
252                if (overrideCT!=null ) {
253                        String contentType = overrideCT.getContentType(); 
254                        log.debug("Found content type '" + contentType + "' for " + partName);
255                         p = newPartForContentType(contentType, partName, rel);
256                         p.setContentType( new ContentType(contentType) );
257                         return p;
258                }               
259               
260                // if there is no override, get use the file extension
261                String ext = partName.substring(partName.indexOf(".") + 1).toLowerCase();
262                log.info("Looking at extension '" + ext);
263                CTDefault defaultCT = (CTDefault)defaultContentType.get(ext);
264                if (defaultCT!=null ) {
265                        String contentType = defaultCT.getContentType();
266                        log.info("Found content type '" + contentType + "' for "
267                                                        + partName);
268                        p = newPartForContentType(contentType, partName, rel);
269                        p.setContentType(new ContentType(contentType));
270                        return p;
271                }
272               
273                // otherwise
274                log.error("No content type found for " + partName);
275                return null;           
276               
277        }
278       
279        public Part newPartForContentType(String contentType, String partName, Relationship rel)
280                throws InvalidFormatException, PartUnrecognisedException {
281                               
282                // TODO - a number of WordML parts aren't listed here!
283                if (rel!=null && rel.getType().equals(Namespaces.AF) ) {
284                        // Could have just passed String relType
285                        // Null where used from BPAI, and a FlatOpcXmlImporter case.
286                        // Cases where rel is not available can prepare a suitable dummy
287                       
288                        AlternativeFormatInputPart afip = 
289                                new AlternativeFormatInputPart(new PartName(partName) );
290                        afip.setContentType(new ContentType(contentType));
291                        return afip;
292                       
293                } else if (rel!=null && rel.getType().equals(Namespaces.EMBEDDED_PKG) ) {
294                       
295                        EmbeddedPackagePart epp = new EmbeddedPackagePart(new PartName(partName) );
296                        epp.setContentType(new ContentType(contentType));
297                        return epp;
298
299                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_DOCUMENT)) { 
300                        return CreateMainDocumentPartObject(partName);
301                        // how is the main document distinguished from the glossary document?
302                        // Answer:- Main Document is a Package level relationship target,
303                        // whereas the Glossary Document is a Part-level target (from the
304                        // Main Document part)                                         
305                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_DOCUMENT_MACROENABLED)) {
306                        return CreateMainDocumentPartObject(partName);
307                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_TEMPLATE)) {
308                        return CreateMainDocumentPartObject(partName);
309                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_TEMPLATE_MACROENABLED)) {
310                        return CreateMainDocumentPartObject(partName);
311                } else if (contentType.equals(ContentTypes.PACKAGE_COREPROPERTIES)) {
312                        return CreateDocPropsCorePartObject(partName ); 
313                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_CUSTOMPROPERTIES)) {
314                        return CreateDocPropsCustomPartObject(partName );
315                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_EXTENDEDPROPERTIES)) {
316                        return CreateDocPropsExtendedPartObject(partName );
317                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_CUSTOMXML_DATASTORAGE)) {
318                        return new org.docx4j.openpackaging.parts.CustomXmlDataStoragePart(new PartName(partName));
319                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_CUSTOMXML_DATASTORAGEPROPERTIES)) {
320                        return CreateCustomXmlDataStoragePropertiesPartObject(partName );                       
321                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_FONT)) {
322                        return CreateObfuscatedFontPartObject(partName );
323                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_OLE_OBJECT)
324                                || contentType.equals(ContentTypes.OFFICEDOCUMENT_ACTIVEX_OBJECT)) {
325                        return new org.docx4j.openpackaging.parts.WordprocessingML.OleObjectBinaryPart(new PartName(partName));
326                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_ACTIVEX_XML_OBJECT)) {
327                        return new org.docx4j.openpackaging.parts.ActiveXControlXmlPart(new PartName(partName));
328                } else if (contentType.equals(ContentTypes.OFFICEDOCUMENT_THEME)) {
329                        return CreateThemePartObject(partName );
330                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_COMMENTS)) {
331                        return CreateCommentsPartObject(partName );
332                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_ENDNOTES)) {
333                        return CreateEndnotesPartObject(partName );
334                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_FONTTABLE)) {
335                        return CreateFontTablePartObject(partName );
336                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_FOOTER)) {
337                        return CreateFooterPartObject(partName );
338                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_FOOTNOTES)) {
339                        return CreateFootnotesPartObject(partName );
340                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_GLOSSARYDOCUMENT)) {
341                        return CreateGlossaryDocumentPartObject(partName );
342                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_HEADER)) {
343                        return CreateHeaderPartObject(partName );
344                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_NUMBERING)) {
345                        return CreateNumberingPartObject(partName );
346                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_SETTINGS)) {
347                        return CreateDocumentSettingsPartObject(partName );
348                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_STYLES)) { 
349                        return CreateStyleDefinitionsPartObject( partName);
350                } else if (contentType.equals(ContentTypes.WORDPROCESSINGML_WEBSETTINGS)) {
351                        return CreateWebSettingsPartObject(partName );
352                } else if (contentType.equals(ContentTypes.IMAGE_JPEG)) {
353                       
354                        if (!partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_JPG_1)
355                                        && !partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_JPG_2)) {
356                                partName = partName + "." + ContentTypes.EXTENSION_JPG_2;
357                        }
358                       
359                        return new org.docx4j.openpackaging.parts.WordprocessingML.ImageJpegPart(new PartName(partName));
360                } else if (contentType.equals(ContentTypes.IMAGE_PNG)) {
361                       
362                        if (!partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_PNG) ) {
363                                partName = partName + "." + ContentTypes.EXTENSION_PNG;
364                        }
365                       
366                        return new org.docx4j.openpackaging.parts.WordprocessingML.ImagePngPart(new PartName(partName));
367                } else if (contentType.equals(ContentTypes.IMAGE_GIF)) {
368                       
369                        if (!partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_GIF) ) {
370                                partName = partName + "." + ContentTypes.EXTENSION_GIF;
371                        }                       
372                       
373                        return new org.docx4j.openpackaging.parts.WordprocessingML.ImageGifPart(new PartName(partName));
374                } else if (contentType.equals(ContentTypes.IMAGE_TIFF)) {
375                       
376                        if (!partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_TIFF) ) {
377                                partName = partName + "." + ContentTypes.EXTENSION_TIFF;
378                        }                       
379                       
380                        return new org.docx4j.openpackaging.parts.WordprocessingML.ImageTiffPart(new PartName(partName));
381//              } else if (contentType.equals(ContentTypes.IMAGE_EPS)) {
382//                     
383//                      if (!partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_EPS) ) {
384//                              partName = partName + "." + ContentTypes.EXTENSION_EPS;
385//                      }                       
386//                     
387//                      return new org.docx4j.openpackaging.parts.WordprocessingML.ImageEpsPart(new PartName(partName));
388                } else if (contentType.equals(ContentTypes.IMAGE_BMP)) {
389                       
390                        if (!partName.toLowerCase().endsWith("." + ContentTypes.EXTENSION_BMP) ) {
391                                partName = partName + "." + ContentTypes.EXTENSION_BMP;
392                        }                       
393                       
394                        return new org.docx4j.openpackaging.parts.WordprocessingML.ImageBmpPart(new PartName(partName));
395                } else if (contentType.equals(ContentTypes.IMAGE_EMF) || contentType.equals(ContentTypes.IMAGE_EMF2)) {
396                        return new MetafileEmfPart(new PartName(partName));
397                } else if (contentType.equals(ContentTypes.IMAGE_WMF)) {
398                        return new MetafileWmfPart(new PartName(partName));
399                } else if (contentType.equals(ContentTypes.VML_DRAWING)) {
400                       
401                        if (partName.endsWith(".xml") ) {                       
402                                return new VMLPart(new PartName(partName));
403                        } else {
404                                return new VMLBinaryPart(new PartName(partName));                               
405                        }
406                } else if (contentType.equals(ContentTypes.DRAWINGML_DIAGRAM_DRAWING)) {
407                        return new org.docx4j.openpackaging.parts.DrawingML.DiagramDrawingPart(new PartName(partName));
408                } else if (contentType.startsWith("application/vnd.openxmlformats-officedocument.drawing")) {
409                        return JaxbDmlPart.newPartForContentType(contentType, partName);
410                } else if (contentType.startsWith("application/vnd.openxmlformats-officedocument.presentationml")) {
411                        return JaxbPmlPart.newPartForContentType(contentType, partName);
412                } else if (contentType.equals(ContentTypes.SPREADSHEETML_WORKBOOK)
413                                || contentType.equals(ContentTypes.SPREADSHEETML_WORKBOOK_MACROENABLED)
414                                || contentType.equals(ContentTypes.SPREADSHEETML_TEMPLATE)
415                                || contentType.equals(ContentTypes.SPREADSHEETML_TEMPLATE_MACROENABLED)) { 
416                        return new WorkbookPart(new PartName(partName));
417                } else if (contentType.startsWith("application/vnd.openxmlformats-officedocument.spreadsheetml")) {
418                        return JaxbSmlPart.newPartForContentType(contentType, partName);
419                } else if (contentType.equals(ContentTypes.DIGITAL_SIGNATURE_XML_SIGNATURE_PART)) {
420                        return new org.docx4j.openpackaging.parts.digitalsignature.XmlSignaturePart(new PartName(partName));
421                } else if (contentType.equals(ContentTypes.APPLICATION_XML)
422                                || partName.endsWith(".xml")) {
423                        // Simple minded detection of XML content.
424                        // If it turns out not to be XML, the zip loader
425                        // will catch the error and load it as a binary part instead.
426                        log.warn("DefaultPart used for part '" + partName
427                                        + "' of content type '" + contentType + "'");
428                        return CreateDefaultXmlPartObject(partName );
429                } else {
430                       
431                        log.error("No subclass found for " + partName + "; defaulting to binary");
432                        //throw new PartUnrecognisedException("No subclass found for " + partName + " (content type '" + contentType + "')");           
433                        return new BinaryPart( new PartName(partName));
434                }
435
436        }
437
438        public Part CreateDefaultXmlPartObject(String partName)
439                        throws InvalidFormatException {
440                return new DefaultXmlPart(new PartName(partName));
441        }
442       
443        public Part CreateMainDocumentPartObject(String partName)
444                        throws InvalidFormatException {
445                return new MainDocumentPart(new PartName(partName));
446        }
447
448        public Part CreateStyleDefinitionsPartObject(String partName) throws InvalidFormatException {
449                return new StyleDefinitionsPart(new PartName(partName));
450        }
451
452        public Part CreateDocumentSettingsPartObject(String partName)
453                        throws InvalidFormatException {
454                return new DocumentSettingsPart(new PartName(partName));
455        }
456
457        public Part CreateWebSettingsPartObject(String partName)
458                        throws InvalidFormatException {
459                return new WebSettingsPart(new PartName(partName));
460        }
461
462        public Part CreateFontTablePartObject(String partName)
463                        throws InvalidFormatException {
464                return new FontTablePart(new PartName(partName));
465        }
466
467        public Part CreateThemePartObject(String partName)
468                        throws InvalidFormatException {
469                return new ThemePart(new PartName(partName));
470        }
471
472        public Part CreateDocPropsCorePartObject(String partName)
473                        throws InvalidFormatException {
474                return new DocPropsCorePart(new PartName(partName));
475        }
476
477        public Part CreateDocPropsExtendedPartObject(String partName)
478                        throws InvalidFormatException {
479                return new DocPropsExtendedPart(new PartName(partName));
480        }
481
482        public Part CreateDocPropsCustomPartObject(String partName)
483                        throws InvalidFormatException {
484                log.info("Using DocPropsCustomPart ...");               
485                return new DocPropsCustomPart(new PartName(partName));
486        }
487       
488        public Part CreateCommentsPartObject(String partName)
489                        throws InvalidFormatException {
490                return new CommentsPart(new PartName(partName));
491        }
492
493        public Part CreateCustomXmlDataStoragePropertiesPartObject(String partName)
494                        throws InvalidFormatException {
495                return new CustomXmlDataStoragePropertiesPart(new PartName(partName));
496        }
497
498        public Part CreateEndnotesPartObject(String partName)
499                        throws InvalidFormatException {
500                return new EndnotesPart(new PartName(partName));
501        }
502
503        public Part CreateFooterPartObject(String partName)
504                        throws InvalidFormatException {
505                return new FooterPart(new PartName(partName));
506        }
507
508        public Part CreateFootnotesPartObject(String partName)
509                        throws InvalidFormatException {
510                return new FootnotesPart(new PartName(partName));
511        }
512
513        public Part CreateGlossaryDocumentPartObject(String partName)
514                        throws InvalidFormatException {
515                return new GlossaryDocumentPart(new PartName(partName));
516        }
517
518        public Part CreateHeaderPartObject(String partName)
519                        throws InvalidFormatException {
520                return new HeaderPart(new PartName(partName));
521        }
522
523        public Part CreateNumberingPartObject(String partName)
524                        throws InvalidFormatException {
525                return new NumberingDefinitionsPart(new PartName(partName));
526        }
527               
528        public Part CreateObfuscatedFontPartObject(String partName)
529                        throws InvalidFormatException {
530                return new ObfuscatedFontPart(new PartName(partName));
531        }
532       
533        /**
534         * Add a content type associated with the specified extension.
535         *
536         * @param extension
537         *            The part name extension to bind to a content type.
538         * @param contentType
539         *            The content type associated with the specified extension.
540         */
541        public void addDefaultContentType(String extension, CTDefault contentType) {
542                log.debug("Registered " + extension );
543                defaultContentType.put(extension.toLowerCase(), contentType);
544        }
545       
546        public void addDefaultContentType(String extension, String contentType) {
547               
548                CTDefault defaultCT = ctFactory.createCTDefault();
549                defaultCT.setExtension(extension.toLowerCase());
550                defaultCT.setContentType(contentType);
551               
552                log.debug("Registered " + extension );
553                defaultContentType.put(extension.toLowerCase(), defaultCT);
554        }
555       
556
557        /**
558         * Delete a content type based on the specified part name. If the specified
559         * part name is register with an override content type, then this content
560         * type is remove, else the content type is remove in the default content
561         * type list if it exists.
562         *
563         * @param partUri
564         *            The part URI associated with the override content type to
565         *            delete.
566         */
567        public void removeContentType(PartName partName) {
568                if (partName == null)
569                        throw new IllegalArgumentException("partName");
570               
571                // Override content type
572                if (this.overrideContentType != null
573                                && (this.overrideContentType.get(partName.getURI()) != null)) {
574                        this.overrideContentType.remove(partName.getURI());
575                        return;
576                }
577                // Default content type
578                this.defaultContentType.remove(partName.getExtension().toLowerCase());
579        }
580
581        /**
582         * Check if the specified content type is already registered
583         * as a default content type.  We don't currently have a method
584         * to check whether its registered as an override content type;
585         * getContentType(PartName partName) may suffice for that purpose.
586         *
587         * @param contentType
588         *            The content type to check.
589         * @return <code>true</code> if the specified content type is already
590         *         registered, then <code>false</code>.
591         */
592        public boolean isContentTypeRegistered(String contentType) {
593                if (contentType == null)
594                        throw new IllegalArgumentException("contentType");
595
596                return this.defaultContentType.values().contains(contentType); 
597//                              || (this.overrideContentType != null
598//                                              && this.overrideContentType.values().contains(contentType)));
599        }
600
601        /**
602         * Get the content type for the specified part, if any.
603         *
604         * @param partUri
605         *            The URI part to check.
606         * @return The content type associated with the URI (in case of an override
607         *         content type) or the extension (in case of default content type),
608         *         else <code>null</code>.
609         */
610        public String getContentType(PartName partName) {
611                if (partName == null)
612                        throw new IllegalArgumentException("partName");
613
614                if ((this.overrideContentType != null)
615                                && this.overrideContentType.containsKey(partName.getURI()))
616                        return this.overrideContentType.get(partName.getURI()).getContentType();
617
618                String extension = partName.getExtension().toLowerCase();
619                if (this.defaultContentType.containsKey(extension))
620                        return this.defaultContentType.get(extension).getContentType();
621
622                return null;
623        }
624
625        /**
626         * Clear all content types.
627         */
628        public void clearAll() {
629                this.defaultContentType.clear();
630                if (this.overrideContentType != null)
631                        this.overrideContentType.clear();
632        }
633
634        /**
635         * Clear all override content types.
636         *
637         */
638        public void clearOverrideContentTypes() {
639                if (this.overrideContentType != null)
640                        this.overrideContentType.clear();
641        }
642
643       
644        public void parseContentTypesFile(InputStream contentTypes) 
645                throws InvalidFormatException {
646               
647                CTTypes types;
648               
649                try {
650                                   
651                        Unmarshaller u = Context.jcContentTypes.createUnmarshaller();
652                       
653                        //u.setSchema(org.docx4j.jaxb.WmlSchema.schema);
654                        u.setEventHandler(new org.docx4j.jaxb.JaxbValidationEventHandler());
655
656                        log.debug("unmarshalling " + this.getClass().getName() );               
657                       
658                        Object res = u.unmarshal( contentTypes );
659                        types = (CTTypes)((JAXBElement)res).getValue();                         
660                        //log.debug( types.getClass().getName() + " unmarshalled" );
661                       
662                        if (log.isDebugEnabled()) {
663                                XmlUtils.marshaltoString(res, true, true, Context.jcContentTypes );
664                        }
665
666                        CTDefault defaultCT;
667                        CTOverride overrideCT;
668                        for(Object o : types.getDefaultOrOverride() ) {
669                               
670                                if (o instanceof CTDefault) {
671                                        defaultCT = (CTDefault)o;
672                                        addDefaultContentType( defaultCT.getExtension(), defaultCT  );
673                                }
674                               
675                                if (o instanceof CTOverride) {
676                                        overrideCT = (CTOverride)o;
677                                        URI uri = new URI(overrideCT.getPartName() );
678                                        addOverrideContentType(uri, overrideCT );
679                                }
680                        }
681                       
682                } catch (Exception e ) {
683                        log.error(e);
684                        throw new InvalidFormatException("Bad [Content_Types].xml", e);
685                }
686               
687               
688        }
689
690        private CTTypes buildTypes() {
691               
692                // Build the JAXB object
693                ObjectFactory factory = new ObjectFactory();
694                CTTypes types = factory.createCTTypes();
695
696                for (Entry<String, CTDefault> entry : defaultContentType.entrySet()) {
697                        types.getDefaultOrOverride().add(entry.getValue());
698                }
699
700                if (overrideContentType != null) {
701                        for (Entry<URI, CTOverride> entry : overrideContentType.entrySet()) {
702                                types.getDefaultOrOverride().add(entry.getValue());
703                        }
704                }       
705                return types;
706        }
707       
708        public void listTypes() {
709               
710
711                for (Entry<String, CTDefault> entry : defaultContentType.entrySet()) {
712                       
713                        System.out.println("// " + entry.getValue().getExtension());
714                        System.out.println("public final static String XX =" );
715                        System.out.println(entry.getValue().getContentType());
716                }
717
718                if (overrideContentType != null) {
719                        for (Entry<URI, CTOverride> entry : overrideContentType.entrySet()) {
720                                System.out.println("// " + entry.getValue().getPartName());
721                                System.out.println("public final static String XX =" );
722                                System.out.println("\"" + entry.getValue().getContentType() + "\";");
723                        }
724                }       
725        }
726       
727    public void marshal(org.w3c.dom.Node node) throws JAXBException {
728               
729                try {
730                        Marshaller marshaller = Context.jcContentTypes.createMarshaller();
731                       
732                        NamespacePrefixMapperUtils.setProperty(marshaller, 
733                                        NamespacePrefixMapperUtils.getPrefixMapper() );
734                       
735                        log.debug("marshalling " + this.getClass().getName() + " ..." );                                                                       
736                       
737                        marshaller.marshal(buildTypes(), node);
738                       
739                        log.info("content types marshalled \n\n" );                                                                     
740
741                } catch (JAXBException e) {
742                        //e.printStackTrace();
743                        log.error(e);
744                        throw e;
745                }
746    }
747   
748    public void marshal(java.io.OutputStream os) throws JAXBException {
749               
750                try {
751                        Marshaller marshaller = Context.jcContentTypes.createMarshaller();
752                       
753                        NamespacePrefixMapperUtils.setProperty(marshaller, 
754                                        NamespacePrefixMapperUtils.getPrefixMapper() );
755                       
756                        log.info("marshalling " + this.getClass().getName() + " ..." );                                                                 
757                        marshaller.marshal(buildTypes(), os);
758
759                } catch (JAXBException e) {
760                        //e.printStackTrace();
761                        log.error(e);
762                        throw e;
763                }
764        }
765
766       
767
768        /* Return a package of the appropriate type.  Used when loading an existing
769         * Package, with an already populated [Content_Types].xml.  When
770         * creating a new Package, start with the new WordprocessingMLPackage constructor. */
771        public OpcPackage createPackage() throws InvalidFormatException {
772               
773                /*
774                 * How do we know what type of Package this is?
775                 *
776                 * In principle, either:
777                 *
778                 * 1. We were told its file extension or mime type in the
779                 * constructor/method parameters, or
780                 *
781                 * 2. Because [Content_Types].xml contains an override for PartName
782                 * /document.xml of content type
783                 * application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml
784                 *
785                 * The latter approach is more reliable, so ..
786                 *
787                 */
788// debugPrint(ctmDocument);
789                OpcPackage p;
790               
791                 
792               
793                if (getPartNameOverridenByContentType(ContentTypes.WORDPROCESSINGML_DOCUMENT) != null
794                                || getPartNameOverridenByContentType(ContentTypes.WORDPROCESSINGML_DOCUMENT_MACROENABLED) != null
795                                || getPartNameOverridenByContentType(ContentTypes.WORDPROCESSINGML_TEMPLATE ) != null
796                                || getPartNameOverridenByContentType(ContentTypes.WORDPROCESSINGML_TEMPLATE_MACROENABLED) != null ) {
797                        log.info("Detected WordProcessingML package ");
798                        p = new WordprocessingMLPackage(this);
799                        return p;
800                } else if (getPartNameOverridenByContentType(ContentTypes.PRESENTATIONML_MAIN) != null
801                                || getPartNameOverridenByContentType(ContentTypes.PRESENTATIONML_TEMPLATE) != null
802                                || getPartNameOverridenByContentType(ContentTypes.PRESENTATIONML_SLIDESHOW) != null) {
803                        log.info("Detected PresentationMLPackage package ");
804                        p = new PresentationMLPackage(this);
805                        return p;
806                } else if (getPartNameOverridenByContentType(ContentTypes.SPREADSHEETML_WORKBOOK) != null
807                                || getPartNameOverridenByContentType(ContentTypes.SPREADSHEETML_WORKBOOK_MACROENABLED) != null
808                                || getPartNameOverridenByContentType(ContentTypes.SPREADSHEETML_TEMPLATE) != null
809                                || getPartNameOverridenByContentType(ContentTypes.SPREADSHEETML_TEMPLATE_MACROENABLED) != null) {
810                        //  "xlam", "xlsb" ?
811                        log.info("Detected SpreadhseetMLPackage package ");
812                        p = new SpreadsheetMLPackage(this);
813                        return p;                       
814                } else if (getPartNameOverridenByContentType(ContentTypes.DRAWINGML_DIAGRAM_LAYOUT) != null) {
815                        log.info("Detected Glox file ");
816                        p = new GloxPackage(this);
817                        return p;                                               
818                } else {
819                        throw new InvalidFormatException("Unexpected package (docx4j supports docx/docxm and pptx only");
820//                      log.warn("No part in [Content_Types].xml for content type"
821//                                      + ContentTypes.WORDPROCESSINGML_DOCUMENT);
822//                      // TODO - what content type in this case?
823//                      return new Package(this);
824                }
825        }
826
827        /*
828         * Gets the content type from an extension.
829         
830        public static String getContentTypeFromExtension(String extension) {
831                if ((extension.equals(ContentTypes.EXTENSION_JPG_1))
832                                || (extension.equals(ContentTypes.EXTENSION_JPG_2))) {
833                        return ContentTypes.IMAGE_JPEG;
834                }
835                if (extension.equals(ContentTypes.EXTENSION_PNG)) {
836                        return ContentTypes.IMAGE_PNG;
837                }
838                if (extension.equals(ContentTypes.EXTENSION_GIF)) {
839                        return ContentTypes.IMAGE_GIF;
840                }
841                if (extension.equals(ContentTypes.EXTENSION_TIFF)) {
842                        return ContentTypes.IMAGE_TIFF;
843                }
844                if (extension.equals(ContentTypes.EXTENSION_PICT)) {
845                        return ContentTypes.IMAGE_PICT;
846                }
847                return null;
848        }
849*/
850       
851    public boolean isContentEqual(ContentTypeManager other) throws Docx4JException {
852       
853        ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
854        ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); 
855        try {
856                marshal(baos);
857                        other.marshal(baos2);
858                } catch (JAXBException e) {
859                        throw new Docx4JException("Error marshalling parts", e);
860                }
861       
862        return java.util.Arrays.equals(baos.toByteArray(), baos2.toByteArray());
863
864    }
865       
866       
867}
Note: See TracBrowser for help on using the repository browser.