1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  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,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.xmerge.converter.xml;
25 
26 import java.io.IOException;
27 
28 import javax.xml.parsers.DocumentBuilder;
29 import javax.xml.parsers.DocumentBuilderFactory;
30 import javax.xml.parsers.ParserConfigurationException;
31 
32 import org.w3c.dom.Document;
33 import org.w3c.dom.DOMException;
34 import org.w3c.dom.Element;
35 import org.w3c.dom.Node;
36 
37 import org.xml.sax.SAXException;
38 
39 /**
40  * This class represents those embedded objects in an OpenOffice.org document
41  * that have an XML representation.  Currently, according to the OpenOffice.org
42  * File Format 1.0 document, there are 6 such objects:
43  *
44  *      Formulae created with Math              (application/vnd.sun.xml.math)
45  *      Charts created with Chart               (application/vnd.sun.xml.chart)
46  *      Spreadsheets created with Calc          (application/vnd.sun.xml.calc)
47  *      Text created with Writer                (application/vnd.sun.xml.writer)
48  *      Drawings created with Draw              (application/vnd.sun.xml.draw)
49  *      Presentations created with Impress      (application/vnd.sun.xml.impress)
50  *
51  * These object types are stored using a combination of content, settings and styles
52  * XML files.
53  */
54 public class EmbeddedXMLObject extends EmbeddedObject {
55 
56     // Entries for the subdocuments that constitute this object;
57     protected Document contentDOM  = null;
58     protected Document settingsDOM = null;
59     protected Document stylesDOM   = null;
60 
61     private DocumentBuilder builder = null;
62 
63     /**
64      * Constructor for an embedded object stored using an XML representation.
65      *
66      * @param   name    The name of the object.
67      * @param   type    The mime-type of the object.  See the class summary.
68      */
EmbeddedXMLObject(String name, String type)69     public EmbeddedXMLObject(String name, String type) {
70         super(name, type);
71     }
72 
73     /**
74      * Package private constructor for use when reading an object from a
75      * compressed SX? file.
76      *
77      * @param   name    The name of the object.
78      * @param   type    The mime-type of the object.  See the class summary.
79      * @param   source  The OfficeZip representation of the SX? file that stores
80      *                  the object.
81      */
EmbeddedXMLObject(String name, String type, OfficeZip source)82     EmbeddedXMLObject(String name, String type, OfficeZip source) {
83         super(name, type, source);
84     }
85 
86 
87     /**
88      * Returns the content data for this embedded object.
89      *
90      * @return DOM represenation of "content.xml"
91      *
92      * @throws  SAXException    If any parser error occurs
93      * @throws  IOException     If any IO error occurs
94      */
getContentDOM()95     public Document getContentDOM() throws SAXException, IOException {
96 
97         if (contentDOM == null) {
98             contentDOM = getNamedDOM("content.xml");
99         }
100 
101         return contentDOM;
102     }
103 
104 
105     /**
106      * Sets the content data for the embedded object.
107      *
108      * @param   content     DOM representation of the object's content.
109      */
setContentDOM(Document content)110     public void setContentDOM(Document content) {
111         contentDOM = content;
112         hasChanged = true;
113     }
114 
115 
116     /**
117      * Returns the settings data for this embedded object.
118      *
119      * @return DOM represenation of "settings.xml"
120      *
121      * @throws  SAXException    If any parser error occurs
122      * @throws  IOException     If any IO error occurs
123      */
getSettingsDOM()124     public Document getSettingsDOM() throws SAXException, IOException {
125 
126         if (settingsDOM == null) {
127             settingsDOM = getNamedDOM("settings.xml");
128         }
129 
130         return settingsDOM;
131     }
132 
133 
134     /**
135      * Sets the settings data for the embedded object.
136      *
137      * @param   settings     DOM representation of the object's styles.
138      */
setSettingsDOM(Document settings)139     public void setSettingsDOM(Document settings) {
140         settingsDOM = settings;
141         hasChanged = true;
142     }
143 
144 
145     /**
146      * Returns the style data for this embedded object.
147      *
148      * @return DOM represenation of "styles.xml"
149      *
150      * @throws  SAXException    If any parser error occurs
151      * @throws  IOException     If any IO error occurs
152      */
getStylesDOM()153     public Document getStylesDOM() throws SAXException, IOException {
154 
155         if (stylesDOM == null) {
156             stylesDOM = getNamedDOM("styles.xml");
157         }
158 
159         return stylesDOM;
160     }
161 
162 
163     /**
164      * Sets the styles data for the embedded object.
165      *
166      * @param   styles     DOM representation of the object's styles.
167      */
setStylesDOM(Document styles)168     public void setStylesDOM(Document styles) {
169         stylesDOM = styles;
170         hasChanged = true;
171     }
172 
173 
174     /**
175      * This method extracts the data for the given XML file from the SX? file
176      * and creates a DOM representation of it.
177      *
178      * @param   name    The name of the XML file to retrieve.  It is paired with
179      *                  the object name to access the SX? file.
180      *
181      * @return  DOM representation of the named XML file.
182      *
183      * @throws  SAXException    If any parser error occurs
184      * @throws  IOException     If any IO error occurs
185      */
getNamedDOM(String name)186     private Document getNamedDOM(String name) throws SAXException, IOException {
187         if (zipFile == null) {
188             return null;
189         }
190 
191         try {
192             if (builder == null) {
193                 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
194 
195                 factory.setValidating(false);
196                 builder = factory.newDocumentBuilder();
197             }
198 
199             byte[] data = zipFile.getNamedBytes(new String(objName + "/" + name));
200             if (data != null) {
201                 return OfficeDocument.parse(builder, data);
202             }
203             else {
204                 return null;
205             }
206 
207         }
208         catch (SAXException se) {
209             throw se;
210         }
211         catch (IOException ioe) {
212             throw ioe;
213         }
214         catch (ParserConfigurationException pce) {
215             throw new SAXException(pce);
216         }
217     }
218 
219 
220     /**
221      * Package private method for writing the data of the EmbeddedObject to a
222      * SX? file.
223      *
224      * @param   zip     An <code>OfficeZip</code> instance representing the file
225      *                  the data is to be written to.
226      */
write(OfficeZip zip)227     void write(OfficeZip zip) throws IOException {
228         if (hasChanged == true) {
229             if (contentDOM != null) {
230                 zip.setNamedBytes(new String(objName + "/content.xml"),
231                                         OfficeDocument.docToBytes(contentDOM));
232             }
233             if (settingsDOM != null) {
234                 zip.setNamedBytes(new String(objName + "/settings.xml"),
235                                         OfficeDocument.docToBytes(settingsDOM));
236             }
237             if (stylesDOM != null) {
238                 zip.setNamedBytes(new String(objName + "/styles.xml"),
239                                         OfficeDocument.docToBytes(stylesDOM));
240             }
241         }
242     }
243 
244     /**
245      * Package private method that constructs the manifest.xml entries for this
246      * embedded object.
247      *
248      * @param  manifestDoc    <code>Document</code> containing the manifest entries.
249      */
writeManifestData(Document manifestDoc)250     void writeManifestData(Document manifestDoc) throws DOMException {
251         Node root = manifestDoc.getDocumentElement();
252 
253         if (contentDOM != null) {
254             Element contentNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
255 
256             contentNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
257             contentNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
258                                         new String(objName + "/content.xml"));
259 
260             root.appendChild(contentNode);
261         }
262 
263         if (settingsDOM != null) {
264             Element settingsNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
265 
266             settingsNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
267             settingsNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
268                                         new String(objName + "/settings.xml"));
269 
270             root.appendChild(settingsNode);
271         }
272 
273         if (stylesDOM != null) {
274             Element stylesNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
275 
276             stylesNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, "text/xml");
277             stylesNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
278                                         new String(objName + "/styles.xml"));
279         }
280 
281 
282         Element objectNode = manifestDoc.createElement(OfficeConstants.TAG_MANIFEST_FILE);
283 
284         objectNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_TYPE, objType);
285         objectNode.setAttribute(OfficeConstants.ATTRIBUTE_MANIFEST_FILE_PATH,
286                                     new String(objName + "/"));
287 
288         root.appendChild(objectNode);
289     }
290 
291 }
292