| /* |
| * 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; |
| } |