1 /************************************************************************/
2 /*									*/
3 /*  Reading of Rtf files. (Various utility functions.)			*/
4 /*									*/
5 /************************************************************************/
6 
7 #   include	"docRtfConfig.h"
8 
9 #   include	<stdlib.h>
10 #   include	<string.h>
11 #   include	<stdio.h>
12 #   include	<ctype.h>
13 #   include	<charnames.h>
14 
15 #   include	<appDebugon.h>
16 
17 #   include	<textOfficeCharset.h>
18 
19 #   include	"docRtfReaderImpl.h"
20 #   include	"docRtfTags.h"
21 #   include	"docRtfFlags.h"
22 
23 /************************************************************************/
24 /*									*/
25 /*  Read a control word from the input stream.				*/
26 /*									*/
27 /************************************************************************/
28 
docRtfReadControlWord(RtfReader * rrc,int * pC,char * controlWord,int * pGotArg,int * pArg)29 static int docRtfReadControlWord(	RtfReader *		rrc,
30 					int *			pC,
31 					char *			controlWord,
32 					int *			pGotArg,
33 					int *			pArg )
34     {
35     SimpleInputStream *	sis= rrc->rrcSis;
36     int			c;
37     int			len= 0;
38     int			sign= 1;
39 
40     c= sioInGetByte( sis );
41     while( c == '\n' || c == '\r' )
42 	{
43 	if  ( c == '\n' )
44 	    { rrc->rrCurrentLine++;	}
45 	c= sioInGetByte( sis );
46 	}
47 
48     if  ( c != '\\' )
49 	{ CDEB(c); return -1;	}
50 
51     c= sioInGetByte( sis );
52     if  ( ! isalpha( c ) )
53 	{
54 	switch( c )
55 	    {
56 	    case '\n':
57 		rrc->rrCurrentLine++;
58 		/*FALLTHROUGH*/
59 	    case '\r':
60 		strcpy( controlWord, RTFtag_par  );
61 		*pGotArg= 0;
62 		return 0;
63 	    case '\t':
64 		strcpy( controlWord, "tab" );
65 		*pGotArg= 0;
66 		return 0;
67 	    case '_':
68 		*pC= '-'; return 1;
69 
70 	    case '-':
71 		controlWord[len++]= c;
72 		controlWord[len  ]= '\0';
73 		*pGotArg= 0;
74 		return 0;
75 
76 	    default:
77 		*pC= c; return 1;
78 	    }
79 	}
80     controlWord[len++]= c;
81 
82     for (;;)
83 	{
84 	c= sioInGetByte( sis );
85 	if  ( ! isalpha( c ) )
86 	    { controlWord[len]= '\0'; break;	}
87 	if  ( len >= TEDszRTFCONTROL )
88 	    { LLDEB(len,TEDszRTFCONTROL); return -1;	}
89 	controlWord[len++]= c;
90 	}
91 
92     if  ( c == '-' )
93 	{ sign= -1; c= sioInGetByte( sis );	}
94 
95     *pGotArg= ( isdigit( c ) != 0 );
96     if  ( *pGotArg )
97 	{
98 	int arg= c- '0';
99 
100 	c= sioInGetByte( sis );
101 
102 	while( isdigit( c ) )
103 	    { arg= 10* arg+ c- '0'; c= sioInGetByte( sis ); }
104 
105 	*pArg= sign* arg;
106 	}
107 
108     if  ( c != ' ' )
109 	{ sioInUngetLastRead( sis );	}
110 
111     return 0;
112     }
113 
114 /************************************************************************/
115 /*									*/
116 /*  Find a Control word.						*/
117 /*									*/
118 /************************************************************************/
119 
docRtfFindWord(const char * controlWord,const RtfControlWord * controlWords)120 const RtfControlWord * docRtfFindWord(	const char *		controlWord,
121 					const RtfControlWord *	controlWords )
122     {
123     if  ( controlWords )
124 	{
125 	while( controlWords->rcwWord )
126 	    {
127 	    if  ( ! strcmp( controlWords->rcwWord, controlWord ) )
128 		{ return controlWords;	}
129 
130 	    controlWords++;
131 	    }
132 	}
133 
134     return (RtfControlWord *)0;
135     }
136 
docRtfApplyControlWord(const RtfControlWord * rcw,int gotArg,int arg,RtfReader * rrc)137 int docRtfApplyControlWord(	const RtfControlWord *	rcw,
138 				int			gotArg,
139 				int			arg,
140 				RtfReader *		rrc )
141     {
142     if  ( ! gotArg )
143 	{ arg= -1;	}
144 
145     if  ( rcw->rcwType == RTCtypeENUM )
146 	{
147 	if  ( gotArg )
148 	    { SLLLDEB(rcw->rcwWord,arg,rcw->rcwType,gotArg);	}
149 
150 	arg= rcw->rcwEnumValue;
151 	}
152 
153     if  ( rcw->rcwType != RTCtypeENUM	&&
154 	  rcw->rcwEnumValue != 0	&&
155 	  rcw->rcwID != PIPpropTYPE	)
156 	{ SLLDEB(rcw->rcwWord,rcw->rcwType,rcw->rcwEnumValue);	}
157 
158     if  ( (*rcw->rcwApply) ( rcw, arg, rrc ) )
159 	{ LSLDEB(rrc->rrCurrentLine,rcw->rcwWord,arg); return -1;	}
160 
161     return 0;
162     }
163 
164 /************************************************************************/
165 /*									*/
166 /*  Find out what to do.						*/
167 /*									*/
168 /*  Return	RTFfiCTRLGROUP:	Found a control group.			*/
169 /*  Return	RTFfiWORD:	Found a control word.			*/
170 /*  Return	RTFfiCHAR:	Found a character.			*/
171 /*  Return	RTFfiCLOSE:	Found an unescaped brace.		*/
172 /*  Return	-1:		Error.					*/
173 /*									*/
174 /************************************************************************/
175 
docRtfFindControl(RtfReader * rrc,int * pC,char * controlWord,int * pGotArg,int * pArg)176 int docRtfFindControl(		RtfReader *		rrc,
177 				int *			pC,
178 				char *			controlWord,
179 				int *			pGotArg,
180 				int *			pArg )
181     {
182     SimpleInputStream *	sis= rrc->rrcSis;
183     RtfReadingState *	rrs= rrc->rrcState;
184 
185     int			c;
186     int			res;
187 
188     if  ( rrc->rrcCharacterAhead != EOF )
189 	{
190 	*pC= rrc->rrcCharacterAhead;
191 	rrc->rrcCharacterAhead= EOF;
192 	return RTFfiCHAR;
193 	}
194 
195     for (;;)
196 	{
197 	c= sioInGetByte( sis );
198 
199 	switch( c )
200 	    {
201 	    case EOF:
202 		if  ( rrs )
203 		    { rrs->rrsUnicodeBytesToSkip= 0;	}
204 
205 		if  ( ! ( rrc->rrReadFlags & RTFflagLENIENT ) )
206 		    {
207 		    const char * message= DOC_RTF_LENIENT_MESSAGE;
208 		    XSDEB(c,message); return -1;
209 		    }
210 		else{ XDEB(c); *pC= '}'; return RTFfiCLOSE;	}
211 
212 	    case '\\':
213 		sioInUngetLastRead( sis );
214 		res= docRtfReadControlWord( rrc, &c,
215 						controlWord, pGotArg, pArg );
216 
217 		if  ( res < 0 )
218 		    { LDEB(res); return -1;	}
219 		if  ( res > 0 )
220 		    {
221 		    switch( c )
222 			{
223 			case '\\': case '{': case '}':
224 			    *pC= c; return RTFfiCHAR;
225 
226 			case '~':
227 			    c= ISO1_nobreakspace;
228 			    *pC= c; return RTFfiCHAR;
229 
230 			case '_':
231 			    c= '-';
232 			    *pC= c; return RTFfiCHAR;
233 
234 			case '\'':
235 			    if  ( res == 1 )
236 				{
237 				char		b[3];
238 				unsigned int	uc;
239 
240 				b[0]= sioInGetByte( sis );
241 				b[1]= sioInGetByte( sis );
242 				b[2]= '\0';
243 
244 				sscanf( b, "%x", &uc ); c= uc;
245 				}
246 			    goto defaultCase;
247 
248 			default:
249 			    if  ( res == 2 )
250 				{ *pC= c; return RTFfiCHAR;	}
251 			    else{ goto defaultCase;		}
252 			}
253 		    }
254 		return RTFfiWORD;
255 
256 	    case '{':
257 		if  ( rrs )
258 		    { rrs->rrsUnicodeBytesToSkip= 0;	}
259 
260 		c= sioInGetByte( sis );
261 		while( c == '\n' || c == '\r' )
262 		    {
263 		    if  ( c == '\n' )
264 			{ rrc->rrCurrentLine++;	}
265 		    c= sioInGetByte( sis );
266 		    }
267 
268 		if  ( c == '\\' )
269 		    {
270 		    sioInUngetLastRead( sis );
271 		    res= docRtfReadControlWord( rrc, &c,
272 						controlWord, pGotArg, pArg );
273 		    if  ( res < 0 )
274 			{ LDEB(res); return -1;	}
275 		    if  ( res > 0 )
276 			{
277 			if  ( c == '*' )
278 			    {
279 			    res= docRtfReadControlWord( rrc, &c,
280 						controlWord, pGotArg, pArg );
281 			    if  ( res )
282 				{ LDEB(res); return -1;	}
283 
284 			    return RTFfiSTARGROUP;
285 			    }
286 
287 			if  ( c=='\'' )
288 			    {
289 			    char		b[3];
290 			    unsigned int	uc;
291 
292 			    b[0]= sioInGetByte( sis );
293 			    b[1]= sioInGetByte( sis );
294 			    b[2]= '\0';
295 
296 			    sscanf( b, "%x", &uc ); c= uc;
297 			    }
298 
299 			if  ( rrs && rrs->rrsUnicodeBytesToSkip > 0 )
300 			    { rrs->rrsUnicodeBytesToSkip= 0;	}
301 
302 			rrc->rrcCharacterAhead= c;
303 
304 			return RTFfiTEXTGROUP;
305 			}
306 
307 		    return RTFfiCTRLGROUP;
308 		    }
309 
310 		sioInUngetLastRead( sis );
311 		return RTFfiTEXTGROUP;
312 
313 	    case '\n':
314 		rrc->rrCurrentLine++;
315 		/*FALLTHROUGH*/
316 	    case '\r':
317 		continue;
318 
319 	    case '}':
320 		rrs->rrsUnicodeBytesToSkip= 0;
321 		*pC= c; return RTFfiCLOSE;
322 
323 	    case '\t':
324 		*pC= c; return RTFfiTAB;
325 
326 	    default: defaultCase:
327 
328 		if  ( rrs && rrs->rrsUnicodeBytesToSkip > 0 )
329 		    { rrs->rrsUnicodeBytesToSkip--; continue;	}
330 
331 		*pC= c; return RTFfiCHAR;
332 	    }
333 	}
334     }
335 
336 /************************************************************************/
337 /*									*/
338 /*  Add the collected text to the document. Subtract extra unicode	*/
339 /*									*/
340 /************************************************************************/
341 
docRtfAddParticule(RtfReader * rrc,const char * collectedText,int len)342 static int docRtfAddParticule(	RtfReader *		rrc,
343 				const char *		collectedText,
344 				int			len )
345     {
346     RtfReadingState *	rrs= rrc->rrcState;
347 
348     if  ( ! rrc->rrcAddParticule )
349 	{ XDEB(rrc->rrcAddParticule); return -1;	}
350 
351     while ( rrs->rrsUnicodeBytesToSkip > 0 && len > 0 )
352 	{
353 	rrs->rrsUnicodeBytesToSkip--; len--;
354 	collectedText++;
355 	}
356 
357     if  ( len > 0 && (*rrc->rrcAddParticule)( rrc, collectedText, len ) )
358 	{ LDEB(len); return -1;	}
359 
360     return 0;
361     }
362 
363 /************************************************************************/
364 /*									*/
365 /*  Consume free text upto a control word or a group.			*/
366 /*									*/
367 /************************************************************************/
368 
docRtfReadText(int c,int * pC,char * controlWord,int * pGotArg,int * pArg,RtfReader * rrc)369 static int docRtfReadText(	int			c,
370 				int *			pC,
371 
372 				char *			controlWord,
373 				int *			pGotArg,
374 				int *			pArg,
375 
376 				RtfReader *	rrc )
377     {
378     RtfReadingState *	rrs= rrc->rrcState;
379     SimpleInputStream *	sis= rrc->rrcSis;
380     int			res;
381 
382     static char *	collectedText;
383     static int		collectedSize;
384 
385     char *		fresh;
386     int			size;
387     int			len;
388 
389     len= 0;
390     if  ( len >= collectedSize )
391 	{
392 	size= 100;
393 
394 	fresh= (char *)realloc( collectedText, size+ 2 );
395 	if  ( ! fresh )
396 	    { LXDEB(size,fresh); return -1;	}
397 
398 	collectedText= fresh;
399 	collectedSize= size;
400 	}
401 
402     collectedText[len++]= c;
403     collectedText[len  ]= '\0';
404 
405     for (;;)
406 	{
407 	c= sioInGetByte( sis );
408 
409 	switch( c )
410 	    {
411 	    case EOF:
412 		LDEB(c); return -1;
413 
414 	    case '}':
415 		if  ( docRtfAddParticule( rrc, collectedText, len ) )
416 		    { LDEB(len); return -1;	}
417 		rrs->rrsUnicodeBytesToSkip= 0;
418 		return RTFfiCLOSE;
419 
420 	    case '{':
421 		sioInUngetLastRead( sis );
422 		res= docRtfFindControl( rrc, &c, controlWord, pGotArg, pArg );
423 		if  ( res < 0 )
424 		    { LDEB(res); return res;	}
425 		if  ( docRtfAddParticule( rrc, collectedText, len ) )
426 		    { LDEB(len); return -1;	}
427 		rrs->rrsUnicodeBytesToSkip= 0;
428 		*pC= c; return res;
429 
430 	    case '\n':
431 		rrc->rrCurrentLine++;
432 		/*FALLTHROUGH*/
433 
434 	    case '\r' :
435 		continue;
436 
437 	    case '\\':
438 		sioInUngetLastRead( sis );
439 		res= docRtfFindControl( rrc, &c, controlWord, pGotArg, pArg );
440 		if  ( res < 0 )
441 		    { LDEB(res); return res;	}
442 
443 		if  ( res != RTFfiCHAR )
444 		    {
445 		    if  ( docRtfAddParticule( rrc, collectedText, len ) )
446 			{ LDEB(len); return -1;	}
447 
448 		    return res;
449 		    }
450 
451 		/*FALLTHROUGH*/
452 
453 	    default:
454 		if  ( len >= collectedSize )
455 		    {
456 		    size= ( 3* collectedSize+ 2 )/ 2;
457 
458 		    if  ( size < len )
459 			{ size= len+ 2;	}
460 
461 		    fresh= (char *)realloc( collectedText, size+ 2 );
462 		    if  ( ! fresh )
463 			{ LXDEB(size,fresh); return -1;	}
464 
465 		    collectedText= fresh;
466 		    collectedSize= size;
467 		    }
468 
469 		collectedText[len++]= c;
470 		collectedText[len  ]= '\0';
471 		break;
472 
473 	    case '\t':
474 		if  ( docRtfAddParticule( rrc, collectedText, len ) )
475 		    { LDEB(len); return -1;	}
476 		strcpy( controlWord, "tab" ); *pGotArg= 0; *pArg= -1;
477 		res= RTFfiWORD;
478 		return res;
479 	    }
480 	}
481     }
482 
483 /************************************************************************/
484 /*									*/
485 /*  Skip an unknown or superfluous group.				*/
486 /*									*/
487 /************************************************************************/
488 
docRtfSkipGroup(const RtfControlWord * rcw,int ignored_arg,RtfReader * rrc)489 int docRtfSkipGroup(	const RtfControlWord *	rcw,
490 			int			ignored_arg,
491 			RtfReader *		rrc )
492     {
493     int		rval= 0;
494     int		complainUnknown= rrc->rrcComplainUnknown;
495 
496     rrc->rrcComplainUnknown= 0;
497     rrc->rrcInIgnoredGroup++;
498 
499     if  ( docRtfReadGroup( rcw, 0, 0, rrc,
500 		(RtfControlWord *)0, docRtfIgnoreText, (RtfCommitGroup)0 ) )
501 	{ SDEB(rcw->rcwWord); rval= -1;	}
502 
503     rrc->rrcInIgnoredGroup--;
504     rrc->rrcComplainUnknown= complainUnknown;
505 
506     return rval;
507     }
508 
509 /************************************************************************/
510 /*									*/
511 /*  Read an RTF control group. typically the document.			*/
512 /*									*/
513 /************************************************************************/
514 
docRtfReadGroupX(const RtfControlWord * rcw,const RtfControlWord * applyFirst,int gotArg,int arg,RtfReader * rrc,const RtfControlWord * groupWords,RtfAddTextParticule addParticule,RtfCommitGroup commitGroup)515 int docRtfReadGroupX(	const RtfControlWord *	rcw,
516 			const RtfControlWord *	applyFirst,
517 			int			gotArg,
518 			int			arg,
519 			RtfReader *	rrc,
520 			const RtfControlWord *	groupWords,
521 			RtfAddTextParticule	addParticule,
522 			RtfCommitGroup		commitGroup )
523     {
524     int				rval;
525     RtfReadingState		internRrs;
526 
527     docRtfPushReadingState( rrc, &internRrs );
528 
529     rval= docRtfConsumeGroup( applyFirst, gotArg, arg,
530 					    rrc, groupWords, addParticule );
531 
532     if  ( rval )
533 	{ LDEB(rval);	}
534 
535     if  ( commitGroup && (*commitGroup)( rcw, rrc ) )
536 	{ LDEB(1); rval= -1;	}
537 
538     docRtfPopReadingState( rrc );
539 
540     return rval;
541     }
542 
docRtfReadGroup(const RtfControlWord * rcw,int gotArg,int arg,RtfReader * rrc,const RtfControlWord * groupWords,RtfAddTextParticule addParticule,RtfCommitGroup commitGroup)543 int docRtfReadGroup(	const RtfControlWord *	rcw,
544 			int			gotArg,
545 			int			arg,
546 			RtfReader *		rrc,
547 			const RtfControlWord *	groupWords,
548 			RtfAddTextParticule	addParticule,
549 			RtfCommitGroup		commitGroup )
550     {
551     int				rval;
552     RtfReadingState		internRrs;
553 
554     docRtfPushReadingState( rrc, &internRrs );
555 
556     rval= docRtfConsumeGroup( (const RtfControlWord *)0, gotArg, arg,
557 					    rrc, groupWords, addParticule );
558 
559     if  ( rval )
560 	{ LDEB(rval);	}
561 
562     if  ( commitGroup && (*commitGroup)( rcw, rrc ) )
563 	{ LDEB(1); rval= -1;	}
564 
565     docRtfPopReadingState( rrc );
566 
567     return rval;
568     }
569 
570 /************************************************************************/
571 /*									*/
572 /*  Consume detail tags. In practice that is the properties of a border	*/
573 /*									*/
574 /************************************************************************/
575 
docRtfConsumeWord(RtfReader * rrc,const RtfControlWord * rcw,int * pC,char * controlWord,int * pGotArg,int * pArg)576 static int docRtfConsumeWord(	RtfReader *		rrc,
577 				const RtfControlWord *	rcw,
578 				int *			pC,
579 				char *			controlWord,
580 				int *			pGotArg,
581 				int *			pArg )
582     {
583     int		resAhead= -2;
584 
585     int		c= *pC;
586     int		gotArg= *pGotArg;
587     int		arg= *pArg;
588 
589     int		gotArgAhead= 0;
590     int		argAhead= -1;
591 
592     int		res;
593 
594     if  ( rcw->rcwPrepare )
595 	{
596 	if  ( (*rcw->rcwPrepare) ( rcw, arg, rrc ) )
597 	    { SLDEB(rcw->rcwWord,arg); return -1;	}
598 	}
599 
600     if  ( rcw->rcwDetailWords )
601 	{
602 	for (;;)
603 	    {
604 	    const RtfControlWord *	rcwAhead;
605 
606 	    resAhead= docRtfFindControl( rrc, &c,
607 			controlWord, &gotArgAhead, &argAhead );
608 
609 	    if  ( resAhead != RTFfiWORD )
610 		{ break;	}
611 
612 	    rcwAhead= docRtfFindWord( controlWord, rcw->rcwDetailWords );
613 
614 	    if  ( ! rcwAhead )
615 		{ break;	}
616 	    if  ( rcwAhead->rcwType == RTCtypeDEST )
617 		{ SLDEB(rcwAhead->rcwWord,rcwAhead->rcwType); break;	}
618 
619 	    if  ( ! rrc->rrcInIgnoredGroup )
620 		{
621 		int resx= docRtfApplyControlWord(
622 				    rcwAhead, gotArgAhead, argAhead, rrc  );
623 
624 		if  ( resx < 0 )
625 		    { LSDEB(resx,controlWord); return -1; }
626 		}
627 	    }
628 	}
629 
630     if  ( rrc->rrcInIgnoredGroup )
631 	{
632 	if  ( rcw->rcwType == RTCtypeDEST )
633 	    { SLDEB(rcw->rcwWord,rcw->rcwType);	}
634 
635 	res= 0;
636 	}
637     else{
638 	res= docRtfApplyControlWord( rcw, gotArg, arg, rrc );
639 	if  ( res < 0 )
640 	    { SLDEB(rcw->rcwWord,res); return -1;	}
641 	}
642 
643     if  ( resAhead == -2 )
644 	{
645 	res= docRtfFindControl( rrc, &c, controlWord, &gotArg, &arg );
646 	}
647     else{
648 	res= resAhead; arg= argAhead; gotArg= gotArgAhead;
649 	resAhead= -2;
650 	}
651 
652     *pC= c; *pGotArg= gotArg; *pArg= arg;
653     return res;
654     }
655 
656 /************************************************************************/
657 /*									*/
658 /*  Read an unknown group.						*/
659 /*									*/
660 /************************************************************************/
661 
docRtfReadUnknownGroup(RtfReader * rrc)662 int docRtfReadUnknownGroup(	RtfReader *	rrc )
663     {
664     int		complainUnknown= rrc->rrcComplainUnknown;
665 
666     rrc->rrcComplainUnknown= 0;
667 
668     if  ( docRtfReadGroup( (const RtfControlWord *)0, 0, 0, rrc,
669 		    (RtfControlWord *)0, docRtfIgnoreText, (RtfCommitGroup)0 ) )
670 	{ LDEB(1); return -1;	}
671 
672     rrc->rrcComplainUnknown= complainUnknown;
673 
674     return 0;
675     }
676 
docRtfConsumeGroup(const RtfControlWord * applyFirst,int gotArg,int arg,RtfReader * rrc,const RtfControlWord * groupWords,RtfAddTextParticule addParticule)677 int docRtfConsumeGroup(	const RtfControlWord *	applyFirst,
678 			int			gotArg,
679 			int			arg,
680 			RtfReader *		rrc,
681 			const RtfControlWord *	groupWords,
682 			RtfAddTextParticule	addParticule )
683     {
684     int				rval= 0;
685     int				res;
686     const RtfControlWord *	rcw;
687 
688     char			controlWord[TEDszRTFCONTROL+1];
689     int				c;
690 
691     RtfAddTextParticule		savedAddParticule= rrc->rrcAddParticule;
692 
693     if  ( applyFirst )
694 	{
695 	res= docRtfConsumeWord( rrc, applyFirst,
696 					&c, controlWord, &gotArg, &arg );
697 	if  ( res < 0 )
698 	    { LDEB(res); rval= -1; goto ready;	}
699 	}
700     else{
701 	res= docRtfFindControl( rrc, &c, controlWord, &gotArg, &arg );
702 	if  ( res < 0 )
703 	    { LDEB(res); rval= -1; goto ready;	}
704 	}
705 
706     if  ( addParticule )
707 	{ rrc->rrcAddParticule= addParticule;	}
708 
709     for (;;)
710 	{
711 	const RtfControlWord *	rcwApplyFirst;
712 	int			argApplyFirst;
713 	int			gotArgApplyFirst;
714 
715 	switch( res )
716 	    {
717 	    case RTFfiCLOSE:
718 		goto ready;
719 
720 	    case RTFfiCHAR:
721 		res= docRtfReadText( c, &c, controlWord, &gotArg, &arg, rrc );
722 		if  ( res < 0 )
723 		    { SLDEB(controlWord,res); rval= -1; goto ready;	}
724 		break;
725 
726 	    case RTFfiTAB:
727 		strcpy( controlWord, "tab" );
728 		/*FALLTHROUGH*/
729 
730 	    case RTFfiWORD:
731 		rcw= docRtfFindPropertyWord( controlWord );
732 		if  ( ! rcw )
733 		    {
734 		    if  ( rrc->rrcComplainUnknown && ! rrc->rrcInIgnoredGroup )
735 			{ LSDEB(rrc->rrCurrentLine,controlWord);	}
736 
737 		    res= docRtfFindControl( rrc, &c,
738 						controlWord, &gotArg, &arg );
739 		    if  ( res < 0 )
740 			{ LDEB(res); rval= -1; goto ready;	}
741 		    }
742 		else{
743 		    if  ( rcw->rcwType == RTCtypeDEST )
744 			{
745 			SLDEB(rcw->rcwWord,rcw->rcwType);
746 
747 			res= docRtfFindControl( rrc, &c,
748 						controlWord, &gotArg, &arg );
749 			if  ( res < 0 )
750 			    { LDEB(res); rval= -1; goto ready;	}
751 			}
752 		    else{
753 			res= docRtfConsumeWord( rrc, rcw,
754 					    &c, controlWord, &gotArg, &arg );
755 			if  ( res < 0 )
756 			    { LDEB(res); rval= -1; goto ready;	}
757 			}
758 		    }
759 		break;
760 	    case RTFfiCTRLGROUP:
761 		rcw= docRtfFindWord( controlWord, groupWords );
762 		if  ( ! rcw )
763 		    { rcw= docRtfFindPropertyWord( controlWord );	}
764 		if  ( rcw )
765 		    {
766 		    if  ( rcw->rcwType == RTCtypeDEST )
767 			{
768 		      groupFound:
769 			if  ( rrc->rrcInIgnoredGroup )
770 			    {
771 			    res= docRtfReadGroup( (const RtfControlWord *)0,
772 					0, 0, rrc, (RtfControlWord *)0,
773 					docRtfIgnoreText, (RtfCommitGroup)0 );
774 			    }
775 			else{
776 			    res= docRtfApplyControlWord( rcw,
777 							    gotArg, arg, rrc );
778 			    }
779 			if  ( res < 0 )
780 			    { LSDEB(res,controlWord); rval= -1; goto ready; }
781 			}
782 		    else{
783 			if  ( docRtfReadGroupX( rcw, rcw, gotArg, arg, rrc,
784 				groupWords, addParticule, (RtfCommitGroup)0 ) )
785 			    { SDEB(rcw->rcwWord); return -1;	}
786 			}
787 		    }
788 		else{
789 		    if  ( rrc->rrcComplainUnknown && ! rrc->rrcInIgnoredGroup )
790 			{ LSDEB(rrc->rrCurrentLine,controlWord);	}
791 
792 		    if  ( docRtfReadUnknownGroup( rrc ) )
793 			{ LSDEB(rrc->rrCurrentLine,controlWord); return -1; }
794 		    }
795 
796 		c= 0x0;
797 		res= docRtfFindControl( rrc, &c, controlWord, &gotArg, &arg );
798 		if  ( res < 0 )
799 		    { LDEB(res); rval= -1; goto ready;	}
800 		break;
801 
802 	    case RTFfiSTARGROUP:
803 		rcw= docRtfFindWord( controlWord, groupWords );
804 		if  ( rcw )
805 		    { goto groupFound; }
806 		rcw= docRtfFindPropertyWord( controlWord );
807 		if  ( rcw && rcw->rcwType == RTCtypeDEST )
808 		    { goto groupFound; }
809 
810 		if  ( rcw )
811 		    {
812 		    if  ( ! gotArg )
813 			{ arg= -1;	}
814 
815 		    rcwApplyFirst= rcw;
816 		    argApplyFirst= arg;
817 		    gotArgApplyFirst= gotArg;
818 
819 		    goto textGroup;
820 		    }
821 
822 		rrc->rrcInIgnoredGroup++;
823 
824 		if  ( docRtfReadUnknownGroup( rrc ) )
825 		    { LDEB(1); rrc->rrcInIgnoredGroup--; rval= -1; goto ready;	}
826 
827 		rrc->rrcInIgnoredGroup--;
828 
829 		res= docRtfFindControl( rrc, &c,
830 					    controlWord, &gotArg, &arg );
831 		if  ( res < 0 )
832 		    { LDEB(res); rval= -1; goto ready;	}
833 		break;
834 
835 	    case RTFfiTEXTGROUP:
836 		rcwApplyFirst= (RtfControlWord *)0;
837 		argApplyFirst= -1;
838 		gotArgApplyFirst= 0;
839 
840 	      textGroup:
841 		if  ( docRtfReadGroupX( (const RtfControlWord *)0,
842 			    rcwApplyFirst, gotArgApplyFirst, argApplyFirst,
843 			    rrc, groupWords,
844 			    addParticule, (RtfCommitGroup)0 ) )
845 		    { LDEB(1); rval= -1; goto ready;	}
846 
847 		res= docRtfFindControl( rrc, &c,
848 					    controlWord, &gotArg, &arg );
849 		if  ( res < 0 )
850 		    { LDEB(res); rval= -1; goto ready;	}
851 		break;
852 
853 	    default:
854 		LDEB(res); rval= -1; goto ready;
855 	    }
856 	}
857 
858   ready:
859     rrc->rrcAddParticule= savedAddParticule;
860 
861     return rval;
862     }
863 
864 /************************************************************************/
865 /*									*/
866 /*  Apply a text group.							*/
867 /*									*/
868 /************************************************************************/
869 
docRtfApplyDocEncodedTextGroup(const RtfControlWord * rcw,int arg,RtfReader * rrc)870 int docRtfApplyDocEncodedTextGroup(
871 				const RtfControlWord *	rcw,
872 				int			arg,
873 				RtfReader *		rrc )
874     {
875     const int	gotArg=		0;
876 
877     if  ( docRtfReadGroup( rcw, gotArg, arg, rrc,
878 						(const RtfControlWord *)0,
879 						docRtfSaveDocEncodedText,
880 						rcw->rwcCommitGroup ) )
881 	{ SDEB(rcw->rcwWord); return -1;	}
882 
883     return 0;
884     }
885 
docRtfApplyRawBytesGroup(const RtfControlWord * rcw,int arg,RtfReader * rrc)886 int docRtfApplyRawBytesGroup(	const RtfControlWord *	rcw,
887 				int			arg,
888 				RtfReader *		rrc )
889     {
890     const int	gotArg=		0;
891 
892     if  ( docRtfReadGroup( rcw, gotArg, arg, rrc,
893 						(const RtfControlWord *)0,
894 						docRtfSaveRawBytes,
895 						rcw->rwcCommitGroup ) )
896 	{ SDEB(rcw->rcwWord); return -1;	}
897 
898     return 0;
899     }
900 
901 /************************************************************************/
902 /*									*/
903 /*  Just ignore a control word.						*/
904 /*									*/
905 /************************************************************************/
906 
docRtfIgnoreWord(const RtfControlWord * rcw,int arg,RtfReader * rrc)907 int docRtfIgnoreWord(	const RtfControlWord *	rcw,
908 			int			arg,
909 			RtfReader *		rrc )
910     { return 0;	}
911 
912