270 lines
5.9 KiB
C
270 lines
5.9 KiB
C
/*
|
|
* 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;
|
|
}
|