Define COBJMACROS. Fixes compilation on Windows.
[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 "charlist.h"
44 #include "wine/debug.h"
45
46 WINE_DEFAULT_DEBUG_CHANNEL(richedit);
47
48 static void     TextClass (RTF_Info *info);
49 static void     ControlClass (RTF_Info *info);
50 static void     Destination (RTF_Info *info);
51 static void     SpecialChar (RTF_Info *info);
52 static void     PutStdChar (RTF_Info *info, int stdCode);
53 static void     PutLitChar (RTF_Info *info, int c);
54 static void     PutLitStr (RTF_Info *info, char *s);
55
56 #if 0
57 static char     *outMap[rtfSC_MaxChar];
58
59 static CHARLIST charlist = {0, NULL, NULL};
60 #endif
61
62 /*int RTFToBuffer(char* pBuffer, int nBufferSize); */
63 int RTFToBuffer(RTF_Info *info, char* pBuffer, int nBufferSize)
64 {
65
66    /* check if the buffer is big enough to hold all characters  */
67    /* we require one more for the '\0'                          */
68
69    TRACE("\n");
70
71    if(nBufferSize < info->charlist.nCount + 1) {
72         return info->charlist.nCount + CHARLIST_CountChar(&info->charlist, '\n') + 1;
73    }
74
75    while(info->charlist.nCount)
76    {
77        *pBuffer = CHARLIST_Dequeue(&info->charlist);
78        if(*pBuffer=='\n')
79        {
80          *pBuffer = '\r';
81          pBuffer++;
82          *pBuffer = '\n';
83        }
84        pBuffer++;
85    }
86    *pBuffer = '\0';
87
88    return 0;
89 }
90
91
92 /*
93  * Initialize the writer.
94  */
95
96 void
97 WriterInit (RTF_Info *info )
98 {
99         RTFReadOutputMap (info, info->outMap,1);
100 }
101
102
103 int
104 BeginFile (RTF_Info *info )
105 {
106         /* install class callbacks */
107
108         RTFSetClassCallback (info, rtfText, TextClass);
109         RTFSetClassCallback (info, rtfControl, ControlClass);
110
111         return (1);
112 }
113
114
115 /*
116  * Write out a character.  rtfMajor contains the input character, rtfMinor
117  * contains the corresponding standard character code.
118  *
119  * If the input character isn't in the charset map, try to print some
120  * representation of it.
121  */
122
123 static void
124 TextClass (RTF_Info *info)
125 {
126 char    buf[rtfBufSiz];
127
128         TRACE("\n");
129
130         if (info->rtfFormat == SF_TEXT)
131                 PutLitChar (info, info->rtfMajor);
132         else if (info->rtfMinor != rtfSC_nothing)
133                 PutStdChar (info, info->rtfMinor);
134         else
135         {
136                 if (info->rtfMajor < 128)       /* in ASCII range */
137                         sprintf (buf, "[[%c]]", info->rtfMajor);
138                 else
139                         sprintf (buf, "[[\\'%02x]]", info->rtfMajor);
140                 PutLitStr (info, buf);
141         }
142 }
143
144
145 static void
146 ControlClass (RTF_Info *info)
147 {
148         TRACE("\n");
149         switch (info->rtfMajor)
150         {
151         case rtfDestination:
152                 Destination (info);
153                 break;
154         case rtfSpecialChar:
155                 SpecialChar (info);
156                 break;
157         }
158 }
159
160
161 /*
162  * This function notices destinations that should be ignored
163  * and skips to their ends.  This keeps, for instance, picture
164  * data from being considered as plain text.
165  */
166
167 static void
168 Destination (RTF_Info *info)
169 {
170
171         TRACE("\n");
172
173         switch (info->rtfMinor)
174         {
175         case rtfPict:
176         case rtfFNContSep:
177         case rtfFNContNotice:
178         case rtfInfo:
179         case rtfIndexRange:
180         case rtfITitle:
181         case rtfISubject:
182         case rtfIAuthor:
183         case rtfIOperator:
184         case rtfIKeywords:
185         case rtfIComment:
186         case rtfIVersion:
187         case rtfIDoccomm:
188                 RTFSkipGroup (info);
189                 break;
190         }
191 }
192
193
194 /*
195  * The reason these use the rtfSC_xxx thingies instead of just writing
196  * out ' ', '-', '"', etc., is so that the mapping for these characters
197  * can be controlled by the text-map file.
198  */
199
200 void SpecialChar (RTF_Info *info)
201 {
202
203         TRACE("\n");
204
205         switch (info->rtfMinor)
206         {
207         case rtfPage:
208         case rtfSect:
209         case rtfRow:
210         case rtfLine:
211         case rtfPar:
212                 PutLitChar (info, '\n');
213                 break;
214         case rtfCell:
215                 PutStdChar (info, rtfSC_space); /* make sure cells are separated */
216                 break;
217         case rtfNoBrkSpace:
218                 PutStdChar (info, rtfSC_nobrkspace);
219                 break;
220         case rtfTab:
221                 PutLitChar (info, '\t');
222                 break;
223         case rtfNoBrkHyphen:
224                 PutStdChar (info, rtfSC_nobrkhyphen);
225                 break;
226         case rtfBullet:
227                 PutStdChar (info, rtfSC_bullet);
228                 break;
229         case rtfEmDash:
230                 PutStdChar (info, rtfSC_emdash);
231                 break;
232         case rtfEnDash:
233                 PutStdChar (info, rtfSC_endash);
234                 break;
235         case rtfLQuote:
236                 PutStdChar (info, rtfSC_quoteleft);
237                 break;
238         case rtfRQuote:
239                 PutStdChar (info, rtfSC_quoteright);
240                 break;
241         case rtfLDblQuote:
242                 PutStdChar (info, rtfSC_quotedblleft);
243                 break;
244         case rtfRDblQuote:
245                 PutStdChar (info, rtfSC_quotedblright);
246                 break;
247         }
248 }
249
250
251 /*
252  * Eventually this should keep track of the destination of the
253  * current state and only write text when in the initial state.
254  *
255  * If the output sequence is unspecified in the output map, write
256  * the character's standard name instead.  This makes map deficiencies
257  * obvious and provides incentive to fix it. :-)
258  */
259
260 void PutStdChar (RTF_Info *info, int stdCode)
261 {
262
263   char  *oStr = (char *) NULL;
264   char  buf[rtfBufSiz];
265
266 /*      if (stdCode == rtfSC_nothing)
267                 RTFPanic ("Unknown character code, logic error\n");
268 */
269         TRACE("\n");
270
271         oStr = info->outMap[stdCode];
272         if (oStr == (char *) NULL)      /* no output sequence in map */
273         {
274                 sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode));
275                 oStr = buf;
276         }
277         PutLitStr (info, oStr);
278 }
279
280
281 void PutLitChar (RTF_Info *info, int c)
282 {
283         CHARLIST_Enqueue(&info->charlist, (char) c);
284         /* fputc (c, ostream); */
285 }
286
287
288 static void PutLitStr (RTF_Info *info, char     *s)
289 {
290         for(;*s;s++)
291         {
292           CHARLIST_Enqueue(&info->charlist, *s);
293         }
294         /* fputs (s, ostream); */
295 }