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