Exemple #1
0
/*! \fn bool PP_AttrProp::explodeStyle(const PD_Document * pDoc, bool bOverwrite)
	 \brief This function transfers attributes and properties defined in style into the AP.
    \param bOverwrite indicates what happens if the property/attribute is already present. If false \
     (default) the style definition is ignored; if true the style value overrides the present value.
*/
bool PP_AttrProp::explodeStyle(const PD_Document * pDoc, bool bOverwrite)
{
	UT_return_val_if_fail(pDoc,false);
	
	// expand style if present
	const gchar * pszStyle = NULL;
	if(getAttribute(PT_STYLE_ATTRIBUTE_NAME, pszStyle))
	{
		PD_Style * pStyle = NULL;

        if(pszStyle && (strcmp(pszStyle, "None") != 0) && pDoc->getStyle(pszStyle,&pStyle))
        {
			UT_Vector vAttrs;
			UT_Vector vProps;

			UT_sint32 i;

			pStyle->getAllAttributes(&vAttrs, 100);
			pStyle->getAllProperties(&vProps, 100);

			for(i = 0; i < vProps.getItemCount(); i += 2)
			{
				const gchar * pName =  (const gchar *)vProps.getNthItem(i);
				const gchar * pValue = (const gchar *)vProps.getNthItem(i+1);
				const gchar * p;

				bool bSet = bOverwrite || !getProperty(pName, p);

				if(bSet)
					setProperty(pName, pValue);
			}

			// attributes are more complicated, because there are some style attributes that must
			// not be transferred to the generic AP
			for(i = 0; i < vAttrs.getItemCount(); i += 2)
			{
				const gchar * pName = (const gchar *)vAttrs.getNthItem(i);
				if(!pName || !strcmp(pName, "type")
				          || !strcmp(pName, "name")
				          || !strcmp(pName, "basedon")
				          || !strcmp(pName, "followedby")
 				          || !strcmp(pName, "props"))
				{
					continue;
				}

				const gchar * pValue = (const gchar *)vAttrs.getNthItem(i+1);
				const gchar * p;

				bool bSet = bOverwrite || !getAttribute(pName, p);

				if(bSet)
					setAttribute(pName, pValue);
			}
		}
	}

	return true;
}
/*!
 * This method sets all the local properties from a vector of pointers
 * to const gchar * strings of Property - Value pairs.
 * This method wipes out all the old values and clears all the bools
 * assciated with them.
 */
