blob: c050202746000c60a8cc387c9ef8f95e3d0630f8 [file] [log] [blame]
/*
* 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;
}