| /* | |
| * text-writer -- RTF-to-text translation writer code. | |
| * | |
| * Read RTF input, write text of document (text extraction). | |
| * | |
| * Wrapper must call WriterInit() once before processing any files, | |
| * then set up input and call BeginFile() for each input file. | |
| * | |
| * This installs callbacks for the text and control token classes. | |
| * The control class is necessary so that special characters such as | |
| * \par, \tab, \sect, etc. can be converted. | |
| * | |
| * It's problematic what to do with text in headers and footers, and | |
| * what to do about tables. | |
| * | |
| * This really is quite a stupid program, for instance, it could keep | |
| * track of the current leader character and dump that out when a tab | |
| * is encountered. | |
| * | |
| * 04 Feb 91 Paul DuBois dubois@primate.wisc.edu | |
| * | |
| * This software may be redistributed without restriction and used for | |
| * any purpose whatsoever. | |
| * | |
| * 04 Feb 91 | |
| * -Created. | |
| * 27 Feb 91 | |
| * - Updated for distribution 1.05. | |
| * 13 Jul 93 | |
| * - Updated to compile under THINK C 6.0. | |
| * 31 Aug 93 | |
| * - Added Mike Sendall's entries for Macintosh char map. | |
| * 07 Sep 93 | |
| * - Uses charset map and output sequence map for character translation. | |
| * 11 Mar 94 | |
| * - Updated for 1.10 distribution. | |
| */ | |
| #include <stdio.h> | |
| #include "rtf.h" | |
| #include "rtf2text.h" | |
| #include "wine/debug.h" | |
| WINE_DEFAULT_DEBUG_CHANNEL(richedit); | |
| static void TextClass (RTF_Info *info); | |
| static void ControlClass (RTF_Info *info); | |
| static void Destination (RTF_Info *info); | |
| static void SpecialChar (RTF_Info *info); | |
| static void PutStdChar (RTF_Info *info, int stdCode); | |
| static void PutLitChar (RTF_Info *info, int c); | |
| static void PutLitStr (RTF_Info *info, char *s); | |
| /* | |
| * Initialize the writer. | |
| */ | |
| void | |
| WriterInit (RTF_Info *info ) | |
| { | |
| RTFReadOutputMap (info, info->outMap,1); | |
| } | |
| int | |
| BeginFile (RTF_Info *info ) | |
| { | |
| /* install class callbacks */ | |
| RTFSetClassCallback (info, rtfText, TextClass); | |
| RTFSetClassCallback (info, rtfControl, ControlClass); | |
| return (1); | |
| } | |
| /* | |
| * Write out a character. rtfMajor contains the input character, rtfMinor | |
| * contains the corresponding standard character code. | |
| * | |
| * If the input character isn't in the charset map, try to print some | |
| * representation of it. | |
| */ | |
| static void | |
| TextClass (RTF_Info *info) | |
| { | |
| char buf[rtfBufSiz]; | |
| TRACE("\n"); | |
| if (info->rtfFormat == SF_TEXT) | |
| PutLitChar (info, info->rtfMajor); | |
| else if (info->rtfMinor != rtfSC_nothing) | |
| PutStdChar (info, info->rtfMinor); | |
| else | |
| { | |
| if (info->rtfMajor < 128) /* in ASCII range */ | |
| sprintf (buf, "[[%c]]", info->rtfMajor); | |
| else | |
| sprintf (buf, "[[\\'%02x]]", info->rtfMajor); | |
| PutLitStr (info, buf); | |
| } | |
| } | |
| static void | |
| ControlClass (RTF_Info *info) | |
| { | |
| TRACE("\n"); | |
| switch (info->rtfMajor) | |
| { | |
| case rtfDestination: | |
| Destination (info); | |
| break; | |
| case rtfSpecialChar: | |
| SpecialChar (info); | |
| break; | |
| } | |
| } | |
| /* | |
| * This function notices destinations that should be ignored | |
| * and skips to their ends. This keeps, for instance, picture | |
| * data from being considered as plain text. | |
| */ | |
| static void | |
| Destination (RTF_Info *info) | |
| { | |
| TRACE("\n"); | |
| switch (info->rtfMinor) | |
| { | |
| case rtfPict: | |
| case rtfFNContSep: | |
| case rtfFNContNotice: | |
| case rtfInfo: | |
| case rtfIndexRange: | |
| case rtfITitle: | |
| case rtfISubject: | |
| case rtfIAuthor: | |
| case rtfIOperator: | |
| case rtfIKeywords: | |
| case rtfIComment: | |
| case rtfIVersion: | |
| case rtfIDoccomm: | |
| RTFSkipGroup (info); | |
| break; | |
| } | |
| } | |
| /* | |
| * The reason these use the rtfSC_xxx thingies instead of just writing | |
| * out ' ', '-', '"', etc., is so that the mapping for these characters | |
| * can be controlled by the text-map file. | |
| */ | |
| void SpecialChar (RTF_Info *info) | |
| { | |
| TRACE("\n"); | |
| switch (info->rtfMinor) | |
| { | |
| case rtfPage: | |
| case rtfSect: | |
| case rtfRow: | |
| case rtfLine: | |
| case rtfPar: | |
| PutLitChar (info, '\n'); | |
| break; | |
| case rtfCell: | |
| PutStdChar (info, rtfSC_space); /* make sure cells are separated */ | |
| break; | |
| case rtfNoBrkSpace: | |
| PutStdChar (info, rtfSC_nobrkspace); | |
| break; | |
| case rtfTab: | |
| PutLitChar (info, '\t'); | |
| break; | |
| case rtfNoBrkHyphen: | |
| PutStdChar (info, rtfSC_nobrkhyphen); | |
| break; | |
| case rtfBullet: | |
| PutStdChar (info, rtfSC_bullet); | |
| break; | |
| case rtfEmDash: | |
| PutStdChar (info, rtfSC_emdash); | |
| break; | |
| case rtfEnDash: | |
| PutStdChar (info, rtfSC_endash); | |
| break; | |
| case rtfLQuote: | |
| PutStdChar (info, rtfSC_quoteleft); | |
| break; | |
| case rtfRQuote: | |
| PutStdChar (info, rtfSC_quoteright); | |
| break; | |
| case rtfLDblQuote: | |
| PutStdChar (info, rtfSC_quotedblleft); | |
| break; | |
| case rtfRDblQuote: | |
| PutStdChar (info, rtfSC_quotedblright); | |
| break; | |
| } | |
| } | |
| /* | |
| * Eventually this should keep track of the destination of the | |
| * current state and only write text when in the initial state. | |
| * | |
| * If the output sequence is unspecified in the output map, write | |
| * the character's standard name instead. This makes map deficiencies | |
| * obvious and provides incentive to fix it. :-) | |
| */ | |
| void PutStdChar (RTF_Info *info, int stdCode) | |
| { | |
| char *oStr = (char *) NULL; | |
| char buf[rtfBufSiz]; | |
| /* if (stdCode == rtfSC_nothing) | |
| RTFPanic ("Unknown character code, logic error\n"); | |
| */ | |
| TRACE("\n"); | |
| oStr = info->outMap[stdCode]; | |
| if (oStr == (char *) NULL) /* no output sequence in map */ | |
| { | |
| sprintf (buf, "[[%s]]", RTFStdCharName (info, stdCode)); | |
| oStr = buf; | |
| } | |
| PutLitStr (info, oStr); | |
| } | |
| void PutLitChar (RTF_Info *info, int c) | |
| { | |
| if( info->dwOutputCount >= ( sizeof info->OutputBuffer - 1 ) ) | |
| RTFFlushOutputBuffer( info ); | |
| info->OutputBuffer[info->dwOutputCount++] = c; | |
| } | |
| void RTFFlushOutputBuffer( RTF_Info *info ) | |
| { | |
| info->OutputBuffer[info->dwOutputCount] = 0; | |
| SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) info->OutputBuffer ); | |
| info->dwOutputCount = 0; | |
| } | |
| static void PutLitStr (RTF_Info *info, char *str ) | |
| { | |
| int len = strlen( str ); | |
| if( ( len + info->dwOutputCount + 1 ) > sizeof info->OutputBuffer ) | |
| RTFFlushOutputBuffer( info ); | |
| if( ( len + 1 ) >= sizeof info->OutputBuffer ) | |
| { | |
| SendMessageA( info->hwndEdit, EM_REPLACESEL, FALSE, (LPARAM) str ); | |
| return; | |
| } | |
| strcpy( &info->OutputBuffer[info->dwOutputCount], str ); | |
| info->dwOutputCount += len; | |
| } |