1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 
3 /* AbiWord
4  * Copyright (C) 1998 AbiSource, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19  * 02110-1301 USA.
20  */
21 
22 #include <ctype.h>
23 #include "ut_types.h"
24 #include "ut_misc.h"
25 #include "ut_string.h"
26 #include "ut_assert.h"
27 #include "ut_debugmsg.h"
28 #include "ut_growbuf.h"
29 #include "pt_PieceTable.h"
30 #include "pf_Frag.h"
31 #include "pf_Frag_Object.h"
32 #include "pf_Frag_FmtMark.h"
33 #include "pf_Frag_Strux.h"
34 #include "pf_Frag_Strux_Block.h"
35 #include "pf_Frag_Strux_Section.h"
36 #include "pf_Frag_Text.h"
37 #include "pf_Fragments.h"
38 #include "px_ChangeRecord.h"
39 #include "px_CR_Span.h"
40 #include "px_CR_SpanChange.h"
41 #include "px_CR_Strux.h"
42 
43 /****************************************************************/
44 /****************************************************************/
45 
appendStrux(PTStruxType pts,const gchar ** attributes,pf_Frag_Strux ** ppfs_ret)46 bool pt_PieceTable::appendStrux(PTStruxType pts, const gchar ** attributes, pf_Frag_Strux ** ppfs_ret)
47 {
48 	pf_Frag_Strux * pfs = NULL;
49 	if(!_makeStrux(pts, attributes, pfs) || !pfs)
50 		return false;
51 
52 	if(attributes)
53 	{
54 		const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
55 		UT_uint32 iXID = 0;
56 		if(pXID && *pXID)
57 		{
58 			iXID = atoi(pXID);
59 			pfs->setXID(iXID);
60 		}
61 	}
62 
63 	pf_Frag * pfPrev = m_fragments.getLast();
64 	bool bDoInsertFmt = false;
65 	if(pfPrev != NULL && pfPrev->getType() == pf_Frag::PFT_Strux)
66 	{
67 		pf_Frag_Strux * pfsPrev = static_cast<pf_Frag_Strux *>(pfPrev);
68 		if(pfsPrev->getStruxType() == PTX_Block)
69 		{
70 			bDoInsertFmt = true;
71 		}
72 	}
73 	m_fragments.appendFrag(pfs);
74 	// insert frag in the embedded_strux list if needed
75 	if ((pts == PTX_EndFootnote) || (pts == PTX_EndEndnote) || (pts == PTX_EndAnnotation))
76 	{
77 		_insertNoteInEmbeddedStruxList(pfs);
78 	}
79 
80 	if(bDoInsertFmt)
81 	{
82 		insertFmtMarkBeforeFrag(static_cast<pf_Frag *>(pfs));
83 	}
84 	if (ppfs_ret)
85 		*ppfs_ret = pfs;
86 	return true;
87 }
88 
89 /**
90  * MIQ11: Extends the old _findLastStruxOfType adding a stopCondition
91  * for failure and returning a Strux* directly in the case of success.
92  * This is like a findBackwards() from a fragment.
93  *
94  * stopConditions must be terminated with a PTX_StruxDummy entry like:
95  * PTStruxType stopCondition[] = { PTX_SectionTable, PTX_StruxDummy };
96  *
97  * Find a fragment of strux type pst looking backwards from pfStart.
98  * If a strux fragment matching the stopCondition is found first then
99  * the function stops and returns 0. If no fragment with pst is found
100  * then 0 is returned.
101  *
102  * MAYBE: extend this again to take yes() and no() functors so a
103  *    function can call _findLastStruxOfType() and decide what is ok
104  *    and what is not using those.
105  *    boost::lambda would be handy to simplify the functors?
106  */
_findLastStruxOfType(pf_Frag * pfStart,PTStruxType pst,PTStruxType * stopConditions,bool bSkipEmbededSections)107 pf_Frag_Strux* pt_PieceTable::_findLastStruxOfType( pf_Frag * pfStart,
108                                                     PTStruxType pst,
109                                                     PTStruxType* stopConditions,
110                                                     bool bSkipEmbededSections )
111 {
112 	UT_return_val_if_fail( pfStart, NULL );
113 
114 	pf_Frag * pf = pfStart;
115     PTStruxType* stopConditionsBegin = stopConditions;
116     PTStruxType* stopConditionsEnd   = stopConditions;
117     while( *stopConditionsEnd != PTX_StruxDummy )
118         ++stopConditionsEnd;
119 
120     while(pf)
121 	{
122 		if(pf->getType() == pf_Frag::PFT_Strux)
123 		{
124 			pf_Frag_Strux * pfs2 = static_cast<pf_Frag_Strux*>(pf);
125 
126             PTStruxType eStruxType = pfs2->getStruxType();
127 
128 			if( eStruxType == pst)
129                 return pfs2;
130 
131             if( stopConditionsEnd !=
132                 std::find( stopConditionsBegin, stopConditionsEnd, eStruxType ))
133             {
134                 return 0;
135             }
136 
137 			if(bSkipEmbededSections)
138 			{
139 				if(pfs2->getStruxType() == PTX_EndTOC)
140 				{
141 					while(pf)
142 					{
143 						if(pf->getType() == pf_Frag::PFT_Strux)
144 						{
145 							pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
146 
147 							if(pfs->getStruxType() == PTX_SectionTOC)
148 								break;
149 						}
150 
151 						pf = pf->getPrev();
152 					}
153 				}
154 				if(pfs2->getStruxType() == PTX_EndFrame)
155 				{
156 					while(pf)
157 					{
158 						if(pf->getType() == pf_Frag::PFT_Strux)
159 						{
160 							pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
161 
162 							if(pfs->getStruxType() == PTX_SectionFrame)
163 								break;
164 						}
165 
166 						pf = pf->getPrev();
167 					}
168 				}
169 
170 				if(pfs2->getStruxType() == PTX_EndEndnote)
171 				{
172 					while(pf)
173 					{
174 						if(pf->getType() == pf_Frag::PFT_Strux)
175 						{
176 							pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
177 
178 							if(pfs->getStruxType() == PTX_SectionEndnote)
179 								break;
180 						}
181 
182 						pf = pf->getPrev();
183 					}
184 				}
185 				if(pfs2->getStruxType() == PTX_EndFootnote)
186 				{
187 					while(pf)
188 					{
189 						if(pf->getType() == pf_Frag::PFT_Strux)
190 						{
191 							pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
192 
193 							if(pfs->getStruxType() == PTX_SectionFootnote)
194 								break;
195 						}
196 
197 						pf = pf->getPrev();
198 					}
199 				}
200 				if(pfs2->getStruxType() == PTX_EndMarginnote)
201 				{
202 					while(pf)
203 					{
204 						if(pf->getType() == pf_Frag::PFT_Strux)
205 						{
206 							pf_Frag_Strux * pfs = static_cast<pf_Frag_Strux*>(pf);
207 
208 							if(pfs->getStruxType() == PTX_SectionMarginnote)
209 								break;
210 						}
211 
212 						pf = pf->getPrev();
213 					}
214 				}
215 			}
216 		}
217 		if(pf)
218 			pf = pf->getPrev();
219 	}
220 
221 	return 0;
222 }
223 
224 
225 
_findLastStruxOfType(pf_Frag * pfStart,PTStruxType pst,bool bSkipEmbededSections)226 pf_Frag_Strux* pt_PieceTable::_findLastStruxOfType( pf_Frag * pfStart,
227                                                     PTStruxType pst,
228                                                     bool bSkipEmbededSections )
229 {
230 	UT_return_val_if_fail( pfStart, NULL );
231     PTStruxType stopCondition[] = { PTX_StruxDummy };
232     return _findLastStruxOfType( pfStart, pst, stopCondition, bSkipEmbededSections );
233 }
234 
235 
236 /*!
237     Changes formating of the last strux of type pts
238     bSkipEmbededSections indicates whether when an end of an embeded section is
239     encountered, the entire section is to be skipped over, for example if the end of the
240     document looks like
241 
242     <p><footnote><p></p></footnote>
243 
244     when searching for <p> if bSkipEmbededSections == true the paragraph before <footnote>
245     will be modified
246 */
appendLastStruxFmt(PTStruxType pst,const gchar ** attributes,const gchar ** props,bool bSkipEmbededSections)247 bool pt_PieceTable::appendLastStruxFmt(PTStruxType pst, const gchar ** attributes, const gchar ** props,
248 									   bool bSkipEmbededSections)
249 {
250 	// can only be used while loading the document
251 	UT_return_val_if_fail (m_pts==PTS_Loading,false);
252 
253 	// Only a strux can be appended to an empty document
254 	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
255 	if (!m_fragments.getFirst())
256 		return false;
257 
258 	pf_Frag * pf = m_fragments.getLast();
259 
260 	UT_return_val_if_fail ( pf, false );
261 
262 	pf = _findLastStruxOfType(pf, pst, bSkipEmbededSections);
263 
264 	UT_return_val_if_fail( pf, false );
265 
266 	PT_AttrPropIndex currentAP = pf->getIndexAP();
267 
268 	const PP_AttrProp * pOldAP;
269     if(!getAttrProp(currentAP,&pOldAP))
270 		return false;
271 
272 	PP_AttrProp * pNewAP = pOldAP->cloneWithReplacements(attributes,props,false);
273 	pNewAP->markReadOnly();
274 
275 	PT_AttrPropIndex indexAP;
276 	if (!m_varset.addIfUniqueAP(pNewAP,&indexAP))
277 		return false;
278 
279 	pf->setIndexAP(indexAP);
280 
281 	return true;
282 }
283 
284 /*!
285     As above, but props represented by a single XML string
286 
287 */
appendLastStruxFmt(PTStruxType pst,const gchar ** attributes,const gchar * props,bool bSkipEmbededSections)288 bool pt_PieceTable::appendLastStruxFmt(PTStruxType pst, const gchar ** attributes, const gchar * props,
289 									   bool bSkipEmbededSections)
290 {
291 	if(props && *props)
292 	{
293 		// we parse the xml props string into separate field by simply duplicating it and then
294 		// replacing ; and : with '0';
295 
296 		// foolproofing
297 		if(*props == ';')
298 			props++;
299 
300 		char * pProps = g_strdup(props);
301 
302 		const gchar ** pPropsArray = UT_splitPropsToArray(pProps);
303 		UT_return_val_if_fail( pPropsArray, false );
304 
305 		bool bRet = appendLastStruxFmt(pst, attributes, pPropsArray, bSkipEmbededSections);
306 
307 		delete [] pPropsArray;
308 		FREEP(pProps);
309 
310 		return bRet;
311 	}
312 	else
313 	{
314 		const gchar ** pPropsArray = NULL;
315 		return appendLastStruxFmt(pst, attributes, pPropsArray, bSkipEmbededSections);
316 	}
317 }
318 
319 /*! changes formatting of a strux while loading document */
appendStruxFmt(pf_Frag_Strux * pfs,const gchar ** attributes)320 bool pt_PieceTable::appendStruxFmt(pf_Frag_Strux * pfs, const gchar ** attributes)
321 {
322 	// can only be used while loading the document
323 	UT_return_val_if_fail (m_pts==PTS_Loading,false);
324 
325 	// Only a strux can be appended to an empty document
326 	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
327 	if (!m_fragments.getFirst())
328 		return false;
329 
330 	UT_return_val_if_fail ( pfs, false );
331 
332 	PT_AttrPropIndex currentAP = pfs->getIndexAP();
333 
334 	const PP_AttrProp * pOldAP;
335     if(!getAttrProp(currentAP,&pOldAP))
336 		return false;
337 
338 	PP_AttrProp * pNewAP = pOldAP->cloneWithReplacements(attributes,NULL,true);
339 	pNewAP->markReadOnly();
340 
341 	PT_AttrPropIndex indexAP;
342 	if (!m_varset.addIfUniqueAP(pNewAP,&indexAP))
343 		return false;
344 
345 	pfs->setIndexAP(indexAP);
346 
347 	return true;
348 }
349 
appendFmt(const gchar ** attributes)350 bool pt_PieceTable::appendFmt(const gchar ** attributes)
351 {
352 	// can only be used while loading the document
353 	UT_return_val_if_fail (m_pts==PTS_Loading, false);
354 
355 	// Only a strux can be appended to an empty document
356 	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
357 
358 	// create a new Attribute/Property structure in the table
359 	// and set the current index to it.  the next span of text
360 	// (in this block) that comes in will then be set to these
361 	// attributes/properties.  becase we are loading, we do not
362 	// create a Fragment or a ChangeRecord.  (Formatting changes
363 	// are implicit at this point in time.)
364 
365 
366 	if (!m_varset.storeAP(attributes,&loading.m_indexCurrentInlineAP))
367 		return false;
368 
369 	return true;
370 }
371 
appendFmt(const UT_GenericVector<const gchar * > * pVecAttributes)372 bool pt_PieceTable::appendFmt(const UT_GenericVector<const gchar*> * pVecAttributes)
373 {
374 	// can only be used while loading the document
375 	UT_return_val_if_fail (m_pts==PTS_Loading, false);
376 
377 	// Only a strux can be appended to an empty document
378 	UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
379 
380 	if (!m_varset.storeAP(pVecAttributes,&loading.m_indexCurrentInlineAP))
381 		return false;
382 
383 	return true;
384 }
385 
appendSpan(const UT_UCSChar * pbuf,UT_uint32 length)386 bool pt_PieceTable::appendSpan(const UT_UCSChar * pbuf, UT_uint32 length)
387 {
388 	// can only be used while loading the document
389 	UT_return_val_if_fail (m_pts==PTS_Loading, false);
390 
391 	// Only a strux can be appended to an empty document
392 	UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
393 
394 	// append the text data to the end of the buffer.
395 
396 	PT_BufIndex bi;
397 	if (!m_varset.appendBuf(pbuf,length,&bi))
398 		return false;
399 
400 	// set the formatting Attributes/Properties to that
401 	// of the last fmt set in this paragraph.
402 
403 	// see if this span can be appended to the previous fragment
404 	// (perhaps the parser was a bit lazy in chunking up the data).
405 
406 	pf_Frag * pfLast = m_fragments.getLast();
407 	if ((pfLast != NULL) && (pfLast->getType() == pf_Frag::PFT_Text))
408 	{
409 		pf_Frag_Text * pfLastText = static_cast<pf_Frag_Text *>(pfLast);
410 		if (   (pfLastText->getIndexAP() == loading.m_indexCurrentInlineAP)
411 			&& m_varset.isContiguous(pfLastText->getBufIndex(),pfLastText->getLength(),bi))
412 		{
413 			pfLastText->changeLength(pfLastText->getLength() + length);
414 			return true;
415 		}
416 	}
417 
418 	// could not coalesce, so create a new fragment for this text span.
419 
420 	pf_Frag_Text * pft = new pf_Frag_Text(this,bi,length,loading.m_indexCurrentInlineAP,NULL);
421 	if (!pft)
422 		return false;
423 
424 	m_fragments.appendFrag(pft);
425 
426 	// because we are loading, we do not create change
427 	// records or any of the other stuff that an insertSpan
428 	// would do.
429 
430 	return true;
431 }
432 
appendObject(PTObjectType pto,const gchar ** attributes)433 bool pt_PieceTable::appendObject(PTObjectType pto, const gchar ** attributes)
434 {
435 	pf_Frag_Object * pfo = NULL;
436 	if(!_makeObject(pto,attributes,pfo) || !pfo)
437 		return false;
438 
439 	if(attributes)
440 	{
441 		const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
442 		UT_uint32 iXID = 0;
443 		if(pXID && *pXID)
444 		{
445 			iXID = atoi(pXID);
446 			pfo->setXID(iXID);
447 		}
448 	}
449 
450 	m_fragments.appendFrag(pfo);
451 	return true;
452 }
453 
appendFmtMark(void)454 bool pt_PieceTable::appendFmtMark(void)
455 {
456 	pf_Frag_FmtMark * pff = NULL;
457 	if (!_makeFmtMark(pff) || !pff)
458 		return false;
459 
460 	m_fragments.appendFrag(pff);
461 	return true;
462 }
463 
insertStruxBeforeFrag(pf_Frag * pF,PTStruxType pts,const gchar ** attributes,pf_Frag_Strux ** ppfs_ret)464 bool pt_PieceTable::insertStruxBeforeFrag(pf_Frag * pF, PTStruxType pts,
465 										  const gchar ** attributes, pf_Frag_Strux ** ppfs_ret)
466 {
467 	UT_return_val_if_fail(pF , false);
468 
469 	pf_Frag_Strux * pfs = NULL;
470 	if(!_makeStrux(pts, attributes, pfs) || !pfs)
471 		return false;
472 
473 	if(attributes)
474 	{
475 		const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
476 		UT_uint32 iXID = 0;
477 		if(pXID && *pXID)
478 		{
479 			iXID = atoi(pXID);
480 			pfs->setXID(iXID);
481 		}
482 	}
483 
484 	m_fragments.insertFragBefore(pF, pfs);
485 	if (ppfs_ret)
486 		*ppfs_ret = pfs;
487 	// insert frag in the embedded_strux list if needed
488 	if ((pts == PTX_EndFootnote) || (pts == PTX_EndEndnote) || (pts == PTX_EndAnnotation))
489 	{
490 		_insertNoteInEmbeddedStruxList(pfs);
491 	}
492 
493 	return true;
494 }
495 
496 
insertSpanBeforeFrag(pf_Frag * pf,const UT_UCSChar * p,UT_uint32 length)497 bool pt_PieceTable::insertSpanBeforeFrag(pf_Frag * pf, const UT_UCSChar * p, UT_uint32 length)
498 {
499 	// can only be used while loading the document
500 	UT_return_val_if_fail (m_pts==PTS_Loading, false);
501 
502 	// Only a strux can be appended to an empty document
503 	UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
504 
505 	// cannot insert before first fragment (i.e., span cannot start a document)
506 	UT_return_val_if_fail(pf && pf->getPrev() && pf != m_fragments.getFirst(), false);
507 
508 	// append the text to the buffer
509 	PT_BufIndex bi;
510 	if (!m_varset.appendBuf(p,length,&bi))
511 		return false;
512 
513 	// update the fragment and/or the fragment list.
514 	// return true if successful.
515 
516 	pf_Frag_Text * pft = NULL;
517 
518 	// see if the fragement before this one is a text frag ...
519 	if (pf->getPrev()->getType() == pf_Frag::PFT_Text)
520 	{
521 		pft = static_cast<pf_Frag_Text *>(pf->getPrev());
522 	}
523 
524 	if (pft)
525 	{
526 		// We have a text frag on the left.  Try to coalesce this
527 		// character data with an existing fragment.
528 
529 		if((pft->getIndexAP() == loading.m_indexCurrentInlineAP) &&
530 		   m_varset.isContiguous(pft->getBufIndex(),pft->getLength(),bi))
531 		{
532 			// new text is contiguous, we just update the length of this fragment.
533 			pft->changeLength(pft->getLength()+length);
534 
535 			// see if this (enlarged) fragment is now contiguous with the
536 			// one that follows -- it cannot be when we are appending
537 			return true;
538 		}
539 	}
540 
541 	// new text is not contiguous on the left, we need to insert a new text
542 	// fragment into the list.  first we construct a new text fragment
543 	// for the data that we inserted.
544 
545 	pf_Frag_Text * pftNew = new pf_Frag_Text(this,bi,length,loading.m_indexCurrentInlineAP,NULL);
546 	if (!pftNew)
547 		return false;
548 
549 	m_fragments.insertFragBefore(pf,pftNew);
550 
551 	// no need to check for the new frag being continguous with the
552 	// one on its right -- it cannot be, since the insertion occured in
553 	// oposite order than the fargments have in the buffer
554 
555 	return true;
556 }
557 
insertObjectBeforeFrag(pf_Frag * pF,PTObjectType pto,const gchar ** attributes)558 bool pt_PieceTable::insertObjectBeforeFrag(pf_Frag * pF, PTObjectType pto,
559 										   const gchar ** attributes)
560 {
561 	// cannot insert before first fragment
562 	UT_return_val_if_fail(pF && pF->getPrev() && pF != m_fragments.getFirst(), false);
563 
564 	pf_Frag_Object * pfo = NULL;
565 	if(!_makeObject(pto,attributes,pfo) || !pfo)
566 		return false;
567 
568 	if(attributes)
569 	{
570 		const gchar * pXID = UT_getAttribute(PT_XID_ATTRIBUTE_NAME, attributes);
571 		UT_uint32 iXID = 0;
572 		if(pXID && *pXID)
573 		{
574 			iXID = atoi(pXID);
575 			pfo->setXID(iXID);
576 		}
577 	}
578 
579 	m_fragments.insertFragBefore(pF, pfo);
580 	return true;
581 }
582 
insertFmtMarkBeforeFrag(pf_Frag * pF)583 bool pt_PieceTable::insertFmtMarkBeforeFrag(pf_Frag * pF)
584 {
585 	// cannot insert before first fragment
586 	UT_return_val_if_fail(pF && pF->getPrev() && pF != m_fragments.getFirst(), false);
587 
588 	pf_Frag_FmtMark * pff = NULL;
589 	if (!_makeFmtMark(pff) || !pff)
590 		return false;
591 
592 	m_fragments.insertFragBefore(pF, pff);
593 	return true;
594 }
595 
596 
insertFmtMarkBeforeFrag(pf_Frag * pF,const gchar ** attributes)597 bool pt_PieceTable::insertFmtMarkBeforeFrag(pf_Frag * pF, const gchar ** attributes)
598 {
599 	// cannot insert before first fragment
600 	UT_return_val_if_fail(pF && pF->getPrev() && pF != m_fragments.getFirst(), false);
601 
602 	pf_Frag_FmtMark * pff = NULL;
603 	if (!_makeFmtMark(pff,attributes) || !pff)
604 		return false;
605 
606 	m_fragments.insertFragBefore(pF, pff);
607 	return true;
608 }
609 
_makeStrux(PTStruxType pts,const gchar ** attributes,pf_Frag_Strux * & pfs)610 bool pt_PieceTable::_makeStrux(PTStruxType pts, const gchar ** attributes, pf_Frag_Strux * &pfs)
611 {
612 	// create a new structure fragment at the current end of the document.
613 	// this function can only be called while loading the document.
614 	UT_return_val_if_fail (m_pts==PTS_Loading, false);
615 
616 	// first, store the attributes and properties and get an index to them.
617 
618 	PT_AttrPropIndex indexAP;
619 	if (!m_varset.storeAP(attributes,&indexAP))
620 		return false;
621 
622 	//
623 	// OK we've got to interogate attributes to determine what sort of section strux
624 	// we have.
625 	//
626 	if((pts == PTX_Section) && (attributes != NULL))
627 	{
628 		const char * szStruxType = UT_getAttribute("type",attributes);
629 		if(szStruxType)
630 		{
631 			if(strcmp(szStruxType,"header") == 0 ||
632 			   strcmp(szStruxType,"footer") == 0 ||
633 			   strcmp(szStruxType,"header-even") == 0 ||
634 			   strcmp(szStruxType,"footer-even") == 0 ||
635 			   strcmp(szStruxType,"header-first") == 0 ||
636 			   strcmp(szStruxType,"footer-first") == 0 ||
637 			   strcmp(szStruxType,"header-last") == 0 ||
638 			   strcmp(szStruxType,"footer-last") == 0)
639 			{
640 				pts = PTX_SectionHdrFtr;
641 			}
642 	    }
643 	}
644 	if (!_createStrux(pts,indexAP,&pfs))
645 		return false;
646 
647 	return true;
648 }
649 
650 
_makeObject(PTObjectType pto,const gchar ** attributes,pf_Frag_Object * & pfo)651 bool pt_PieceTable::_makeObject(PTObjectType pto, const gchar ** attributes, pf_Frag_Object * &pfo)
652 {
653 	// create a new object fragment at the current end of the document.
654 	// this function can only be called while loading the document.
655 	UT_return_val_if_fail (m_pts==PTS_Loading, false);
656 
657 	// Only a strux can be appended to an empty document
658 	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
659 
660 	// first, store the attributes and properties and get an index to them.
661 
662 	PT_AttrPropIndex indexAP;
663 	if (!m_varset.storeAP(attributes,&indexAP))
664 		return false;
665 
666 	if (!_createObject(pto,indexAP,&pfo))
667 		return false;
668 
669 	return true;
670 }
671 
_makeFmtMark(pf_Frag_FmtMark * & pff)672 bool pt_PieceTable::_makeFmtMark(pf_Frag_FmtMark * &pff)
673 {
674 	// this function can only be called while loading the document.
675 	UT_return_val_if_fail (m_pts==PTS_Loading,false);
676 
677 	// Only a strux can be appended to an empty document
678 	UT_return_val_if_fail (NULL != m_fragments.getFirst(),false);
679 
680 	pff = new pf_Frag_FmtMark(this,loading.m_indexCurrentInlineAP);
681 	if (!pff)
682 		return false;
683 
684 	return true;
685 }
686 
687 
_makeFmtMark(pf_Frag_FmtMark * & pff,const gchar ** attributes)688 bool pt_PieceTable::_makeFmtMark(pf_Frag_FmtMark * &pff, const gchar ** attributes)
689 {
690 	// this function can only be called while loading the document.
691 	UT_return_val_if_fail (m_pts==PTS_Loading,false);
692 
693 	// Only a strux can be appended to an empty document
694 	UT_return_val_if_fail (NULL != m_fragments.getFirst(), false);
695 	if(attributes == NULL)
696 		{
697 			return _makeFmtMark(pff);
698 		}
699 	PT_AttrPropIndex indexAP;
700 	if (!m_varset.storeAP(attributes,&indexAP))
701 		return false;
702 
703 	pff = new pf_Frag_FmtMark(this,indexAP);
704 	if (!pff)
705 		return false;
706 
707 	return true;
708 }
709