--- psiconv/trunk/lib/psiconv/gen_rtf.c 1999/10/04 16:38:15 5 +++ psiconv/trunk/lib/psiconv/gen_rtf.c 1999/10/05 15:33:38 9 @@ -68,6 +68,7 @@ }; + static void fput_text(FILE * of, const char *text, int length) { int j; @@ -76,14 +77,446 @@ } } -static void psiconv_gen_rtf_word(FILE * of, psiconv_word_f tf) +static int length_to_twips(psiconv_length_t len) +{ + return 1440.0 / 2.54 * len; +} + +static int lookup_color(psiconv_list colors,psiconv_color color) +{ + int i; + psiconv_color comp; + for (i = 0; i < psiconv_list_length(colors); i ++) { + comp = * (psiconv_color *) psiconv_list_get(colors,i); + if ((comp->red == color->red) && (comp->green == color->green) && + (comp->blue == color->blue)) + return i; + } + return -1; +} + +static void add_color(psiconv_list colors, psiconv_color color) +{ + if (color) + if (lookup_color(colors,color) < 0) + psiconv_list_add(colors,&color); +} + +static int lookup_font(psiconv_list fonts,psiconv_font font) +{ + int i; + psiconv_font comp; + for (i = 0; i < psiconv_list_length(fonts); i ++) { + comp = *(psiconv_font *) psiconv_list_get(fonts,i); + if ((comp->screenfont == font->screenfont) && + ! strcmp(comp->name,font->name)) + return i; + } + return -1; +} + +static void add_font(psiconv_list fonts, psiconv_font font) +{ + if (font) + if (lookup_font(fonts,font) < 0) + psiconv_list_add(fonts,&font); +} + +static void scan_border(psiconv_list colors,psiconv_list fonts, + psiconv_border sec) +{ + if (sec) { + add_color(colors,sec->color); + } +} + +static void scan_bullet(psiconv_list colors,psiconv_list fonts, + psiconv_bullet sec) +{ + if (sec) { + add_color(colors,sec->color); + add_font(fonts,sec->font); + } +} + +static void scan_paragraph_layout(psiconv_list colors,psiconv_list fonts, + psiconv_paragraph_layout sec) +{ + if (sec) { + add_color(colors,sec->back_color); + scan_bullet(colors,fonts,sec->bullet); + scan_border(colors,fonts,sec->left_border); + scan_border(colors,fonts,sec->right_border); + scan_border(colors,fonts,sec->top_border); + scan_border(colors,fonts,sec->bottom_border); + } +} + +static void scan_character_layout(psiconv_list colors,psiconv_list fonts, + psiconv_character_layout sec) +{ + if (sec) { + add_color(colors,sec->color); + add_color(colors,sec->back_color); + add_font(fonts,sec->font); + } +} + +static void scan_in_line_layout(psiconv_list colors,psiconv_list fonts, + psiconv_in_line_layout sec) +{ + if (sec) { + scan_character_layout(colors,fonts,sec->layout); + } +} + +static void scan_in_line_layouts(psiconv_list colors,psiconv_list fonts, + psiconv_in_line_layouts sec) +{ + int i; + psiconv_in_line_layout layout; + if (sec) { + for (i = 0; i < psiconv_list_length(sec); i++) { + layout = psiconv_list_get(sec,i); + scan_in_line_layout(colors,fonts,layout); + } + } +} + +static void scan_paragraph(psiconv_list colors,psiconv_list fonts, + psiconv_paragraph sec) +{ + if (sec) { + scan_paragraph_layout(colors,fonts,sec->base_paragraph); + scan_character_layout(colors,fonts,sec->base_character); + scan_in_line_layouts(colors,fonts,sec->in_lines); + } +} + +static void scan_text_and_layout(psiconv_list colors,psiconv_list fonts, + psiconv_text_and_layout sec) +{ + int i; + psiconv_paragraph para; + if (sec) { + for (i = 0; i < psiconv_list_length(sec); i++) { + para = psiconv_list_get(sec,i); + scan_paragraph(colors,fonts,para); + } + } +} + +static void scan_texted_section(psiconv_list colors,psiconv_list fonts, + psiconv_texted_section sec) +{ + if (sec) { + scan_text_and_layout(colors,fonts,sec->paragraphs); + } +} + +static void scan_page_header(psiconv_list colors,psiconv_list fonts, + psiconv_page_header sec) +{ + if (sec) { + scan_paragraph_layout(colors,fonts,sec->base_paragraph_layout); + scan_character_layout(colors,fonts,sec->base_character_layout); + scan_texted_section(colors,fonts,sec->text); + } +} + +static void scan_page_layout_section(psiconv_list colors,psiconv_list fonts, + psiconv_page_layout_section sec) +{ + if (sec) { + scan_page_header(colors,fonts,sec->header); + scan_page_header(colors,fonts,sec->footer); + } +} + +static void scan_word_style(psiconv_list colors,psiconv_list fonts, + psiconv_word_style sec) +{ + if (sec) { + scan_character_layout(colors,fonts,sec->character); + scan_paragraph_layout(colors,fonts,sec->paragraph); + } +} + +static void scan_word_style_list(psiconv_list colors,psiconv_list fonts, + psiconv_word_style_list sec) +{ + int i; + psiconv_word_style style; + if (sec) { + for (i = 0; i < psiconv_list_length(sec); i++) { + style = psiconv_list_get(sec,i); + scan_word_style(colors,fonts,style); + } + } +} + +static void scan_word_styles_section(psiconv_list colors,psiconv_list fonts, + psiconv_word_styles_section sec) +{ + if (sec) { + scan_word_style(colors,fonts,sec->normal); + scan_word_style_list(colors,fonts,sec->styles); + } +} + + +static void scan_word_f(psiconv_list colors,psiconv_list fonts, + psiconv_word_f sec) +{ + if (sec) { + scan_page_layout_section(colors,fonts,sec->page_sec); + scan_text_and_layout(colors,fonts,sec->paragraphs); + scan_word_styles_section(colors,fonts,sec->styles_sec); + } +} + +static void scan_texted_f(psiconv_list colors,psiconv_list fonts, + psiconv_texted_f sec) +{ + if (sec) { + scan_page_layout_section(colors,fonts,sec->page_sec); + scan_texted_section(colors,fonts,sec->texted_sec); + } +} + +static void gen_font_table(FILE *of,psiconv_list fonts) +{ + int i; + psiconv_font *font; + + fprintf(of,"{\\fonttbl"); + for (i = 0; i < psiconv_list_length(fonts); i++) { + font = psiconv_list_get(fonts,i); + fprintf(of,"{\\f%d",i); + if ((*font)->screenfont == 1) + fprintf(of,"\\fswiss"); + else if ((*font)->screenfont == 2) + fprintf(of,"\\fmodern"); + else if ((*font)->screenfont == 3) + fprintf(of,"\\froman"); + else + fprintf(of,"\\fnil"); + fprintf(of,"\\cpg1252\\f%s;}",(*font)->name); + } + fprintf(of,"}\n"); +} + +static void gen_color_table(FILE *of, psiconv_list colors) +{ + int i; + psiconv_color *color; + + fprintf(of,"{\\colortbl"); + for (i = 0; i < psiconv_list_length(colors); i++) { + color = psiconv_list_get(colors,i); + fprintf(of,"\\red%d\\green%d\\blue%d;",(*color)->red, + (*color)->green, (*color)->blue); + } + fprintf(of,"}\n"); +} + +/* This is not necessarily the same as returned by basic_character_layout_status + This one is specific for the base point of RTF */ +static psiconv_character_layout + gen_base_char(psiconv_list colors, psiconv_list fonts) +{ + struct psiconv_color white = { 0,0,0 }; + struct psiconv_color black = { 0xff,0xff,0xff }; + struct psiconv_font font = { strdup(""),-1 }; /* Pseudo - not added! */ + + struct psiconv_character_layout base_char_struct = + { + &black, /* color */ + &white, /* back_color */ + 13.0, /* font_size */ + psiconv_bool_false, /* italic */ + psiconv_bool_false, /* bold */ + psiconv_normalscript, /* super_sub */ + psiconv_bool_false, /* underline */ + psiconv_bool_false, /* strike_out */ + &font, /* font */ + }; + + add_color(colors,&white); + add_color(colors,&black); + + return psiconv_clone_character_layout(&base_char_struct); +} + +void diff_char(FILE *of,psiconv_list colors, psiconv_list fonts, + const psiconv_character_layout old, + const psiconv_character_layout new) +{ + if ((old->font->screenfont != new->font->screenfont) || + strcmp(old->font->name,new->font->name)) + fprintf(of,"\\f%d",lookup_font(fonts,new->font)); + if (old->font_size != new->font_size) + fprintf(of,"\\fs%d",(int) (new->font_size * 2)); + if (old->super_sub != new->super_sub) { + if (new->super_sub == psiconv_normalscript) + fprintf(of,"\\nosupersub"); + else if (new->super_sub == psiconv_superscript) + fprintf(of,"\\super"); + else if (new->super_sub == psiconv_subscript) + fprintf(of,"\\sub"); + } + if (old->bold != new->bold) + fprintf(of,"\\b%s",new->bold?"":"0"); + if (old->italic != new->italic) + fprintf(of,"\\i%s",new->italic?"":"0"); + if (old->underline != new->underline) + fprintf(of,"\\ul%s",new->underline?"":"0"); + if (old->strike_out != new->strike_out) + fprintf(of,"\\strike%s",new->strike_out?"":"0"); + if ((old->color->red != new->color->red) || + (old->color->green != new->color->green) || + (old->color->blue != new->color->blue)) + fprintf(of,"\\cf%d",lookup_color(colors,new->color)); + if ((old->back_color->red != new->back_color->red) || + (old->back_color->green != new->back_color->green) || + (old->back_color->blue != new->back_color->blue)) + fprintf(of,"\\cb%d",lookup_color(colors,new->back_color)); +} + + +/* Note: this generates also some character formatting; Psion Word and + RTF do not agree on what is paragraph-level formatting and what is + character-level formatting. The character-level formatting is put + at the end. This should work out. */ +static void gen_paragraph_codes(FILE *of, psiconv_list colors, + psiconv_list fonts, + psiconv_paragraph_layout para) +{ + if (para->indent_first != 0.0) + fprintf(of,"\\fl%d",length_to_twips( para->indent_first)); + if (para->indent_left != 0.0) + fprintf(of,"\\ll%d",length_to_twips(para->indent_left)); + if (para->indent_right != 0.0) + fprintf(of,"\\rl%d",length_to_twips(para->indent_right)); + if (para->justify_hor != psiconv_justify_left) { + if (para->justify_hor == psiconv_justify_right) + fprintf(of,"\\qr"); + else if (para->justify_hor == psiconv_justify_centre) + fprintf(of,"\\qc"); + else if (para->justify_hor == psiconv_justify_full) + fprintf(of,"\\qj"); +/* + else if (para->justify_hor == psiconv_justify_left) + fprintf(of,"\\ql"); +*/ + } + if (para->interline != 0.0) + fprintf(of,"\\sl%d",(para->interline_exact?-1:1) * + length_to_twips(para->interline)); + if (para->top_space != 0.0) + fprintf(of,"\\sb%d",length_to_twips(para->top_space)); + if (para->bottom_space != 0.0) + fprintf(of,"\\sa%d",length_to_twips(para->bottom_space)); + if (para->on_one_page) + fprintf(of,"\\keep"); + if (para->together_with) + fprintf(of,"\\keepn"); + if (!para->on_next_page) + fprintf(of,"pagebb"); + if (!para->no_widow_protection) + fprintf(of,"\\nowidctlpar"); +} + + +static void gen_para(FILE *of, psiconv_list colors, psiconv_list fonts, + psiconv_paragraph para) +{ + psiconv_character_layout cur_char,base_char; + psiconv_in_line_layout inl; + int loc,i,j; + + fprintf(of,"\\par\\pard"); + gen_paragraph_codes(of,colors,fonts,para->base_paragraph); + + base_char = gen_base_char(colors,fonts); + cur_char = base_char; + + if (psiconv_list_length(para->in_lines) == 0) { + diff_char(of,colors,fonts,cur_char,para->base_character); + cur_char = para->base_character; + } + loc = 0; + + for (i = 0; i < psiconv_list_length(para->in_lines); i++) { + inl = psiconv_list_get(para->in_lines,i); + diff_char(of,colors,fonts,cur_char,inl->layout); + cur_char = inl->layout; + for (j = loc; j < inl->length + loc; j ++) { + fputs(char_table[(unsigned char) (para->text[j])],of); + } + loc = j; + } + + if (loc < strlen(para->text)) { + diff_char(of,colors,fonts,cur_char,para->base_character); + cur_char = para->base_character; + for (j = loc; j < strlen(para->text); j ++) { + fputs(char_table[(unsigned char) (para->text[j])],of); + } + } + + psiconv_free_character_layout(base_char); +} + +static void gen_text(FILE *of, psiconv_list colors, psiconv_list fonts, + psiconv_text_and_layout paragraphs) { - return; + int i; + psiconv_paragraph para; + fprintf(of,"\\sect"); + for (i = 0; i < psiconv_list_length(paragraphs); i++) { + para = psiconv_list_get(paragraphs,i); + gen_para(of,colors,fonts,para); + } +} + +static void psiconv_gen_rtf_word(FILE * of, psiconv_word_f wf) +{ + psiconv_list fonts; + psiconv_list colors; + + fonts = psiconv_list_new(sizeof(psiconv_font)); + colors = psiconv_list_new(sizeof(psiconv_color)); + scan_word_f(colors,fonts,wf); + + fputs("{\\rtf1\\ansi\n",of); + gen_font_table(of,fonts); + gen_color_table(of,colors); + gen_text(of,colors,fonts,wf->paragraphs); + fputs("}\n",of); + + psiconv_list_free(fonts); + psiconv_list_free(colors); + } static void psiconv_gen_rtf_texted(FILE * of, psiconv_texted_f tf) { - return; + psiconv_list fonts; + psiconv_list colors; + + fonts = psiconv_list_new(sizeof(psiconv_font)); + colors = psiconv_list_new(sizeof(psiconv_color)); + scan_texted_f(colors,fonts,tf); + + fputs("{\\rtf1\\ansi\n",of); + gen_font_table(of,fonts); + gen_color_table(of,colors); + gen_text(of,colors,fonts,tf->texted_sec->paragraphs); + fputs("}\n",of); + + psiconv_list_free(fonts); + psiconv_list_free(colors); } void psiconv_gen_rtf(FILE * of, psiconv_file file)