1 /************************************************************************/
2 /*									*/
3 /*  Save a BufferDocument into an RTF file.				*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docRtfConfig.h"
8 
9 #   include	<string.h>
10 #   include	<stdio.h>
11 #   include	<ctype.h>
12 
13 #   include	<bitmap.h>
14 
15 #   include	<appDebugon.h>
16 
17 #   include	"docRtfFlags.h"
18 #   include	"docRtfTags.h"
19 #   include	<docTreeType.h>
20 #   include	<docObjectProperties.h>
21 #   include	<docParaParticules.h>
22 #   include	"docRtfWriterImpl.h"
23 
24 /************************************************************************/
25 /*									*/
26 /*  Save a paragraph in RTF format.					*/
27 /*									*/
28 /*  Column counting is approximate as it is only for cosmetic reasons.	*/
29 /*									*/
30 /************************************************************************/
31 
docRtfParaSaveProperties(RtfWriter * rw,int flattenCell,int firstInRow,int * pPropertyChange,int * pTabsSaved,const ParagraphProperties * newPP,const ParagraphProperties * prevPP)32 static void docRtfParaSaveProperties(
33 				RtfWriter *			rw,
34 				int				flattenCell,
35 				int				firstInRow,
36 				int *				pPropertyChange,
37 				int *				pTabsSaved,
38 				const ParagraphProperties *	newPP,
39 				const ParagraphProperties *	prevPP )
40     {
41     ParagraphProperties		defPP;
42     PropertyMask		ppDifMask;
43     PropertyMask		ppCmpMask;
44 
45     utilPropMaskClear( &ppDifMask );
46     utilPropMaskClear( &ppCmpMask );
47     utilPropMaskFill( &ppCmpMask, PPprop_FULL_COUNT );
48     if  ( flattenCell )
49 	{ PROPmaskUNSET( &ppCmpMask, PPpropTABLE_NESTING );	}
50 
51     docParaPropertyDifference( &ppDifMask, newPP, &ppCmpMask, prevPP );
52 
53     if  ( rw->rwPpExtraMask )
54 	{ utilPropMaskOr( &ppDifMask, &ppDifMask, rw->rwPpExtraMask );	}
55 
56     if  ( utilPropMaskIsEmpty( &ppDifMask ) )
57 	{
58 	if  ( ! flattenCell		&&
59 	      firstInRow		&&
60 	      newPP->ppTableNesting > 0	)
61 	    { docRtfSaveParaTableNesting( rw, newPP->ppTableNesting );	}
62 
63 	return;
64 	}
65 
66     docInitParagraphProperties( &defPP );
67 
68     /*  1  */
69     docRtfWriteTag( rw, RTFtag_pard );
70     *pPropertyChange= 1;
71 
72     utilPropMaskClear( &ppDifMask );
73     docParaPropertyDifference( &ppDifMask, newPP, &ppCmpMask, &defPP );
74 
75     if  ( rw->rwPpExtraMask )
76 	{ utilPropMaskOr( &ppDifMask, &ppDifMask, rw->rwPpExtraMask );	}
77 
78     docCleanParagraphProperties( &defPP );
79 
80     docRtfSaveParagraphProperties( rw, &ppDifMask, newPP );
81 
82     if  ( PROPmaskISSET( &ppDifMask, PPpropTAB_STOPS )	&&
83 	  newPP->ppTabStopListNumber != 0		)
84 	{ *pTabsSaved= 1;	}
85 
86     return;
87     }
88 
docRtfSaveObject(RtfWriter * rwc,const BufferItem * paraNode,const TextParticule * tp)89 static int docRtfSaveObject(	RtfWriter *		rwc,
90 				const BufferItem *	paraNode,
91 				const TextParticule *	tp )
92     {
93     InsertedObject *	io;
94     PictureProperties *	pip;
95 
96     PropertyMask	pipSetMask;
97 
98     io= docGetObject( rwc->rwDocument, tp->tpObjectNumber );
99     if  ( ! io )
100 	{ LXDEB(tp->tpObjectNumber,io); return -1;	}
101 
102     pip= &(io->ioPictureProperties);
103 
104     docRtfWriteNextLine( rwc );
105 
106     switch( io->ioKind )
107 	{
108 	case DOCokPICTWMETAFILE:
109 	case DOCokMACPICT:
110 	case DOCokPICTPNGBLIP:
111 	case DOCokPICTJPEGBLIP:
112 	case DOCokPICTEMFBLIP:
113 
114 	    docRtfWriteDestinationBegin( rwc, RTFtag_pict );
115 
116 	    docRtfPicturePropertyMask( &pipSetMask,
117 						&(io->ioPictureProperties) );
118 	    docRtfSavePictureTags( rwc, &pipSetMask,
119 						&(io->ioPictureProperties) );
120 
121 	    docRtfWriteMemoryBuffer( rwc, &(io->ioObjectData) );
122 	    docRtfWriteNextLine( rwc );
123 	    docRtfWriteDestinationEnd( rwc );
124 	    return 0;
125 
126 	case DOCokOLEOBJECT:
127 	    docRtfWriteDestinationBegin( rwc, "object" );
128 
129 	    switch( io->ioRtfEmbedKind )
130 		{
131 		case EMBEDkindOBJEMB:
132 		    docRtfWriteTag( rwc, "objemb" );
133 		    break;
134 		case EMBEDkindOBJLINK:
135 		    docRtfWriteTag( rwc, "objlink" );
136 		    break;
137 		case EMBEDkindOBJAUTLINK:
138 		    docRtfWriteTag( rwc, "objautlink" );
139 		    break;
140 		case EMBEDkindOBJSUB:
141 		    docRtfWriteTag( rwc, "objsub" );
142 		    break;
143 		case EMBEDkindOBJPUB:
144 		    docRtfWriteTag( rwc, "objpub" );
145 		    break;
146 		case EMBEDkindOBJICEMB:
147 		    docRtfWriteTag( rwc, "objicemb" );
148 		    break;
149 		case EMBEDkindOBJHTML:
150 		    docRtfWriteTag( rwc, "objhtml" );
151 		    break;
152 		case EMBEDkindOBJOCX:
153 		    docRtfWriteTag( rwc, "objocx" );
154 		    break;
155 		default:
156 		    LDEB(io->ioRtfEmbedKind);
157 		    break;
158 		}
159 
160 	    switch( io->ioRtfResultKind )
161 		{
162 		case RESULTkindUNKNOWN:
163 		    break;
164 		case RESULTkindRTF:
165 		    docRtfWriteTag( rwc, "rsltrtf" );
166 		    break;
167 		case RESULTkindTXT:
168 		    docRtfWriteTag( rwc, "rslttxt" );
169 		    break;
170 		case RESULTkindPICT:
171 		    docRtfWriteTag( rwc, "rsltpict" );
172 		    break;
173 		case RESULTkindBMP:
174 		    docRtfWriteTag( rwc, "rsltbmp" );
175 		    break;
176 		case RESULTkindHTML:
177 		    docRtfWriteTag( rwc, "rslthtml" );
178 		    break;
179 		default:
180 		    LDEB(io->ioRtfResultKind);
181 		    break;
182 		}
183 
184 	    if  ( io->ioObjectClass )
185 		{
186 		const int	addSemicolon= 0;
187 
188 		docRtfWriteDocEncodedStringDestination( rwc, "*\\objclass",
189 				io->ioObjectClass, strlen( io->ioObjectClass ),
190 				addSemicolon );
191 		}
192 
193 	    if  ( io->ioObjectName )
194 		{
195 		const int	addSemicolon= 0;
196 
197 		docRtfWriteDocEncodedStringDestination( rwc, "*\\objname",
198 				io->ioObjectName, strlen( io->ioObjectName ),
199 				addSemicolon );
200 		}
201 
202 	    docRtfWriteArgTag( rwc, "objw", io->ioTwipsWide );
203 	    docRtfWriteArgTag( rwc, "objh", io->ioTwipsHigh );
204 	    if  ( io->ioScaleXSet != 100 )
205 		{ docRtfWriteArgTag( rwc, "objscalex", io->ioScaleXSet ); }
206 	    if  ( io->ioScaleYSet != 100 )
207 		{ docRtfWriteArgTag( rwc, "objscaley", io->ioScaleYSet ); }
208 
209 	    docRtfWriteDestinationBegin( rwc, "*\\objdata" );
210 	    docRtfWriteMemoryBuffer( rwc, &io->ioObjectData );
211 	    docRtfWriteNextLine( rwc );
212 	    docRtfWriteDestinationEnd( rwc );
213 
214 	    if  ( io->ioResultKind == DOCokPICTWMETAFILE )
215 		{
216 		docRtfWriteDestinationBegin( rwc, RTFtag_result );
217 		docRtfWriteDestinationBegin( rwc, RTFtag_pict );
218 		docRtfWriteArgTag( rwc, "wmetafile", pip->pipMapMode );
219 
220 		docRtfPicturePropertyMask( &pipSetMask,
221 						&(io->ioPictureProperties) );
222 		docRtfSavePictureTags( rwc, &pipSetMask,
223 						&(io->ioPictureProperties) );
224 
225 		docRtfWriteMemoryBuffer( rwc, &(io->ioResultData) );
226 		docRtfWriteNextLine( rwc );
227 		docRtfWriteDestinationEnd( rwc );
228 
229 		docRtfWriteDestinationEnd( rwc );
230 		}
231 
232 	    docRtfWriteDestinationEnd( rwc );
233 	    return 0;
234 
235 	case DOCokEPS_FILE:
236 	    return 0;
237 
238 	case DOCokDRAWING_SHAPE:
239 	    SDEB(docObjectKindStr(io->ioKind));
240 	    return 0;
241 
242 	default:
243 	    SDEB(docObjectKindStr(io->ioKind));
244 	    return -1;
245 	}
246 
247     /*  Not reached ..
248     return 0;
249     */
250     }
251 
252 /************************************************************************/
253 
docRtfSaveTagParticule(RtfWriter * rwc,int kind)254 static int docRtfSaveTagParticule(	RtfWriter *		rwc,
255 					int			kind )
256     {
257     switch( kind )
258 	{
259 	case DOCkindCHFTNSEP:
260 	    docRtfWriteTag( rwc, "chftnsep" );
261 	    break;
262 
263 	case DOCkindCHFTNSEPC:
264 	    docRtfWriteTag( rwc, "chftnsepc" );
265 	    break;
266 
267 	case DOCkindOPT_HYPH:
268 	    docRtfWriteTag( rwc, "-" );
269 	    rwc->rwcAfter= RTFafterTEXT;
270 	    break;
271 
272 	case DOCkindTAB:
273 	    docRtfWriteTag( rwc, "tab" );
274 	    break;
275 
276 	case DOCkindLINEBREAK:
277 	    docRtfWriteTag( rwc, "line" );
278 	    docRtfWriteNextLine( rwc );
279 	    break;
280 
281 	case DOCkindPAGEBREAK:
282 	    docRtfWriteTag( rwc, "page" );
283 	    docRtfWriteNextLine( rwc );
284 	    break;
285 
286 	case DOCkindCOLUMNBREAK:
287 	    docRtfWriteTag( rwc, "column" );
288 	    docRtfWriteNextLine( rwc );
289 	    break;
290 
291 	case DOCkindLTR_MARK:
292 	    docRtfWriteTag( rwc, "ltrmark" );
293 	    break;
294 
295 	case DOCkindRTL_MARK:
296 	    docRtfWriteTag( rwc, "rtlmark" );
297 	    break;
298 
299 	default:
300 	    LDEB(kind); return -1;
301 	}
302 
303     return 0;
304     }
305 
306 /************************************************************************/
307 /*									*/
308 /*  Save a paragraph to rtf.						*/
309 /*									*/
310 /*  8)  MS-Word has a tendency to only pick up certain paragraph	*/
311 /*	properties, such as the tabs, at the paragraph mark. On the	*/
312 /*	other do superfluous paragraph marks result in empty paragraphs.*/
313 /*	Try to find a compromise: The \cell or \row count as a paragraph*/
314 /*	mark, so no need to save a paragraph mark in a table. This	*/
315 /*	construct was necessary to activate tabs in headers and footers.*/
316 /*									*/
317 /************************************************************************/
318 
docRtfSaveParaNode(RtfWriter * rwc,const BufferItem * paraNode,const DocumentSelection * ds,const int flattenCell,const int firstInRow)319 int docRtfSaveParaNode(		RtfWriter *			rwc,
320 				const BufferItem *		paraNode,
321 				const DocumentSelection *	ds,
322 				const int			flattenCell,
323 				const int			firstInRow )
324     {
325     TextParticule *		tp;
326 
327     const int			paralen= docParaStrlen( paraNode );
328     int				stroffFrom= -1;
329     int				stroffUpto= paralen;
330     int				part= 0;
331     int				partUpto= paraNode->biParaParticuleCount;
332     int				headFlags= 0;
333     int				tailFlags= 0;
334     int				restartFromDefault= 0;
335     int				paraPropChange= 0;
336     int				tabsSaved= 0;
337 
338     PropertyMask		ppUpdMask;
339 
340     DocumentPosition		dpLast;
341 
342     docRtfParaSaveProperties( rwc, flattenCell, firstInRow,
343 					&paraPropChange, &tabsSaved,
344 					&(paraNode->biParaProperties),
345 					&(rwc->rwcParagraphProperties) );
346 
347     if  ( restartFromDefault || paraPropChange )
348 	{ docRtfWriteSwitchToPlain( rwc );	}
349 
350     if  ( paraNode->biParaParticuleCount == 0 )
351 	{ LDEB(paraNode->biParaParticuleCount);	}
352 
353     {
354     DocumentSelection	dsPara;
355 
356     if  ( docIntersectSelectionWithParagraph( &dsPara,
357 					    &part, &partUpto,
358 					    &headFlags, &tailFlags,
359 					    paraNode, ds ) )
360 	{ LDEB(1); return -1;	}
361 
362     stroffFrom= dsPara.dsHead.dpStroff;
363     stroffUpto= dsPara.dsTail.dpStroff;
364     }
365 
366     tp= paraNode->biParaParticules+ part;
367     for ( ; part < paraNode->biParaParticuleCount; part++, tp++ )
368 	{
369 	int	pastSel= ( tailFlags & POSflagPARA_FOUND ) && tp->tpStroff >= stroffUpto;
370 
371 	if  ( rwc->rwSaveFlags & RTFflagOMIT_TEXT )
372 	    { continue;	}
373 
374 	if  ( ! pastSel || ( tp->tpKind == DOCkindSPAN && tp->tpStrlen == 0 ) )
375 	    {
376 	    const char *	first= (const char *)0;
377 
378 	    if  ( tp->tpStroff < paralen )
379 		{
380 		first= (const char *)docParaString( paraNode, tp->tpStroff );
381 		}
382 
383 	    if  ( tp->tpKind != DOCkindFIELDTAIL )
384 		{
385 		docRtfWriteSwitchTextAttributes( rwc, tp->tpTextAttrNr, first );
386 		}
387 	    }
388 
389 	switch( tp->tpKind )
390 	    {
391 	    int		extra;
392 
393 	    case DOCkindCHFTNSEP:
394 	    case DOCkindCHFTNSEPC:
395 	    case DOCkindOPT_HYPH:
396 	    case DOCkindTAB:
397 	    case DOCkindLINEBREAK:
398 	    case DOCkindPAGEBREAK:
399 	    case DOCkindCOLUMNBREAK:
400 	    case DOCkindLTR_MARK:
401 	    case DOCkindRTL_MARK:
402 		if  ( pastSel )
403 		    { break;	}
404 
405 		if  ( docRtfSaveTagParticule( rwc, tp->tpKind ) )
406 		    { LSDEB(tp->tpKind,docKindStr(tp->tpKind)); return -1; }
407 
408 		continue;
409 
410 	    case DOCkindSPAN:
411 		if  ( pastSel )
412 		    { break;	}
413 
414 		{
415 		int		n;
416 		int		stroff= tp->tpStroff;
417 
418 		if  ( stroff < stroffFrom )
419 		    { stroff=  stroffFrom;	}
420 
421 		if  ( ( tailFlags & POSflagPARA_FOUND )		&&
422 		      tp->tpStroff+ tp->tpStrlen > stroffUpto	)
423 		    { n= stroffUpto- stroff;			}
424 		else{ n= tp->tpStroff+ tp->tpStrlen- stroff;	}
425 
426 		if  ( rwc->rwCol > 0				&&
427 		      rwc->rwCol+ n > 72			&&
428 		      n < 72					)
429 		    { docRtfWriteNextLine( rwc ); }
430 
431 		docRtfWriteFontEncodedString( rwc,
432 				(char *)docParaString( paraNode, stroff ), n );
433 		}
434 
435 		continue;
436 
437 	    case DOCkindOBJECT:
438 		if  ( pastSel )
439 		    { break;	}
440 
441 		if  ( docRtfSaveObject( rwc, paraNode, tp ) )
442 		    { LDEB(tp->tpKind); }
443 		continue;
444 
445 	    case DOCkindFIELDHEAD:
446 		if  ( pastSel )
447 		    { break;	}
448 
449 		extra= docRtfSaveFieldHead( rwc, paraNode, part );
450 		if  ( extra < 0 )
451 		    { LDEB(extra); return -1;	}
452 		tp += extra; part += extra;
453 		continue;
454 
455 	    case DOCkindFIELDTAIL:
456 		extra= docRtfSaveFieldTail( rwc, paraNode, part );
457 		if  ( extra != 0 )
458 		    { LDEB(extra); return -1;	}
459 		continue;
460 
461 	    default:
462 		LDEB(tp->tpKind);
463 		continue;
464 	    }
465 
466 	break;
467 	}
468 
469     {
470     int		saveSpace= 0;
471 
472     if  ( ( rwc->rwSaveFlags & RTFflagSAVE_SOMETHING )	&&
473 	  ds						&&
474 	  ds->dsHead.dpNode == paraNode			&&
475 	  docIsIBarSelection( ds )			)
476 	{ saveSpace= 1;	}
477 
478     if  ( rwc->rwSaveFlags & RTFflagOMIT_TEXT )
479 	{ saveSpace= 1;	}
480 
481     if  ( saveSpace )
482 	{ docRtfWriteFontEncodedString( rwc, " ", 1 );	}
483     }
484 
485     docInitDocumentPosition( &dpLast );
486     docTailPosition( &dpLast, (BufferItem *)paraNode );
487 
488     /*  8  */
489     if  ( ! ( tailFlags & POSflagPARA_FOUND )	||
490 	  stroffUpto == dpLast.dpStroff 	||
491 	  ds					)
492 	{
493 	if  ( ( paraNode->biParaTableNesting == 0		&&
494 		paraNode->biTreeType == DOCinBODY		)	||
495 	      ( tabsSaved && paraNode->biParaTableNesting == 0	)	||
496 	      paraNode->biNumberInParent < paraNode->biParent->biChildCount- 1 )
497 	    {
498 	    docRtfWriteTag( rwc, RTFtag_par  );
499 	    docRtfWriteNextLine( rwc );
500 	    }
501 	}
502 
503     utilPropMaskClear( &ppUpdMask );
504     utilPropMaskFill( &ppUpdMask, PPprop_FULL_COUNT );
505 
506     if  ( docUpdParaProperties( (PropertyMask *)0,
507 				    &(rwc->rwcParagraphProperties),
508 				    &ppUpdMask, &(paraNode->biParaProperties),
509 				    (const DocumentAttributeMap *)0 ) )
510 	{ LDEB(1); return -1;	}
511 
512     return 0;
513     }
514 
515