void XAP_Dialog_FontChooser::setAllPropsFromVec(const UT_Vector & vProps)
{
	UT_sint32 remCount = vProps.getItemCount();
	if(remCount <= 0)
		return;
	// BAD BAD, we have wrong count
	UT_ASSERT_HARMLESS(remCount % 2 == 0);
	if(remCount % 2) {
		remCount--;
	}
	m_mapProps.clear();
	UT_sint32 i = 0;
	for(i=0; i< remCount; i+=2)
	{
		m_mapProps.insert(std::make_pair((const char*)vProps.getNthItem(i), 
										 (const char*)vProps.getNthItem(i+1)));
	}
//
// Do the Text decorations
//
	const std::string sDecor = getVal("text-decoration");
	m_bUnderline = (NULL != strstr(sDecor.c_str(),"underline"));
	m_bOverline = (NULL != strstr(sDecor.c_str(),"overline"));
	m_bStrikeout = (NULL != strstr(sDecor.c_str(),"line-through"));
	m_bTopline = (NULL != strstr(sDecor.c_str(),"topline"));
	m_bBottomline = (NULL != strstr(sDecor.c_str(),"bottomline"));

	const std::string sDisplay = getVal("display");
	m_bHidden = !strcmp(sDisplay.c_str(),"none");
	
	const std::string sPosition = getVal("text-position");
	m_bSuperScript = strcmp(sPosition.c_str(),"superscript")==0;
	m_bSubScript = strcmp(sPosition.c_str(),"subscript")==0;
}
bool AP_Dialog_Paragraph::getDialogData(const gchar **& pProps)
{
	UT_Vector v;

	struct propPair
	{
		gchar * prop;
		gchar * val;
	};

	propPair * p;

	// only do this if the control has a proper value
	if (_wasChanged(id_MENU_ALIGNMENT)  && _getMenuItemValue(id_MENU_ALIGNMENT))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("text-align");

		switch (_getMenuItemValue(id_MENU_ALIGNMENT))
		{
			case align_LEFT:
				p->val = g_strdup("left");
				break;
			case align_CENTERED:
				p->val = g_strdup("center");
				break;
			case align_RIGHT:
				p->val = g_strdup("right");
				break;
			case align_JUSTIFIED:
				p->val = g_strdup("justify");
				break;
			default:
				UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
		}
		v.addItem(p);
	}


	if (_wasChanged(id_CHECK_DOMDIRECTION))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("dom-dir");

		if (_getCheckItemValue(id_CHECK_DOMDIRECTION) == check_TRUE)
			p->val = g_strdup("rtl");
		else
			p->val = g_strdup("ltr");

		v.addItem(p);

	}


	if (_wasChanged(id_SPIN_LEFT_INDENT))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("margin-left");
		p->val = g_strdup(_getSpinItemValue(id_SPIN_LEFT_INDENT));

		v.addItem(p);
	}

	if (_wasChanged(id_SPIN_RIGHT_INDENT))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("margin-right");
		p->val = g_strdup(_getSpinItemValue(id_SPIN_RIGHT_INDENT));

		v.addItem(p);
	}

	// TODO : The logic here might not be bulletproof.  If the user triggers
	// TODO : a change in the TYPE of special indent (hanging, first line,
	// TODO : none), we will always save what's in the box as a property.
	// TODO : One could make it smarter with a stronger contract with
	// TODO : the platform interfaces.

	if (_getMenuItemValue(id_MENU_SPECIAL_INDENT) &&
		(_wasChanged(id_MENU_SPECIAL_INDENT) || _wasChanged(id_SPIN_SPECIAL_INDENT)))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("text-indent");

		tIndentState i = (tIndentState) _getMenuItemValue(id_MENU_SPECIAL_INDENT);

		if (i == indent_NONE)
			p->val = g_strdup(UT_convertInchesToDimensionString(m_dim, 0));
		else if (i == indent_FIRSTLINE)
			p->val = g_strdup(_getSpinItemValue(id_SPIN_SPECIAL_INDENT));
		else if (i == indent_HANGING)
		{
			// we have to flip the sign for "hanging" indents to a negative quantity for
			// storage in the document as a text-indent

			// get with no dimension
			UT_Dimension dim = UT_determineDimension(_getSpinItemValue(id_SPIN_SPECIAL_INDENT));
			double val = UT_convertDimensionless(_getSpinItemValue(id_SPIN_SPECIAL_INDENT));
			// Convert to inches
			val = UT_convertDimToInches(val, dim);

			// flip sign
			val = val * (double) -1;

			// store the reconstructed
			p->val = g_strdup(UT_convertInchesToDimensionString(dim, val));
		}

		v.addItem(p);
	}

	if (_wasChanged(id_SPIN_BEFORE_SPACING))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("margin-top");
		p->val = g_strdup(_getSpinItemValue(id_SPIN_BEFORE_SPACING));

		v.addItem(p);
	}

	if (_wasChanged(id_SPIN_AFTER_SPACING))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("margin-bottom");
		p->val = g_strdup(_getSpinItemValue(id_SPIN_AFTER_SPACING));

		v.addItem(p);
	}

	// TODO : The logic here might not be bulletproof.  If the user triggers
	// TODO : a change in the TYPE of special indent (single, double, etc.)
	// TODO : we will always save what's in the box as a property.
	// TODO : One could make it smarter with a stronger contract with
	// TODO : the platform interfaces.

	if(_getMenuItemValue(id_MENU_SPECIAL_SPACING) &&
		 (_wasChanged(id_MENU_SPECIAL_SPACING) || _wasChanged(id_SPIN_SPECIAL_SPACING)))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("line-height");

		// normal spacings (single, 1.5, double) are just simple numbers.
		// "at least" needs a "+" at the end of the number (no units).
		// "exactly" simply has units.
		// "multiple" has no units.

		gchar * pTmp = NULL;
		const gchar * pString = _getSpinItemValue(id_SPIN_SPECIAL_SPACING);
		UT_uint32 nSize = 0;

		switch(_getMenuItemValue(id_MENU_SPECIAL_SPACING))
		{
		case spacing_SINGLE:
			p->val = g_strdup("1.0");
			break;
		case spacing_ONEANDHALF:
			p->val = g_strdup("1.5");
			break;
		case spacing_DOUBLE:
			p->val = g_strdup("2.0");
			break;
		case spacing_ATLEAST:
			nSize = strlen(pString);
			pTmp = (gchar *) UT_calloc(nSize + 2, sizeof(gchar));
			UT_return_val_if_fail (pTmp, false);

			strncpy(pTmp, pString, nSize);
			// stick a '+' at the end
			pTmp[nSize] = '+';
			p->val = g_strdup(pTmp);
			FREEP(pTmp);
			break;

		case spacing_EXACTLY:
			// fallthrough
		case spacing_MULTIPLE:
			// both these cases either do or don't have units associated with them.
			// the platform dialog code takes care of that.
			p->val = g_strdup(pString);
			break;
		default:
			UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
		}
		v.addItem(p);
	}

	// NOTE : "orphans" and "widows" hold a number specifying the number
	// NOTE : of lines to consider an orphaned or widowed piece of text.
	// NOTE : If they're both 0 they're off.  If either is greater than
	// NOTE : 0, then some form of control is in effect.  If the property
	// NOTE : is not set, they're indeterminate.

	if (_wasChanged(id_CHECK_WIDOW_ORPHAN))
	{
		// TODO : fix this!  we stomp on both properties (setting them
		// TODO : to "2"s or "0"s) if the one check box was ever
		// TODO : changed

		{
			ALLOC_PROP_PAIR(p);
			p->prop = g_strdup("orphans");

			if (_getCheckItemValue(id_CHECK_WIDOW_ORPHAN) == check_TRUE)
				p->val = g_strdup("2");
			else
				p->val = g_strdup("0");

			v.addItem(p);
		}

		{
			ALLOC_PROP_PAIR(p);
			p->prop = g_strdup("widows");

			if (_getCheckItemValue(id_CHECK_WIDOW_ORPHAN) == check_TRUE)
				p->val = g_strdup("2");
			else
				p->val = g_strdup("0");

			v.addItem(p);
		}
	}

	if (_wasChanged(id_CHECK_KEEP_LINES))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("keep-together");

		if (_getCheckItemValue(id_CHECK_KEEP_LINES) == check_TRUE)
			p->val = g_strdup("yes");
		else
			p->val = g_strdup("no");

		v.addItem(p);
	}

	if (_wasChanged(id_CHECK_KEEP_NEXT))
	{
		ALLOC_PROP_PAIR(p);
		p->prop = g_strdup("keep-with-next");

		if (_getCheckItemValue(id_CHECK_KEEP_NEXT) == check_TRUE)
			p->val = g_strdup("yes");
		else
			p->val = g_strdup("no");

		v.addItem(p);
	}

	// TODO : add these to PP_Property (pp_Property.cpp) !!!
	/*
	  m_pageBreakBefore;
	  m_suppressLineNumbers;
	  m_noHyphenate;
	*/

	// export everything in the array
	UT_uint32 count = v.getItemCount()*2 + 1;

	const gchar ** newprops = (const gchar **) UT_calloc(count, sizeof(gchar *));
	if (!newprops)
		return false;

	const gchar ** newitem = newprops;

	UT_uint32 i = v.getItemCount();

	while (i > 0)
	{
		p = (propPair *) v.getNthItem(i-1);
		i--;

		newitem[0] = p->prop;
		newitem[1] = p->val;
		newitem += 2;
	}

	// DO purge the vector's CONTENTS, which are just propPair structs
	UT_VECTOR_FREEALL(propPair *, v);

	// DO NOT purge the propPair's CONTENTS, because they will be pointed to
	// by the pointers we just copied into memory typed (gchar **)

	pProps = newprops;

	return true;
}
Exemple #4
0
bool pt_PieceTable::_realChangeSpanFmt(PTChangeFmt ptc,
									   PT_DocPosition dpos1,
									   PT_DocPosition dpos2,
									   const gchar ** attributes,
									   const gchar ** properties,
									   bool bRevisionDelete)
{
	// apply a span-level formatting change to the given region.

	UT_return_val_if_fail (m_pts==PTS_Editing,false);
    _tweakFieldSpan(dpos1,dpos2);
//
// Deal with case of exactly selecting the endOfFootnote
//
	pf_Frag * pfEndDum = m_fragments.findFirstFragBeforePos(dpos2);
	if(isEndFootnote(pfEndDum))
	{
		if(dpos2 > dpos1)
		{
			dpos2--;
		}
	}
//
// Deal with addStyle
//
	bool bApplyStyle = (PTC_AddStyle == ptc);
	const gchar ** sProps = NULL;
	const gchar ** lProps = properties;
	if(bApplyStyle)
	{
//
// OK for styles we expand out all defined properties including BasedOn styles
// Then we use these to eliminate any specfic properties in the current strux
// Then properties in the current strux will resolve to those defined in the
// style (they exist there) to specifc values in strux (if not overridden by
// the style) then finally to default value.
//
		const gchar * szStyle = UT_getAttribute(PT_STYLE_ATTRIBUTE_NAME,attributes);
		PD_Style * pStyle = NULL;
		UT_return_val_if_fail (szStyle,false);
		getDocument()->getStyle(szStyle,&pStyle);
		UT_return_val_if_fail (pStyle,false);
		UT_Vector vProps;
//
// Get the vector of properties
//
		pStyle->getAllProperties(&vProps,0);
//
// Finally make the const gchar * array of properties
//
		UT_uint32 countp = vProps.getItemCount() + 1;
		sProps = (const gchar **) UT_calloc(countp, sizeof(gchar *));
		countp--;
		UT_uint32 i;
		for(i=0; i<countp; i++)
		{
			sProps[i] = (const gchar *) vProps.getNthItem(i);
		}
		sProps[i] = NULL;
		lProps = sProps;
	}
	if (dpos1 == dpos2) 		// if length of change is zero, then we have a toggle format.
	{
		UT_uint32 startUndoPos = m_history.getUndoPos();
		bool bRes = _insertFmtMarkFragWithNotify(ptc,dpos1,attributes,lProps);
		UT_uint32 endUndoPos = m_history.getUndoPos();
		// Won't be a persistant change if it's just a toggle
		PX_ChangeRecord *pcr=0;
		m_history.getUndo(&pcr,true);
		if (pcr && (startUndoPos != endUndoPos) )
		{
			UT_DEBUGMSG(("Setting persistance of change to false\n"));
			pcr->setPersistance(false);
			m_history.setSavePosition(m_history.getSavePosition()+1);
		}
		if(bApplyStyle)
		{
			FREEP(sProps);
		}
		return bRes;
	}

	UT_return_val_if_fail (dpos1 < dpos2,false);
	bool bHaveAttributes, bHaveProperties;
	bHaveAttributes = (attributes && *attributes);
	bHaveProperties = (lProps && *lProps);

	pf_Frag * pf_First;
	pf_Frag * pf_End;
	PT_BlockOffset fragOffset_First;
	PT_BlockOffset fragOffset_End;

	bool bFound;
	bFound = getFragsFromPositions(dpos1,dpos2,&pf_First,&fragOffset_First,&pf_End,&fragOffset_End);
	UT_return_val_if_fail (bFound, false);

#if 0
	{
		pf_Frag * pf1, * pf2;
		PT_BlockOffset fo1, fo2;

		bool bFound1 = getFragFromPosition(dpos1,&pf1,&fo1);
		bool bFound2 = getFragFromPosition(dpos2,&pf2,&fo2);
		UT_return_val_if_fail (bFound1 && bFound2, false);
		UT_return_val_if_fail ((pf1==pf_First) && (fragOffset_First==fo1), false);
		UT_return_val_if_fail ((pf2==pf_End) && (fragOffset_End==fo2), false);
	}
#endif

	// see if the amount of text to be changed is completely
	// contained within a single fragment.  if so, we have a
	// simple change.  otherwise, we need to set up a multi-step
	// change -- it may not actually take more than one step,
	// but it is too complicated to tell at this point, so we
	// assume it will and don't worry about it.
	//
	// we are in a simple change if the beginning and end are
	// within the same fragment.

	// NOTE: if we call beginMultiStepGlob() we ***MUST*** call
	// NOTE: endMultiStepGlob() before we return -- otherwise,
	// NOTE: the undo/redo won't be properly bracketed.

	bool bSimple = (pf_First == pf_End);
	if (!bSimple)
		beginMultiStepGlob();

	pf_Frag_Strux * pfsContainer = NULL;
	pf_Frag * pfNewEnd;
	UT_uint32 fragOffsetNewEnd;

	UT_uint32 length = dpos2 - dpos1;
	while (length != 0)
	{
		// FIXME: Special check to support a FmtMark at the end of the
		// document. This is necessary because FmtMarks don't have a
		// length...  See bug 452.
		if (0 == length
			&& (!pf_First || pf_Frag::PFT_FmtMark != pf_First->getType()))
			break;

		UT_return_val_if_fail (dpos1+length==dpos2, false);

		UT_uint32 lengthInFrag = pf_First->getLength() - fragOffset_First;
		UT_uint32 lengthThisStep = UT_MIN(lengthInFrag, length);

		switch (pf_First->getType())
		{
		case pf_Frag::PFT_EndOfDoc:
		default:
			UT_DEBUGMSG(("fragment type: %d\n",pf_First->getType()));
			UT_ASSERT_HARMLESS(0);
			if(bApplyStyle)
			{
				FREEP(sProps);
			}
			return false;

		case pf_Frag::PFT_Strux:
			{
				// we are only applying span-level changes, so we ignore strux.
				// but we still need to update our loop indices.

				pfNewEnd = pf_First->getNext();
				fragOffsetNewEnd = 0;
				pfsContainer = static_cast<pf_Frag_Strux *> (pf_First);
				bool bFoundStrux = false;
				if(isEndFootnote(pfsContainer))
				{
					bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux, false);
				}
			}
			break;

		case pf_Frag::PFT_Text:
			{
				if (!pfsContainer)
				{
					bool bFoundStrux;
					bFoundStrux = _getStruxFromPosition(dpos1,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux,false);
					if(isEndFootnote(pfsContainer))
					{
						bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
						UT_return_val_if_fail (bFoundStrux,false);
					}
				}

				bool bResult;
				bResult	= _fmtChangeSpanWithNotify(ptc,static_cast<pf_Frag_Text *>(pf_First),
											   fragOffset_First,dpos1,lengthThisStep,
											   attributes,lProps,
											   pfsContainer,&pfNewEnd,&fragOffsetNewEnd,bRevisionDelete);
				UT_return_val_if_fail (bResult,false);
			}
			break;

		case pf_Frag::PFT_Object:
			{
				if (!pfsContainer)
				{
					bool bFoundStrux;
					bFoundStrux = _getStruxFromPosition(dpos1,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux,false);
					if(isEndFootnote(pfsContainer))
					{
						bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
						UT_return_val_if_fail (bFoundStrux,false);
					}
				}

				bool bResult;
				bResult	= _fmtChangeObjectWithNotify(ptc,static_cast<pf_Frag_Object *>(pf_First),
												 fragOffset_First,dpos1,lengthThisStep,
												 attributes,lProps,
												 pfsContainer,&pfNewEnd,&fragOffsetNewEnd,false);
				UT_return_val_if_fail (bResult,false);
			}
			break;

		case pf_Frag::PFT_FmtMark:
			{
				if (!pfsContainer)
				{
					bool bFoundStrux;
					bFoundStrux = _getStruxFromPosition(dpos1,&pfsContainer);
					UT_return_val_if_fail (bFoundStrux,false);
					if(isEndFootnote(pfsContainer))
					{
						bFoundStrux = _getStruxFromFragSkip(pfsContainer,&pfsContainer);
						UT_return_val_if_fail (bFoundStrux,false);
					}

				}

				bool bResult;
				bResult = _fmtChangeFmtMarkWithNotify(ptc,static_cast<pf_Frag_FmtMark *>(pf_First),
												  dpos1, attributes,lProps,
												  pfsContainer,&pfNewEnd,&fragOffsetNewEnd);
				UT_return_val_if_fail (bResult,false);
			}
			break;

		}

		dpos1 += lengthThisStep;
		length -= lengthThisStep;

		// since _fmtChange{Span,FmtMark,...}WithNotify(), can delete pf_First, mess with the
		// fragment list, and does some aggressive coalescing of
		// fragments, we cannot just do a pf_First->getNext() here.
		// to advance to the next fragment, we use the *NewEnd variables
		// that each of the cases routines gave us.

		pf_First = pfNewEnd;
		if (!pf_First)
			length = 0;
		fragOffset_First = fragOffsetNewEnd;
	}
	if(bApplyStyle)
	{
		FREEP(sProps);
	}

	if (!bSimple)
		endMultiStepGlob();

	return true;
}
UT_Error IE_Imp_StarOffice::_loadFile(GsfInput * input)
{
	try {
		UT_DEBUGMSG(("SDW: Starting import\n"));
		mOle = GSF_INFILE (gsf_infile_msole_new(input, NULL));
		if (!mOle)
			return UT_IE_BOGUSDOCUMENT;

		// firstly, load metadata
		SDWDocInfo::load(mOle, getDoc());

		mDocStream = gsf_infile_child_by_name(mOle, "StarWriterDocument");
		if (!mDocStream)
			return UT_IE_BOGUSDOCUMENT;

		gsf_off_t size = gsf_input_size(mDocStream);

		if (!appendStrux(PTX_Section, PP_NOPROPS))
			return UT_IE_NOMEMORY;

		UT_DEBUGMSG(("SDW: Attempting to load DocHdr...\n"));
		mDocHdr.load(mDocStream);
		UT_DEBUGMSG(("SDW: ...success\n"));

		// Ask for and verify the password
		if (mDocHdr.cryptor) {
			if (!mDocHdr.cryptor->SetPassword(GetPassword().c_str())) {
				UT_DEBUGMSG(("SDW: Wrong password\n"));
				return UT_IE_PROTECTED;
			}
		}

		// do the actual reading
		char type;
		bool done = false;
		UT_uint32 recSize;
		while (!done) {
			if (gsf_input_tell(mDocStream) == size)
				break;
			readChar(mDocStream, type);
			gsf_off_t eor;
			readRecSize(mDocStream, recSize, &eor);

			switch (type) {
				case SWG_CONTENTS: {
					gsf_off_t flagsEnd = 0;
					UT_uint32 nNodes;
					// sw/source/core/sw3io/sw3sectn.cxx#L129
					if (mDocHdr.nVersion >= SWG_LAYFRAMES) {
						UT_uint8 flags;
						readFlagRec(mDocStream, flags, &flagsEnd);
					}
					if (mDocHdr.nVersion >= SWG_LONGIDX)
						streamRead(mDocStream, nNodes);
					else {
						if (mDocHdr.nVersion >= SWG_LAYFRAMES) {
							UT_uint16 sectidDummy;
							streamRead(mDocStream, sectidDummy);
						}
						UT_uint16 nodes16;
						streamRead(mDocStream, nodes16);
						nNodes = (UT_uint32)nodes16;
					}
					if (flagsEnd) {
						UT_ASSERT(flagsEnd >= gsf_input_tell(mDocStream));
						if (gsf_input_tell(mDocStream) != flagsEnd) {
							UT_DEBUGMSG(("SDW: have not read all flags\n"));
							if (gsf_input_seek(mDocStream, flagsEnd, G_SEEK_SET))
								return UT_IE_BOGUSDOCUMENT;
						}
					}
					bool done2 = false;
					UT_uint32 size2;
					while (!done2) {
						readChar(mDocStream, type);
						gsf_off_t eor2;
						readRecSize(mDocStream, size2, &eor2);

						switch (type) {
							case SWG_TEXTNODE: { // sw/source/core/sw3io/sw3nodes.cxx#L788
								UT_DEBUGMSG(("SDW: Found Textnode! (start at 0x%08llX end at 0x%08llX)\n", 
											 (long long)gsf_input_tell(mDocStream), 
											 (long long)eor2));
								UT_uint8 flags;
								gsf_off_t newPos;
								readFlagRec(mDocStream, flags, &newPos);
								// XXX check flags
								if (gsf_input_seek(mDocStream, newPos, G_SEEK_SET))
									return UT_IE_BOGUSDOCUMENT;

								// Read the actual text
								UT_UCS4Char* str;
								readByteString(mDocStream, str);
								UT_UCS4String textNode(str);
								free(str);
								UT_DEBUGMSG(("SDW: ...length=%zu contents are: |%s|\n", textNode.length(), textNode.utf8_str()));

								// now get the attributes
								UT_String attrs;
								UT_String pAttrs;
								UT_Vector charAttributes;
								while (gsf_input_tell(mDocStream) < eor2) {
									char attVal;
									streamRead(mDocStream, attVal);
									UT_uint32 attSize;
									gsf_off_t eoa; // end of attribute
									readRecSize(mDocStream, attSize, &eoa);
									if (attVal == SWG_ATTRIBUTE) {
										TextAttr* a = new TextAttr;
										streamRead(mDocStream, *a, eoa);
										UT_DEBUGMSG(("SDW: ...found text-sub-node, which=0x%x, ver=0x%x, start=%u, end=%u - data:%s len:%llu data is:",
													 a->which, a->ver, a->start,
													 a->end, a->data?"Yes":"No",
													 (long long unsigned)a->dataLen));
#ifdef DEBUG
										hexdump(a->data, a->dataLen);
                    putc('\n', stderr);
#endif
										charAttributes.addItem(a);
									}
									else if (attVal == SWG_ATTRSET) {
									  // bah, yet another loop
										UT_DEBUGMSG(("SDW: ...paragraph attributes found\n"));
										while (gsf_input_tell(mDocStream) < eoa) {
											// reusing attVal and attSize
											streamRead(mDocStream, attVal);
											gsf_off_t eoa2; // end of attribute
											readRecSize(mDocStream, attSize, &eoa2);
											if (attVal == SWG_ATTRIBUTE) {
												TextAttr a;
												streamRead(mDocStream, a, eoa2);
                        if (!a.attrVal.empty()) {
  												if (a.isPara)
	  												UT_String_setProperty(pAttrs, a.attrName, a.attrVal);
		  										else
			  										UT_String_setProperty(attrs, a.attrName, a.attrVal);
                        }
						UT_DEBUGMSG(("SDW: ......found paragraph attr, which=0x%x, ver=0x%x, start=%u, end=%u (string now %s) Data:%s Len=%lld Data:", a.which, a.ver, (a.startSet?a.start:0), (a.endSet?a.end:0), attrs.c_str(), (a.data ? "Yes" : "No"), (long long)a.dataLen));
#ifdef DEBUG
												hexdump(a.data, a.dataLen);
                        putc('\n', stderr);
#endif
											}
											if (gsf_input_seek(mDocStream, eoa2, G_SEEK_SET))
												return UT_IE_BOGUSDOCUMENT;
										}
									}
									else {
										UT_DEBUGMSG(("SDW: ...unknown attribute '%c' found (start=%" GSF_OFF_T_FORMAT " end=%" GSF_OFF_T_FORMAT ")\n", attVal, gsf_input_tell(mDocStream), eoa));
									}
									if (gsf_input_seek(mDocStream, eoa, G_SEEK_SET))
										return UT_IE_BOGUSDOCUMENT;
								}

								PP_PropertyVector attributes = {
									"props",
									pAttrs.c_str()
								};
								// first, insert the paragraph
								if (!appendStrux(PTX_Block, attributes))
									return UT_IE_NOMEMORY;

								UT_String pca(attrs); // character attributes for the whole paragraph
								// now insert the spans of text
								UT_uint32 len = textNode.length();
								UT_uint32 lastInsPos = 0;
								for (UT_uint32 i = 1; i < len; i++) {
									bool doInsert = false; // whether there was an attribute change
									for (UT_sint32 j = 0; j < charAttributes.getItemCount(); j++) {
										const TextAttr* a = reinterpret_cast<const TextAttr*>(charAttributes[j]);
										// clear the last attribute, if set
										if (a->endSet && a->end == (i - 1)) {
											if (a->isOff) {
												UT_String propval = UT_String_getPropVal(pca, a->attrName);
												UT_String_setProperty(attrs, a->attrName, propval);
											}
											else
												UT_String_removeProperty(attrs, a->attrName);
										}

										// now set new attribute, if needed
										if (a->startSet && a->start == (i - 1)) {
											if (a->isPara)
												UT_String_setProperty(pAttrs, a->attrName, a->attrVal);
											else if (a->isOff)
												UT_String_removeProperty(attrs, a->attrName);
											else
												UT_String_setProperty(attrs, a->attrName, a->attrVal);
										}

										// insert if this is the last character, or if there was a format change
										if ((a->endSet && a->end == i) || (a->startSet && a->start == i))
											doInsert = true;
									}
									if (doInsert || i == (len - 1)) {
										attributes[1] = attrs.c_str();
										UT_DEBUGMSG(("SDW: Going to appendFmt with %s\n", attributes[1].c_str()));
										if (!appendFmt(attributes))
											return UT_IE_NOMEMORY; /* leave cast alone! */
										UT_DEBUGMSG(("SDW: About to insert %u-%u\n", lastInsPos, i));
										size_t spanLen = i - lastInsPos;
										if (i == (len - 1)) spanLen++;
										UT_UCS4String span = textNode.substr(lastInsPos, spanLen);
										appendSpan(span.ucs4_str(), spanLen);
										lastInsPos = i;
									}
								}

								UT_VECTOR_PURGEALL(TextAttr*, charAttributes);
								break;

							}
							case SWG_JOBSETUP: {
								// flags are apparently unused here. no idea why they are there.
								gsf_off_t newpos;
								UT_uint8 flags;
								readFlagRec(mDocStream, flags, &newpos);
								if (gsf_input_seek(mDocStream, newpos, G_SEEK_SET))
									return UT_IE_BOGUSDOCUMENT;
								UT_uint16 len, system;
								streamRead(mDocStream, len);
								streamRead(mDocStream, system);
								char printerName[64];
								streamRead(mDocStream, printerName, 64);
								char deviceName[32], portName[32], driverName[32];
								streamRead(mDocStream, deviceName, 32);
								streamRead(mDocStream, portName, 32);
								streamRead(mDocStream, driverName, 32);
								UT_DEBUGMSG(("SDW: Jobsetup: len %u sys 0x%x printer |%.64s| device |%.32s| port |%.32s| driver |%.32s|\n", len, system, printerName, deviceName, portName, driverName));

								if (system == JOBSET_FILE364_SYSTEM || system == JOBSET_FILE605_SYSTEM) {
									UT_uint16 len2, system2;
									streamRead(mDocStream, len2);
									streamRead(mDocStream, system2);
									UT_uint32 ddl; // driver data length
									streamRead(mDocStream, ddl);
									// now the interesting data
									UT_uint16 orient; // 0=portrait 1=landscape
									streamRead(mDocStream, orient);
									UT_uint16 paperBin;
									streamRead(mDocStream, paperBin);
									UT_uint16 paperFormat;
									streamRead(mDocStream, paperFormat);
									UT_uint32 width, height;
									streamRead(mDocStream, width);
									streamRead(mDocStream, height);
									UT_DEBUGMSG(("SDW: orient %u bin %u format %u width %u height %u\n", orient, paperBin, paperFormat, width, height));
									// rest of the data is ignored, seems to be printer specific anyway.
									// Use A4, Portrait by default
									PP_PropertyVector attributes = {
										"pagetype", "a4", // A4/Letter/...
										"orientation", "portrait",
										"width", "210",
										"height", "297",
										"units", "mm"
									};
									const char* sdwPaperToAbi[] = {
										"A3",
										"A4",
										"A5",
										"B4",
										"B5",
										"Letter",
										"Legal",
										"Tabloid/Ledger",
										"Custom"
									};
									if (paperFormat < sizeof(sdwPaperToAbi)/sizeof(*sdwPaperToAbi)) {
										attributes[1] = sdwPaperToAbi[paperFormat];
                                    }
									const char* sdwOrientToAbi[] = {
										"portrait",
										"landscape"
									};
									if (orient < sizeof(sdwOrientToAbi)/sizeof(*sdwOrientToAbi)) {
										attributes[3] = sdwOrientToAbi[orient];
                                    }
									attributes[5] = UT_std_string_sprintf("%f", static_cast<double>(width)/100);
									attributes[7] = UT_std_string_sprintf("%f", static_cast<double>(height)/100);

									getDoc()->setPageSizeFromFile(attributes);
								}
								break;

							}
							case SWG_EOF:
								done2 = true;
								break;
							default:
								UT_DEBUGMSG(("SDW: SWG_CONTENT: Skipping %u bytes for record type '%c' (starting at 0x%08llX)\n",
											 size2, type,
											 (long long)gsf_input_tell(mDocStream)));
						}
						if (gsf_input_seek(mDocStream, eor2, G_SEEK_SET))
							return UT_IE_BOGUSDOCUMENT;
					}
					break;
				}
				case SWG_STRINGPOOL:
				{
					if (mDocHdr.nVersion <= SWG_POOLIDS) {
						UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
						break;
					}
					UT_uint8 encoding;
					streamRead(mDocStream, encoding);
					UT_iconv_t cd = findConverter(encoding);
					if (!UT_iconv_isValid(cd))
						throw UT_IE_IMPORTERROR;
					UT_uint16 count;
					streamRead(mDocStream, count);
					while (count--) {
						UT_uint16 id;
						streamRead(mDocStream, id);
						char* str;
						UT_uint16 len;
						::readByteString(mDocStream, str, &len);
						if (id == IDX_NOCONV_FF) {
							UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
						}
						// FIXME: find a way to not have to copy and free 
						// the result of UT_convert_cd.... --hub
						UT_DEBUGMSG(("SDW: StringPool: found 0x%04x <-> %.*s\n", id, len, str));
						UT_UCS4Char* convertedString = reinterpret_cast<UT_UCS4Char*>(UT_convert_cd(str, len + 1, cd, NULL, NULL));
						mStringPool.insert(stringpool_map::value_type(id, convertedString));
						FREEP(convertedString);
                        delete [] str;
					}
                    UT_iconv_close(cd);
					break;
				}
				case SWG_COMMENT: // skip over comments
					break;
				case SWG_EOF:
					done = true;
					break;
				default:
					UT_DEBUGMSG(("SDW: Skipping %u bytes for record type '%c' (starting at 0x%08llX)\n", recSize, type, (long long)gsf_input_tell(mDocStream)));
			}
			// Seek to the end of the record, in case it wasn't read completely
			if (gsf_input_seek(mDocStream, eor, G_SEEK_SET))
				return UT_IE_BOGUSDOCUMENT;
		}

		UT_DEBUGMSG(("SDW: Done\n"));

		return UT_OK;
	}
	catch(UT_Error e) {
		UT_DEBUGMSG(("SDW: error %d\n", e));
		return e;
	}
	catch(...) {
		UT_DEBUGMSG(("SDW: Unknown error\n"));
		return UT_IE_BOGUSDOCUMENT;
	}
}