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