Fix signed/unsigned comparison warnings.
[wine] / dlls / richedit / text-writer.c
1 /*
2  * text-writer -- RTF-to-text translation writer code.
3  *
4  * Read RTF input, write text of document (text extraction).
5  *
6  * Wrapper must call WriterInit() once before processing any files,
7  * then set up input and call BeginFile() for each input file.
8  *
9  * This installs callbacks for the text and control token classes.
10  * The control class is necessary so that special characters such as
11  * \par, \tab, \sect, etc.  can be converted.
12  *
13  * It's problematic what to do with text in headers and footers, and
14  * what to do about tables.
15  *
16  * This really is quite a stupid program, for instance, it could keep
17  * track of the current leader character and dump that out when a tab
18  * is encountered.
19  *
20  * 04 Feb 91    Paul DuBois     dubois@primate.wisc.edu
21  *
22  * This software may be redistributed without restriction and used for
23  * any purpose whatsoever.
24  *
25  * 04 Feb 91
26  * -Created.
27  * 27 Feb 91
28  * - Updated for distribution 1.05.
29  * 13 Jul 93
30  * - Updated to compile under THINK C 6.0.
31  * 31 Aug 93
32  * - Added Mike Sendall's entries for Macintosh char map.
33  * 07 Sep 93
34  * - Uses charset map and output sequence map for character translation.
35  * 11 Mar 94
36  * - Updated for 1.10 distribution.
37  */
38
39 #include <stdio.h>
40
41 #include "rtf.h"
42 #include "rtf2text.h"
43 #include "wine/debug.h"
44
45 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
46
47 static void     TextClass (RTF_Info *info);
48 static void     ControlClass (RTF_Info *info);
49 static void     Destination (RTF_Info *info);
50 static void     SpecialChar (RTF_Info *info);
51 static void     PutStdChar (RTF_Info *info, int stdCode);
52 static void     PutLitChar (RTF_Info *info, int c);
53 static void     PutLitStr (RTF_Info *info, char *s);
54
55 /*
56  * Initialize the writer.
57  */
58
59 void
60 WriterInit (RTF_Info *info )
61 {
62         RTFReadOutputMap (info, info->outMap,1);
63 }
64
65
66 int
67 BeginFile (RTF_Info *info )
68 {
69         /* install class callbacks */
70
71         RTFSetClassCallback (info, rtfText, TextClass);
72         RTFSetClassCallback (info, rtfControl, ControlClass);
73
74         return (1);
75 }
76
77
78 /*
79  * Write out a character.  rtfMajor contains the input character, rtfMinor
80  * contains the corresponding standard character code.
81  *
82  * If the input character isn't in the charset map, try to print some
83  * representation of it.
84  */
85
86 static void
87 TextClass (RTF_Info *info)
88 {
89 char    buf[rtfBufSiz];
90
91         TRACE("\n");
92
93         if (info->rtfFormat == SF_TEXT)
94                 PutLitChar (info, info->rtfMajor);
95         else if (info->rtfMinor != rtfSC_nothing)
96                 PutStdChar (info, info->rtfMinor);
97         else
98         {
99                 if (info->rtfMajor < 128)       /* in ASCII range */
100                         sprintf (buf, "[[%c]]", info->rtfMajor);
101                 else
102                         sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
103                 PutLitStr (info, buf);
104         }
105 }
106
107
108 static void
109 ControlClass (RTF_Info *info)
110 {
111         TRACE("\n");
112         switch (info->rtfMajor)
113         {
114         case rtfDestination:
115                 Destination (info);
116                 break;
117         case rtfSpecialChar:
118                 SpecialChar (info);
119                 break;
120         }
121 }
122
123
124 /*
125  * This function notices destinations that should be ignored
126  * and skips to their ends.  This keeps, for instance, picture
127  * data from being considered as plain text.
128  */
129
130 static void
131 Destination (RTF_Info *info)
132 {
133
134         TRACE("\n");
135
136         switch (info->rtfMinor)
137         {
138         case rtfPict:
139         case rtfFNContSep:
140         case rtfFNContNotice:
141         case rtfInfo:
142         case rtfIndexRange:
143         case rtfITitle:
144         case rtfISubject:
145         case rtfIAuthor:
146         case rtfIOperator:
147         case rtfIKeywords:
148         case rtfIComment:
149         case rtfIVersion:
150         case rtfIDoccomm:
151                 RTFSkipGroup (info);
152                 break;
153         }
154 }
155
156
157 /*
158  * The reason these use the rtfSC_xxx thingies instead of just writing
159  * out ' ', '-', '"', etc., is so that the mapping for these characters
160  * can be controlled by the text-map file.
161  */
162
163 void SpecialChar (RTF_Info *info)
164 {
165
166         TRACE("\n");
167
168         switch (info->rtfMinor)
169         {
170         case rtfPage:
171         case rtfSect:
172         case rtfRow:
173         case rtfLine:
174         case rtfPar:
175                 PutLitChar (info, '\n');
176                 break;
177         case rtfCell:
178                 PutStdChar (info, rtfSC_space); /* make sure cells are separated */
179                 break;
180         case rtfNoBrkSpace:
181                 PutStdChar (info, rtfSC_nobrkspace);
182                 break;
183         case rtfTab:
184                 PutLitChar (info, '\t');
185                 break;
186         case rtfNoBrkHyphen:
187                 PutStdChar (info, rtfSC_nobrkhyphen);
188                 break;
189         case rtfBullet:
190                 PutStdChar (info, rtfSC_bullet);
191                 break;
192         case rtfEmDash:
193                 PutStdChar (info, rtfSC_emdash);
194                 break;
195         case rtfEnDash:
196                 PutStdChar (info, rtfSC_endash);
197                 break;
198         case rtfLQuote:
199                 PutStdChar (info, rtfSC_quoteleft);
200                 break;
201         case rtfRQuote:
202                 PutStdChar (info, rtfSC_quoteright);
203                 break;
204         case rtfLDblQuote:
205                 PutStdChar (info, rtfSC_quotedblleft);
206                 break;
207         case rtfRDblQuote:
208                 PutStdChar (info, rtfSC_quotedblright);
209                 break;
210         }
211 }
212
213
214 /*
215  * Eventually this should keep track of the destination of the
216  * current state and only write text when in the initial state.
217  *
218  * If the output sequence is unspecified in the output map, write
219  * the character's standard name instead.  This makes map deficiencies
220  * obvious and provides incentive to fix it. :-)
221  */
222
223 void PutStdChar (RTF_Info *info, int stdCode)
224 {
225
226   char  *oStr = (char *) NULL;
227   char  buf[rtfBufSiz];
228
229 /*      if (stdCode == rtfSC_nothing)
230                 RTFPanic ("Unknown character code, logic error\n");
231 */
232         TRACE("\n");
233
234         oStr = info->outMap[stdCode];
235         if (oStr == (char *) NULL)      /* no output sequence in map */
236         {
237                 sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode));
238                 oStr = buf;
239         }
240         PutLitStr (info, oStr);
241 }
242
243 void PutLitChar (RTF_Info *info, int c)
244 {
245     if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) )
246         RTFFlushOutputBuffer( info );
247     info->OutputBuffer[info->dwOutputCount++] = c;
248 }
249
250 void RTFFlushOutputBuffer( RTF_Info *info )
251 {
252     info->OutputBuffer[info->dwOutputCount] = 0;
253     SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer );
254     info->dwOutputCount = 0;
255 }
256
257 static void PutLitStr (RTF_Info *info, char *str )
258 {
259     int len = strlen( str );
260     if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer )
261         RTFFlushOutputBuffer( info );
262     if( ( len + 1 ) >= sizeof info->OutputBuffer )
263     {
264         SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str );
265         return;
266     }
267     strcpy( &info->OutputBuffer[info->dwOutputCount], str );
268     info->dwOutputCount += len;
269 }