pidgin/pidgin

Remove documentation for non-public struct fields.

2019-12-19, Elliott Sales de Andrade
7a330cab3546
Remove documentation for non-public struct fields.
/*
* nmrtf.c
*
* Copyright (c) 2004 Novell, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
*
*/
/* This code was adapted from the sample RTF reader found here:
* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnrtfspec/html/rtfspec.asp
*/
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <ctype.h>
#include <string.h>
#include "nmrtf.h"
#include "debug.h"
#include "util.h"
/* Internal RTF parser error codes */
#define NMRTF_OK 0 /* Everything's fine! */
#define NMRTF_STACK_UNDERFLOW 1 /* Unmatched '}' */
#define NMRTF_STACK_OVERFLOW 2 /* Too many '{' -- memory exhausted */
#define NMRTF_UNMATCHED_BRACE 3 /* RTF ended during an open group. */
#define NMRTF_INVALID_HEX 4 /* invalid hex character found in data */
#define NMRTF_BAD_TABLE 5 /* RTF table (sym or prop) invalid */
#define NMRTF_ASSERTION 6 /* Assertion failure */
#define NMRTF_EOF 7 /* End of file reached while reading RTF */
#define NMRTF_CONVERT_ERROR 8 /* Error converting text */
#define NMRTF_MAX_DEPTH 256
typedef enum
{
NMRTF_STATE_NORMAL,
NMRTF_STATE_SKIP,
NMRTF_STATE_FONTTABLE,
NMRTF_STATE_BIN,
NMRTF_STATE_HEX
} NMRtfState; /* Rtf State */
/* Property types that we care about */
typedef enum
{
NMRTF_PROP_FONT_IDX,
NMRTF_PROP_FONT_CHARSET,
NMRTF_PROP_MAX
} NMRtfProperty;
typedef enum
{
NMRTF_SPECIAL_BIN,
NMRTF_SPECIAL_HEX,
NMRTF_SPECIAL_UNICODE,
NMRTF_SPECIAL_SKIP
} NMRtfSpecialKwd;
typedef enum
{
NMRTF_DEST_FONTTABLE,
NMRTF_DEST_SKIP
} NMRtfDestinationType;
typedef enum
{
NMRTF_KWD_CHAR,
NMRTF_KWD_DEST,
NMRTF_KWD_PROP,
NMRTF_KWD_SPEC
} NMRtfKeywordType;
typedef struct
{
/* All we care about for now is the font.
* bold, italic, underline, etc. should be
* added here
*/
int font_idx;
int font_charset;
} NMRtfCharProp;
typedef struct
{
NMRtfCharProp chp;
NMRtfState rds;
NMRtfState ris;
} NMRtfStateSave;
typedef struct
{
char *keyword; /* RTF keyword */
int default_val; /* default value to use */
gboolean pass_default; /* true to use default value from this table */
NMRtfKeywordType kwd_type; /* the type of the keyword */
int action; /* property type if the keyword represents a property */
/* destination type if the keyword represents a destination */
/* character to print if the keyword represents a character */
} NMRtfSymbol;
typedef struct
{
int number;
char *name;
int charset;
} NMRtfFont;
/* RTF Context */
struct _NMRtfContext
{
NMRtfState rds; /* destination state */
NMRtfState ris; /* internal state */
NMRtfCharProp chp; /* current character properties (ie. font, bold, italic, etc.) */
GSList *font_table; /* the font table */
GSList *saved; /* saved state stack */
int param; /* numeric parameter for the current keyword */
long bytes_to_skip; /* number of bytes to skip (after encountering \bin) */
int depth; /* how many groups deep are we */
gboolean skip_unknown; /* if true, skip any unknown destinations (this is set after encountering '\*') */
char *input; /* input string */
guchar nextch; /* next char in input */
gboolean nextch_available; /* nextch value is set */
GString *ansi; /* Temporary ansi text, will be convert/flushed to the output string */
GString *output; /* The plain text UTF8 string */
};
static int rtf_parse(NMRtfContext *ctx);
static int rtf_push_state(NMRtfContext *ctx);
static int rtf_pop_state(NMRtfContext *ctx);
static NMRtfFont *rtf_get_font(NMRtfContext *ctx, int index);
static int rtf_get_char(NMRtfContext *ctx, guchar *ch);
static int rtf_unget_char(NMRtfContext *ctx, guchar ch);
static int rtf_flush_data(NMRtfContext *ctx);
static int rtf_parse_keyword(NMRtfContext *ctx);
static int rtf_dispatch_control(NMRtfContext *ctx, char *keyword, int param, gboolean param_set);
static int rtf_dispatch_char(NMRtfContext *ctx, guchar ch);
static int rtf_dispatch_unicode_char(NMRtfContext *ctx, gunichar ch);
static int rtf_print_char(NMRtfContext *ctx, guchar ch);
static int rtf_print_unicode_char(NMRtfContext *ctx, gunichar ch);
static int rtf_change_destination(NMRtfContext *ctx, NMRtfDestinationType dest);
static int rtf_dispatch_special(NMRtfContext *ctx, NMRtfSpecialKwd special);
static int rtf_apply_property(NMRtfContext *ctx, NMRtfProperty prop, int val);
/* RTF parser tables */
/* Keyword descriptions */
NMRtfSymbol rtf_symbols[] = {
/* keyword, default, pass_default, keyword_type, action */
{"fonttbl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_FONTTABLE},
{"f", 0, FALSE, NMRTF_KWD_PROP, NMRTF_PROP_FONT_IDX},
{"fcharset", 0, FALSE, NMRTF_KWD_PROP, NMRTF_PROP_FONT_CHARSET},
{"par", 0, FALSE, NMRTF_KWD_CHAR, 0x0a},
{"line", 0, FALSE, NMRTF_KWD_CHAR, 0x0a},
{"\0x0a", 0, FALSE, NMRTF_KWD_CHAR, 0x0a},
{"\0x0d", 0, FALSE, NMRTF_KWD_CHAR, 0x0a},
{"tab", 0, FALSE, NMRTF_KWD_CHAR, 0x09},
{"\r", 0, FALSE, NMRTF_KWD_CHAR, '\r'},
{"\n", 0, FALSE, NMRTF_KWD_CHAR, '\n'},
{"ldblquote",0, FALSE, NMRTF_KWD_CHAR, '"'},
{"rdblquote",0, FALSE, NMRTF_KWD_CHAR, '"'},
{"{", 0, FALSE, NMRTF_KWD_CHAR, '{'},
{"}", 0, FALSE, NMRTF_KWD_CHAR, '}'},
{"\\", 0, FALSE, NMRTF_KWD_CHAR, '\\'},
{"bin", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_BIN},
{"*", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_SKIP},
{"'", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_HEX},
{"u", 0, FALSE, NMRTF_KWD_SPEC, NMRTF_SPECIAL_UNICODE},
{"colortbl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"author", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"buptim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"comment", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"creatim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"doccomm", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"footer", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"footerf", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"footerl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"footerr", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"footnote", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"ftncn", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"ftnsep", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"ftnsepc", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"header", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"headerf", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"headerl", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"headerr", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"info", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"keywords", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"operator", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"pict", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"printim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"private1", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"revtim", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"rxe", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"stylesheet", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"subject", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"tc", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"title", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"txe", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP},
{"xe", 0, FALSE, NMRTF_KWD_DEST, NMRTF_DEST_SKIP}
};
int table_size = sizeof(rtf_symbols) / sizeof(NMRtfSymbol);
NMRtfContext *
nm_rtf_init()
{
NMRtfContext *ctx = g_new0(NMRtfContext, 1);
ctx->nextch_available = FALSE;
ctx->ansi = g_string_new("");
ctx->output = g_string_new("");
return ctx;
}
char *
nm_rtf_strip_formatting(NMRtfContext *ctx, const char *input)
{
int status;
ctx->input = (char *)input;
status = rtf_parse(ctx);
if (status == NMRTF_OK)
return g_strdup(ctx->output->str);
purple_debug_info("novell", "RTF parser failed with error code %d\n", status);
return NULL;
}
static void
nm_rtf_font_free(NMRtfFont *font)
{
g_return_if_fail(font != NULL);
g_free(font->name);
g_free(font);
}
void
nm_rtf_deinit(NMRtfContext *ctx)
{
if (ctx) {
g_slist_free_full(ctx->font_table, (GDestroyNotify)nm_rtf_font_free);
g_slist_free_full(ctx->saved, g_free);
g_string_free(ctx->ansi, TRUE);
g_string_free(ctx->output, TRUE);
g_free(ctx);
}
}
static const char *
get_current_encoding(NMRtfContext *ctx)
{
NMRtfFont *font;
font = rtf_get_font(ctx, ctx->chp.font_idx);
switch (font->charset) {
case 0:
return "CP1252";
case 77:
return "MACINTOSH";
case 78:
return "SJIS";
case 128:
return "CP932";
case 129:
return "CP949";
case 130:
return "CP1361";
case 134:
return "CP936";
case 136:
return "CP950";
case 161:
return "CP1253";
case 162:
return "CP1254";
case 163:
return "CP1258";
case 181:
case 177:
return "CP1255";
case 178:
case 179:
case 180:
return "CP1256";
case 186:
return "CP1257";
case 204:
return "CP1251";
case 222:
return "CP874";
case 238:
return "CP1250";
case 254:
return "CP437";
default:
purple_debug_info("novell", "Unhandled font charset %d\n", font->charset);
return "CP1252";
}
}
/*
* Add an entry to the font table
*/
static int
rtf_add_font_entry(NMRtfContext *ctx, int number, const char *name, int charset)
{
NMRtfFont *font = g_new0(NMRtfFont, 1);
font->number = number;
font->name = g_strdup(name);
font->charset = charset;
purple_debug_info("novell", "Adding font to table: #%d\t%s\t%d\n",
font->number, font->name, font->charset);
ctx->font_table = g_slist_append(ctx->font_table, font);
return NMRTF_OK;
}
/*
* Return the nth entry in the font table
*/
static NMRtfFont *
rtf_get_font(NMRtfContext *ctx, int nth)
{
NMRtfFont *font;
font = g_slist_nth_data(ctx->font_table, nth);
return font;
}
/*
* Step 1:
* Isolate RTF keywords and send them to rtf_parse_keyword;
* Push and pop state at the start and end of RTF groups;
* Send text to rtf_dispatch_char for further processing.
*/
static int
rtf_parse(NMRtfContext *ctx)
{
int status;
guchar ch;
guchar hex_byte = 0;
int hex_count = 2;
int len;
if (ctx->input == NULL)
return NMRTF_OK;
while (rtf_get_char(ctx, &ch) == NMRTF_OK) {
if (ctx->depth < 0)
return NMRTF_STACK_UNDERFLOW;
/* if we're parsing binary data, handle it directly */
if (ctx->ris == NMRTF_STATE_BIN) {
if ((status = rtf_dispatch_char(ctx, ch)) != NMRTF_OK)
return status;
} else {
switch (ch) {
case '{':
if (ctx->depth > NMRTF_MAX_DEPTH)
return NMRTF_STACK_OVERFLOW;
rtf_flush_data(ctx);
if ((status = rtf_push_state(ctx)) != NMRTF_OK)
return status;
break;
case '}':
rtf_flush_data(ctx);
/* for some reason there is always an unwanted '\par' at the end */
if (ctx->rds == NMRTF_STATE_NORMAL) {
len = ctx->output->len;
if (ctx->output->str[len-1] == '\n')
ctx->output = g_string_truncate(ctx->output, len-1);
}
if ((status = rtf_pop_state(ctx)) != NMRTF_OK)
return status;
if (ctx->depth < 0)
return NMRTF_STACK_OVERFLOW;
break;
case '\\':
if ((status = rtf_parse_keyword(ctx)) != NMRTF_OK)
return status;
break;
case 0x0d:
case 0x0a: /* cr and lf are noise characters... */
break;
default:
if (ctx->ris == NMRTF_STATE_NORMAL) {
if ((status = rtf_dispatch_char(ctx, ch)) != NMRTF_OK)
return status;
} else { /* parsing a hex encoded character */
if (ctx->ris != NMRTF_STATE_HEX)
return NMRTF_ASSERTION;
hex_byte = hex_byte << 4;
if (isdigit(ch))
hex_byte += (char) ch - '0';
else {
if (islower(ch)) {
if (ch < 'a' || ch > 'f')
return NMRTF_INVALID_HEX;
hex_byte += (char) ch - 'a' + 10;
} else {
if (ch < 'A' || ch > 'F')
return NMRTF_INVALID_HEX;
hex_byte += (char) ch - 'A' + 10;
}
}
hex_count--;
if (hex_count == 0) {
if ((status = rtf_dispatch_char(ctx, hex_byte)) != NMRTF_OK)
return status;
hex_count = 2;
hex_byte = 0;
ctx->ris = NMRTF_STATE_NORMAL;
}
}
break;
}
}
}
if (ctx->depth < 0)
return NMRTF_STACK_OVERFLOW;
if (ctx->depth > 0)
return NMRTF_UNMATCHED_BRACE;
return NMRTF_OK;
}
/*
* Push the current state onto stack
*/
static int
rtf_push_state(NMRtfContext *ctx)
{
NMRtfStateSave *save = g_new0(NMRtfStateSave, 1);
save->chp = ctx->chp;
save->rds = ctx->rds;
save->ris = ctx->ris;
ctx->saved = g_slist_prepend(ctx->saved, save);
ctx->ris = NMRTF_STATE_NORMAL;
(ctx->depth)++;
return NMRTF_OK;
}
/*
* Restore the state at the top of the stack
*/
static int
rtf_pop_state(NMRtfContext *ctx)
{
NMRtfStateSave *save_old;
GSList *link_old;
if (ctx->saved == NULL)
return NMRTF_STACK_UNDERFLOW;
save_old = ctx->saved->data;
ctx->chp = save_old->chp;
ctx->rds = save_old->rds;
ctx->ris = save_old->ris;
(ctx->depth)--;
g_free(save_old);
link_old = ctx->saved;
ctx->saved = g_slist_delete_link(ctx->saved, link_old);
return NMRTF_OK;
}
/*
* Step 2:
* Get a control word (and its associated value) and
* dispatch the control.
*/
static int
rtf_parse_keyword(NMRtfContext *ctx)
{
int status = NMRTF_OK;
guchar ch;
gboolean param_set = FALSE;
gboolean is_neg = FALSE;
int param = 0;
char keyword[30];
char parameter[20];
gsize i;
keyword[0] = '\0';
parameter[0] = '\0';
if ((status = rtf_get_char(ctx, &ch)) != NMRTF_OK)
return status;
if (!isalpha(ch)) {
/* a control symbol; no delimiter. */
keyword[0] = (char) ch;
keyword[1] = '\0';
return rtf_dispatch_control(ctx, keyword, 0, param_set);
}
/* parse keyword */
for (i = 0; isalpha(ch) && (i < sizeof(keyword) - 1); rtf_get_char(ctx, &ch)) {
keyword[i] = (char) ch;
i++;
}
keyword[i] = '\0';
/* check for '-' indicated a negative parameter value */
if (ch == '-') {
is_neg = TRUE;
if ((status = rtf_get_char(ctx, &ch)) != NMRTF_OK)
return status;
}
/* check for numerical param */
if (isdigit(ch)) {
param_set = TRUE;
for (i = 0; isdigit(ch) && (i < sizeof(parameter) - 1); rtf_get_char(ctx, &ch)) {
parameter[i] = (char) ch;
i++;
}
parameter[i] = '\0';
ctx->param = param = atoi(parameter);
if (is_neg)
ctx->param = param = -param;
}
/* space after control is optional, put character back if it is not a space */
if (ch != ' ')
rtf_unget_char(ctx, ch);
return rtf_dispatch_control(ctx, keyword, param, param_set);
}
/*
* Route the character to the appropriate destination
*/
static int
rtf_dispatch_char(NMRtfContext *ctx, guchar ch)
{
if (ctx->ris == NMRTF_STATE_BIN && --(ctx->bytes_to_skip) <= 0)
ctx->ris = NMRTF_STATE_NORMAL;
switch (ctx->rds) {
case NMRTF_STATE_SKIP:
return NMRTF_OK;
case NMRTF_STATE_NORMAL:
return rtf_print_char(ctx, ch);
case NMRTF_STATE_FONTTABLE:
if (ch == ';') {
rtf_add_font_entry(ctx, ctx->chp.font_idx,
ctx->ansi->str, ctx->chp.font_charset);
g_string_truncate(ctx->ansi, 0);
}
else {
return rtf_print_char(ctx, ch);
}
return NMRTF_OK;
default:
return NMRTF_OK;
}
}
/* Handle a unicode character */
static int
rtf_dispatch_unicode_char(NMRtfContext *ctx, gunichar ch)
{
switch (ctx->rds) {
case NMRTF_STATE_SKIP:
return NMRTF_OK;
case NMRTF_STATE_NORMAL:
case NMRTF_STATE_FONTTABLE:
return rtf_print_unicode_char(ctx, ch);
default:
return NMRTF_OK;
}
}
/*
* Output a character
*/
static int
rtf_print_char(NMRtfContext *ctx, guchar ch)
{
ctx->ansi = g_string_append_c(ctx->ansi, ch);
return NMRTF_OK;
}
/*
* Output a unicode character
*/
static int
rtf_print_unicode_char(NMRtfContext *ctx, gunichar ch)
{
char buf[7];
int num;
/* convert and flush the ansi buffer to the utf8 buffer */
rtf_flush_data(ctx);
/* convert the unicode character to utf8 and add directly to the output buffer */
num = g_unichar_to_utf8((gunichar) ch, buf);
buf[num] = 0;
purple_debug_info("novell", "converted unichar 0x%X to utf8 char %s\n", ch, buf);
ctx->output = g_string_append(ctx->output, buf);
return NMRTF_OK;
}
/*
* Flush the output text
*/
static int
rtf_flush_data(NMRtfContext *ctx)
{
int status = NMRTF_OK;
char *conv_data = NULL;
const char *enc = NULL;
GError *gerror = NULL;
if (ctx->rds == NMRTF_STATE_NORMAL && ctx->ansi->len > 0) {
enc = get_current_encoding(ctx);
conv_data = g_convert(ctx->ansi->str, ctx->ansi->len, "UTF-8", enc,
NULL, NULL, &gerror);
if (conv_data) {
ctx->output = g_string_append(ctx->output, conv_data);
g_free(conv_data);
ctx->ansi = g_string_truncate(ctx->ansi, 0);
} else {
status = NMRTF_CONVERT_ERROR;
purple_debug_info("novell", "failed to convert data! error code = %d msg = %s\n",
gerror->code, gerror->message);
}
}
g_error_free(gerror);
return status;
}
/*
* Handle a property change
*/
static int
rtf_apply_property(NMRtfContext *ctx, NMRtfProperty prop, int val)
{
if (ctx->rds == NMRTF_STATE_SKIP) /* If we're skipping text, */
return NMRTF_OK; /* don't do anything. */
/* Need to flush any temporary data before a property change*/
rtf_flush_data(ctx);
switch (prop) {
case NMRTF_PROP_FONT_IDX:
ctx->chp.font_idx = val;
break;
case NMRTF_PROP_FONT_CHARSET:
ctx->chp.font_charset = val;
break;
default:
return NMRTF_BAD_TABLE;
}
return NMRTF_OK;
}
/*
* Step 3.
* Search the table for keyword and evaluate it appropriately.
*
* Inputs:
* keyword: The RTF control to evaluate.
* param: The parameter of the RTF control.
* param_set: TRUE if the control had a parameter; (that is, if param is valid)
* FALSE if it did not.
*/
static int
rtf_dispatch_control(NMRtfContext *ctx, char *keyword, int param, gboolean param_set)
{
int idx;
for (idx = 0; idx < table_size; idx++) {
if (purple_strequal(keyword, rtf_symbols[idx].keyword))
break;
}
if (idx == table_size) {
if (ctx->skip_unknown)
ctx->rds = NMRTF_STATE_SKIP;
ctx->skip_unknown = FALSE;
return NMRTF_OK;
}
/* found it! use kwd_type and action to determine what to do with it. */
ctx->skip_unknown = FALSE;
switch (rtf_symbols[idx].kwd_type) {
case NMRTF_KWD_PROP:
if (rtf_symbols[idx].pass_default || !param_set)
param = rtf_symbols[idx].default_val;
return rtf_apply_property(ctx, rtf_symbols[idx].action, param);
case NMRTF_KWD_CHAR:
return rtf_dispatch_char(ctx, rtf_symbols[idx].action);
case NMRTF_KWD_DEST:
return rtf_change_destination(ctx, rtf_symbols[idx].action);
case NMRTF_KWD_SPEC:
return rtf_dispatch_special(ctx, rtf_symbols[idx].action);
default:
return NMRTF_BAD_TABLE;
}
return NMRTF_BAD_TABLE;
}
/*
* Change to the destination specified.
*/
static int
rtf_change_destination(NMRtfContext *ctx, NMRtfDestinationType type)
{
/* if we're skipping text, don't do anything */
if (ctx->rds == NMRTF_STATE_SKIP)
return NMRTF_OK;
switch (type) {
case NMRTF_DEST_FONTTABLE:
ctx->rds = NMRTF_STATE_FONTTABLE;
g_string_truncate(ctx->ansi, 0);
break;
default:
ctx->rds = NMRTF_STATE_SKIP; /* when in doubt, skip it... */
break;
}
return NMRTF_OK;
}
/*
* Dispatch an RTF control that needs special processing
*/
static int
rtf_dispatch_special(NMRtfContext *ctx, NMRtfSpecialKwd type)
{
int status = NMRTF_OK;
guchar ch;
if (ctx->rds == NMRTF_STATE_SKIP && type != NMRTF_SPECIAL_BIN) /* if we're skipping, and it's not */
return NMRTF_OK; /* the \bin keyword, ignore it. */
switch (type) {
case NMRTF_SPECIAL_BIN:
ctx->ris = NMRTF_STATE_BIN;
ctx->bytes_to_skip = ctx->param;
break;
case NMRTF_SPECIAL_SKIP:
ctx->skip_unknown = TRUE;
break;
case NMRTF_SPECIAL_HEX:
ctx->ris = NMRTF_STATE_HEX;
break;
case NMRTF_SPECIAL_UNICODE:
purple_debug_info("novell", "parsing unichar\n");
status = rtf_dispatch_unicode_char(ctx, ctx->param);
/* Skip next char */
if (status == NMRTF_OK)
status = rtf_get_char(ctx, &ch);
break;
default:
status = NMRTF_BAD_TABLE;
break;
}
return status;
}
/*
* Get the next character from the input stream
*/
static int
rtf_get_char(NMRtfContext *ctx, guchar *ch)
{
if (ctx->nextch_available) {
*ch = ctx->nextch;
ctx->nextch_available = FALSE;
} else {
*ch = *(ctx->input);
ctx->input++;
}
if (*ch)
return NMRTF_OK;
else
return NMRTF_EOF;
}
/*
* Move a character back into the input stream
*/
static int
rtf_unget_char(NMRtfContext *ctx, guchar ch)
{
ctx->nextch = ch;
ctx->nextch_available = TRUE;
return NMRTF_OK;
}