1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2
3 /* AbiSource
4 *
5 * Copyright (C) 2007 Philippe Milot <PhilMilot@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301 USA.
21 */
22
23 // Class definition include
24 #include <OXMLi_PackageManager.h>
25
26 // Internal includes
27 #include <OXML_Types.h>
28 #include <OXML_Document.h>
29 #include <OXMLi_StreamListener.h>
30 #include <OXMLi_ListenerState.h>
31 #include <OXML_Section.h>
32
33 // AbiWord includes
34 #include <ut_types.h>
35 #include <ut_assert.h>
36 #include <ut_debugmsg.h>
37 #include <ut_xml.h>
38
39 // External includes
40 #include <gsf/gsf-input.h>
41 #include <gsf/gsf-infile.h>
42 #include <gsf/gsf-open-pkg-utils.h>
43
44 OXMLi_PackageManager* OXMLi_PackageManager::s_pInst = NULL;
45
getNewInstance()46 OXMLi_PackageManager* OXMLi_PackageManager::getNewInstance()
47 {
48 OXMLi_PackageManager::destroyInstance();
49 return OXMLi_PackageManager::getInstance();
50 }
51
getInstance()52 OXMLi_PackageManager* OXMLi_PackageManager::getInstance()
53 {
54 if (s_pInst == NULL) {
55 try {
56 s_pInst = new OXMLi_PackageManager();
57 } catch(...) {
58 UT_DEBUGMSG(("Could not allocate memory!\n"));
59 return NULL;
60 }
61 }
62 return s_pInst;
63 }
64
destroyInstance()65 void OXMLi_PackageManager::destroyInstance()
66 {
67 DELETEP(s_pInst);
68 }
69
OXMLi_PackageManager()70 OXMLi_PackageManager::OXMLi_PackageManager() :
71 m_pPkg(NULL),
72 m_pDocPart(NULL)
73 {
74 }
75
~OXMLi_PackageManager()76 OXMLi_PackageManager::~OXMLi_PackageManager()
77 {
78 if (m_pPkg) {
79 g_object_unref (G_OBJECT(m_pPkg));
80 }
81 if (m_pDocPart) {
82 g_object_unref (G_OBJECT(m_pDocPart));
83 }
84 m_parsedParts.clear();
85 }
86
setContainer(GsfInfile * pPkg)87 void OXMLi_PackageManager::setContainer(GsfInfile * pPkg)
88 {
89 if (m_pPkg) {
90 g_object_unref (G_OBJECT(m_pPkg));
91 }
92 if (m_pDocPart) {
93 g_object_unref (G_OBJECT(m_pDocPart));
94 }
95 m_pPkg = pPkg;
96 }
97
parseDocumentStream()98 UT_Error OXMLi_PackageManager::parseDocumentStream()
99 {
100 OXMLi_StreamListener listener;
101 listener.setupStates(DOCUMENT_PART);
102 return _parseStream( _getDocumentStream(), &listener);
103 }
104
parseDocumentHdrFtr(const char * id)105 UT_Error OXMLi_PackageManager::parseDocumentHdrFtr( const char * id )
106 {
107 GsfInput * doc = _getDocumentStream();
108 UT_return_val_if_fail(doc != NULL, UT_ERROR);
109 OXMLi_StreamListener listener;
110 listener.setupStates(HEADER_PART, id); //Doesn't matter whether it's header or footer
111 return parseChildById(doc, id, &listener);
112 }
113
parseDocumentStyles()114 UT_Error OXMLi_PackageManager::parseDocumentStyles()
115 {
116 GsfInput * doc = _getDocumentStream();
117 UT_return_val_if_fail(doc != NULL, UT_ERROR);
118 OXMLi_StreamListener listener;
119 listener.setupStates(STYLES_PART);
120 return parseChildByType(doc, STYLES_PART, &listener);
121 }
122
parseDocumentTheme()123 UT_Error OXMLi_PackageManager::parseDocumentTheme()
124 {
125 GsfInput * doc = _getDocumentStream();
126 UT_return_val_if_fail(doc != NULL, UT_ERROR);
127 OXMLi_StreamListener listener;
128 listener.setupStates(THEME_PART);
129 UT_Error err = parseChildByType(doc, THEME_PART, &listener);
130 //themes are optional in .docx files
131 if(err != UT_OK){
132 UT_DEBUGMSG(("FRT: OpenXML Theme Part is not found\n"));
133 }
134 return UT_OK;
135 }
136
parseDocumentSettings()137 UT_Error OXMLi_PackageManager::parseDocumentSettings()
138 {
139 GsfInput * doc = _getDocumentStream();
140 UT_return_val_if_fail(doc != NULL, UT_ERROR);
141 OXMLi_StreamListener listener;
142 listener.setupStates(DOCSETTINGS_PART);
143 return parseChildByType(doc, DOCSETTINGS_PART, &listener);
144 }
145
parseDocumentNumbering()146 UT_Error OXMLi_PackageManager::parseDocumentNumbering()
147 {
148 GsfInput * doc = _getDocumentStream();
149 UT_return_val_if_fail(doc != NULL, UT_ERROR);
150 OXMLi_StreamListener listener;
151 listener.setupStates(NUMBERING_PART);
152 return parseChildByType(doc, NUMBERING_PART, &listener);
153 }
154
parseDocumentFootnotes()155 UT_Error OXMLi_PackageManager::parseDocumentFootnotes()
156 {
157 GsfInput * doc = _getDocumentStream();
158 UT_return_val_if_fail(doc != NULL, UT_ERROR);
159 OXMLi_StreamListener listener;
160 listener.setupStates(FOOTNOTES_PART);
161 return parseChildByType(doc, FOOTNOTES_PART, &listener);
162 }
163
parseDocumentEndnotes()164 UT_Error OXMLi_PackageManager::parseDocumentEndnotes()
165 {
166 GsfInput * doc = _getDocumentStream();
167 UT_return_val_if_fail(doc != NULL, UT_ERROR);
168 OXMLi_StreamListener listener;
169 listener.setupStates(ENDNOTES_PART);
170 return parseChildByType(doc, ENDNOTES_PART, &listener);
171 }
172
getChildById(GsfInput * parent,const char * id)173 GsfInput* OXMLi_PackageManager::getChildById( GsfInput * parent, const char * id )
174 {
175 return gsf_open_pkg_open_rel_by_id(parent, id, NULL);
176 }
177
getChildByType(GsfInput * parent,OXML_PartType type)178 GsfInput* OXMLi_PackageManager::getChildByType( GsfInput * parent, OXML_PartType type )
179 {
180 const char * fulltype;
181 fulltype = _getFullType(type);
182 UT_return_val_if_fail(fulltype != NULL, NULL);
183 return gsf_open_pkg_open_rel_by_type(parent, fulltype, NULL);
184 }
185
parseChildById(GsfInput * parent,const char * id,OXMLi_StreamListener * pListener)186 UT_Error OXMLi_PackageManager::parseChildById( GsfInput * parent, const char * id, OXMLi_StreamListener * pListener)
187 {
188 GsfInput * pInput = getChildById(parent, id);
189 UT_return_val_if_fail(pInput != NULL, UT_ERROR);
190 return _parseStream( pInput, pListener);
191 }
192
parseChildByType(GsfInput * parent,OXML_PartType type,OXMLi_StreamListener * pListener)193 UT_Error OXMLi_PackageManager::parseChildByType( GsfInput * parent, OXML_PartType type, OXMLi_StreamListener * pListener)
194 {
195 GsfInput * pInput = getChildByType(parent, type);
196 if(!pInput)
197 return UT_ERROR;
198
199 return _parseStream( pInput, pListener);
200 }
201
_getFullType(OXML_PartType type)202 const char * OXMLi_PackageManager::_getFullType( OXML_PartType type )
203 { //There's probably a better way to do this...
204 const char * ret;
205 switch (type)
206 {
207 case ALTERNATEFORMAT_PART:
208 ret = ALTERNATEFORMAT_REL_TYPE;
209 break;
210 case COMMENTS_PART:
211 ret = COMMENTS_REL_TYPE;
212 break;
213 case DOCSETTINGS_PART:
214 ret = DOCSETTINGS_REL_TYPE;
215 break;
216 case DOCUMENT_PART:
217 ret = DOCUMENT_REL_TYPE;
218 break;
219 case ENDNOTES_PART:
220 ret = ENDNOTES_REL_TYPE;
221 break;
222 case FONTTABLE_PART:
223 ret = FONTTABLE_REL_TYPE;
224 break;
225 case FOOTER_PART:
226 ret = FOOTER_REL_TYPE;
227 break;
228 case FOOTNOTES_PART:
229 ret = FOOTNOTES_REL_TYPE;
230 break;
231 case GLOSSARY_PART:
232 ret = GLOSSARY_REL_TYPE;
233 break;
234 case HEADER_PART:
235 ret = HEADER_REL_TYPE;
236 break;
237 case NUMBERING_PART:
238 ret = NUMBERING_REL_TYPE;
239 break;
240 case STYLES_PART:
241 ret = STYLES_REL_TYPE;
242 break;
243 case WEBSETTINGS_PART:
244 ret = WEBSETTINGS_REL_TYPE;
245 break;
246 case IMAGE_PART:
247 ret = IMAGE_REL_TYPE;
248 break;
249 case THEME_PART:
250 ret = THEME_REL_TYPE;
251 break;
252 default:
253 ret = NULL;
254 }
255 return ret;
256 }
257
_getDocumentStream()258 GsfInput * OXMLi_PackageManager::_getDocumentStream()
259 {
260 UT_return_val_if_fail(m_pPkg != NULL, NULL);
261
262 if (m_pDocPart == NULL)
263 m_pDocPart = getChildByType ( GSF_INPUT (m_pPkg), DOCUMENT_PART );
264 return m_pDocPart;
265 }
266
_parseStream(GsfInput * stream,OXMLi_StreamListener * pListener)267 UT_Error OXMLi_PackageManager::_parseStream( GsfInput * stream, OXMLi_StreamListener * pListener)
268 {
269 UT_return_val_if_fail(stream != NULL && pListener != NULL , UT_ERROR);
270
271 //First, we check if this stream has already been parsed before
272 std::string part_name = gsf_input_name(stream); //TODO: determine if part names are truly unique
273 std::map<std::string, bool>::iterator it;
274 it = m_parsedParts.find(part_name);
275 if (it != m_parsedParts.end() && it->second) {
276 //this stream has already been parsed successfully
277 return UT_OK;
278 }
279
280 UT_Error ret = UT_OK;
281 guint8 const *data = NULL;
282 const char * cdata = NULL;
283 size_t len = 0;
284
285 UT_XML reader;
286 reader.setListener(pListener);
287
288 if (gsf_input_size (stream) > 0) {
289 len = gsf_input_remaining (stream);
290 if (len > 0) {
291 data = gsf_input_read (stream, len, NULL);
292 if (NULL == data) {
293 g_object_unref (G_OBJECT (stream));
294 return UT_ERROR;
295 }
296 cdata = (const char *)data;
297 ret = reader.parse (cdata, len);
298 }
299 }
300
301 //There are two error codes to check here.
302 if (ret == UT_OK && pListener->getStatus() == UT_OK)
303 m_parsedParts[part_name] = true;
304
305 //We prioritize the one from UT_XML when returning.
306 return ret == UT_OK ? pListener->getStatus() : ret;
307 }
308
309 /**
310 * Parses the image stream and returns the image data
311 */
parseImageStream(const char * id)312 UT_ByteBuf* OXMLi_PackageManager::parseImageStream(const char * id)
313 {
314 GsfInput * parent = _getDocumentStream();
315 GsfInput * stream = getChildById(parent, id);
316
317 //First, we check if this stream has already been parsed before
318 std::string part_name = gsf_input_name(stream); //TODO: determine if part names are truly unique
319 std::map<std::string, bool>::iterator it;
320 it = m_parsedParts.find(part_name);
321 if (it != m_parsedParts.end() && it->second) {
322 //this stream has already been parsed successfully
323 return NULL;
324 }
325
326 UT_ByteBuf* buffer = new UT_ByteBuf();
327 buffer->insertFromInput(0, stream);
328 g_object_unref (G_OBJECT (stream));
329
330 m_parsedParts[part_name] = true;
331
332 return buffer;
333 }
334
335 /**
336 * This function is needed for external targets. Ex: hyperlinks, bookmarks.
337 */
getPartName(const char * id)338 std::string OXMLi_PackageManager::getPartName(const char * id)
339 {
340 GsfInput * parent = _getDocumentStream();
341 const char* target = gsf_open_pkg_rel_get_target(gsf_open_pkg_lookup_rel_by_id(parent, id));
342 return std::string(target);
343 }
344
345