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 ¶PropChange, &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