1 | /* |
|
|
2 | * gen_html4.c - Part of psiconv, a PSION 5 data formats converter |
1 | /* gen_html.c - Part of psiconv, a PSION 5 file formats converter |
3 | * Copyright (c) 1999 Andrew Johnson <anjohnson@iee.org> |
|
|
4 | * Portions Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> |
2 | Copyright (c) 1999-2004 Frodo Looijaard <frodol@dds.nl> |
5 | * |
3 | |
6 | * This program is free software; you can redistribute it and/or modify |
4 | This program is free software; you can redistribute it and/or modify |
7 | * it under the terms of the GNU General Public License as published by |
5 | it under the terms of the GNU General Public License as published by |
8 | * the Free Software Foundation; either version 2 of the License, or |
6 | the Free Software Foundation; either version 2 of the License, or |
9 | * (at your option) any later version. |
7 | (at your option) any later version. |
10 | * |
8 | |
11 | * This program is distributed in the hope that it will be useful, |
9 | This program is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | * GNU General Public License for more details. |
12 | GNU General Public License for more details. |
15 | * |
13 | |
16 | * You should have received a copy of the GNU General Public License |
14 | You should have received a copy of the GNU General Public License |
17 | * along with this program; if not, write to the Free Software |
15 | along with this program; if not, write to the Free Software |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
16 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
19 | */ |
|
|
20 | |
|
|
21 | /* |
|
|
22 | 2002/Apr. Keita KAWABE |
|
|
23 | A: <META HTTP-EQUIV="Content-Type" CONTENT="text/html"> header |
|
|
24 | was added. |
|
|
25 | |
|
|
26 | B: Support for narrow build Asian Psions added. |
|
|
27 | If the encoding_type is PSICONV_ENCODING_UTF8, |
|
|
28 | B-1: use utf8_table for character conversion. |
|
|
29 | B-2: add the "Charset=UTF-8" in the Content-Type header. |
|
|
30 | Otherwise proceed as normal. |
|
|
31 | */ |
17 | */ |
32 | |
18 | |
33 | #include "config.h" |
19 | #include "config.h" |
34 | #include <stdio.h> |
20 | |
|
|
21 | #include <psiconv/configuration.h> |
|
|
22 | #include <psiconv/data.h> |
|
|
23 | #include "general.h" |
|
|
24 | |
35 | #include <string.h> |
25 | #include <string.h> |
36 | #include <ctype.h> |
|
|
37 | #include <stdlib.h> |
26 | #include <stdlib.h> |
38 | #include "psiconv/data.h" |
|
|
39 | #include "psiconv/list.h" |
|
|
40 | #include "gen.h" |
|
|
41 | #include "psiconv.h" |
|
|
42 | |
|
|
43 | #ifndef TRUE |
|
|
44 | #define TRUE (0==0) |
|
|
45 | #endif |
|
|
46 | |
27 | |
47 | #ifdef DMALLOC |
28 | #ifdef DMALLOC |
48 | #include "dmalloc.h" |
29 | #include "dmalloc.h" |
49 | #endif |
30 | #endif |
50 | |
31 | |
51 | /* |
32 | #define TEMPSTR_LEN 100 |
52 | * Various string tables for HTML4 settings |
|
|
53 | */ |
|
|
54 | |
33 | |
55 | /* How to display each character */ |
34 | static void text(const psiconv_config config,psiconv_list list, |
56 | static const char *char_table[0x100] = { |
35 | psiconv_string_t data,const encoding enc); |
57 | /* 0x00 */ "", "", "", "", "", "", "<BR>\n", "<BR>\n", |
36 | static void header(const psiconv_config config, psiconv_list list, |
58 | /* 0x08 */ "\n<HR>\n", "\t", "", "", "", "", "", "", |
37 | const encoding enc); |
59 | /* 0x10 */ " ", "", "", "", "", "", "", "", |
38 | static void footer(const psiconv_config config, psiconv_list list, |
60 | /* 0x18 */ "", "", "", "", "", "", "", "", |
39 | const encoding enc); |
61 | /* 0x20 */ " ", "!", """, "#", "$", "%", "&", "'", |
40 | static void characters(const psiconv_config config, psiconv_list list, |
62 | /* 0x28 */ "(", ")", "*", "+", ",", "-", ".", "/", |
41 | const psiconv_string_t textstr, |
63 | /* 0x30 */ "0", "1", "2", "3", "4", "5", "6", "7", |
42 | const psiconv_character_layout layout,const encoding enc); |
64 | /* 0x38 */ "8", "9", ":", ";", "<", "=", ">", "?", |
43 | static void paragraph(const psiconv_config config, psiconv_list list, |
65 | /* 0x40 */ "@", "A", "B", "C", "D", "E", "F", "G", |
44 | psiconv_paragraph para, const encoding enc); |
66 | /* 0x48 */ "H", "I", "J", "K", "L", "M", "N", "O", |
45 | static void paragraphs(const psiconv_config config, psiconv_list list, |
67 | /* 0x50 */ "P", "Q", "R", "S", "T", "U", "V", "W", |
46 | psiconv_text_and_layout paragraphs, const encoding enc); |
68 | /* 0x58 */ "X", "Y", "Z", "[", "\\", "]", "^", "_", |
47 | static void gen_word(const psiconv_config config, psiconv_list list, |
69 | /* 0x60 */ "`", "a", "b", "c", "d", "e", "f", "g", |
48 | const psiconv_word_f file, const encoding enc); |
70 | /* 0x68 */ "h", "i", "j", "k", "l", "m", "n", "o", |
49 | static void gen_texted(const psiconv_config config, psiconv_list list, |
71 | /* 0x70 */ "p", "q", "r", "s", "t", "u", "v", "w", |
50 | const psiconv_texted_f file, const encoding enc); |
72 | /* 0x78 */ "x", "y", "z", "{", "|", "}", "~", "", |
|
|
73 | /* 0x80 */ "", "", "‚", "ƒ", |
|
|
74 | "„", "…", "†", "‡", |
|
|
75 | /* 0x88 */ "ˆ", "‰", "Š", "<", |
|
|
76 | "Œ", "", "", "", |
|
|
77 | /* 0x90 */ "", "‘", "’", "“", |
|
|
78 | "”","•", "–", "—", |
|
|
79 | /* 0x98 */ "˜", "™", "š", ">", |
|
|
80 | "œ", "", "", "Ÿ", |
|
|
81 | /* 0xa0 */ " ", "¡", "¢", "£", |
|
|
82 | "¤", "¥", "¦", "§", |
|
|
83 | /* 0xa8 */ "¨", "©", "ª", "«", |
|
|
84 | "¬", "­", "®", "¯", |
|
|
85 | /* 0xb0 */ "°", "±", "²", "³", |
|
|
86 | "´", "µ", "¶", "·", |
|
|
87 | /* 0xb8 */ "¸", "¹", "º", "»", |
|
|
88 | "¼", "½", "¾", "¿", |
|
|
89 | /* 0xc0 */ "À", "Á", "Â", "Ã", |
|
|
90 | "Ä", "Å", "Æ", "Ç", |
|
|
91 | /* 0xc8 */ "È", "É", "Ê", "Ë", |
|
|
92 | "Ì", "Í", "Î", "Ï", |
|
|
93 | /* 0xd0 */ "Ð", "Ñ", "Ò", "Ó", |
|
|
94 | "Ô", "Õ", "Ö", "×", |
|
|
95 | /* 0xd8 */ "Ø", "Ù", "Ú", "Û", |
|
|
96 | "Ü", "Ý", "Þ", "ß", |
|
|
97 | /* 0xe0 */ "à", "á", "â", "ã", |
|
|
98 | "ä", "å", "æ", "ç", |
|
|
99 | /* 0xe8 */ "è", "é", "ê", "ë", |
|
|
100 | "ì", "í", "î", "ï", |
|
|
101 | /* 0xf0 */ "ð", "ñ", "ò", "ó", |
|
|
102 | "ô", "õ", "ö", "÷", |
|
|
103 | /* 0xf8 */ "ø", "ù", "ú", "û", |
|
|
104 | "ü", "ý", "þ", "ÿ" |
|
|
105 | }; |
|
|
106 | |
51 | |
107 | static const char *utf_table[0x100] = { |
|
|
108 | /* 0x00 */ "", "", "", "", "", "", "<BR>\n", "<BR>\n", |
|
|
109 | /* 0x08 */ "\n<HR>\n", "\t", "", "", "", "", "", "", |
|
|
110 | /* 0x10 */ " ", "", "", "", "", "", "", "", |
|
|
111 | /* 0x18 */ "", "", "", "", "", "", "", "", |
|
|
112 | /* 0x20 */ " ", "!", """, "#", "$", "%", "&", "'", |
|
|
113 | /* 0x28 */ "(", ")", "*", "+", ",", "-", ".", "/", |
|
|
114 | /* 0x30 */ "0", "1", "2", "3", "4", "5", "6", "7", |
|
|
115 | /* 0x38 */ "8", "9", ":", ";", "<", "=", ">", "?", |
|
|
116 | /* 0x40 */ "@", "A", "B", "C", "D", "E", "F", "G", |
|
|
117 | /* 0x48 */ "H", "I", "J", "K", "L", "M", "N", "O", |
|
|
118 | /* 0x50 */ "P", "Q", "R", "S", "T", "U", "V", "W", |
|
|
119 | /* 0x58 */ "X", "Y", "Z", "[", "\\", "]", "^", "_", |
|
|
120 | /* 0x60 */ "`", "a", "b", "c", "d", "e", "f", "g", |
|
|
121 | /* 0x68 */ "h", "i", "j", "k", "l", "m", "n", "o", |
|
|
122 | /* 0x70 */ "p", "q", "r", "s", "t", "u", "v", "w", |
|
|
123 | /* 0x78 */ "x", "y", "z", "{", "|", "}", "~", "", |
|
|
124 | /* 0x80 */ "\x80", "\x81", "\x82", "\x83", "\x84", "\x85", "\x86", "\x87", |
|
|
125 | /* 0x88 */ "\x88", "\x89", "\x8a", "\x8b", "\x8c", "\x8d", "\x8e", "\x8f", |
|
|
126 | /* 0x90 */ "\x90", "\x91", "\x92", "\x93", "\x94", "\x95", "\x96", "\x97", |
|
|
127 | /* 0x98 */ "\x98", "\x99", "\x9a", "\x9b", "\x9c", "\x9d", "\x9e", "\x9f", |
|
|
128 | /* 0xa0 */ "\xa0", "\xa1", "\xa2", "\xa3", "\xa4", "\xa5", "\xa6", "\xa7", |
|
|
129 | /* 0xa8 */ "\xa8", "\xa9", "\xaa", "\xab", "\xac", "\xad", "\xae", "\xaf", |
|
|
130 | /* 0xb0 */ "\xb0", "\xb1", "\xb2", "\xb3", "\xb4", "\xb5", "\xb6", "\xb7", |
|
|
131 | /* 0xb8 */ "\xb8", "\xb9", "\xba", "\xbb", "\xbc", "\xbd", "\xbe", "\xbf", |
|
|
132 | /* 0xc0 */ "\xc0", "\xc1", "\xc2", "\xc3", "\xc4", "\xc5", "\xc6", "\xc7", |
|
|
133 | /* 0xc8 */ "\xc8", "\xc9", "\xca", "\xcb", "\xcc", "\xcd", "\xce", "\xcf", |
|
|
134 | /* 0xd0 */ "\xd0", "\xd1", "\xd2", "\xd3", "\xd4", "\xd5", "\xd6", "\xd7", |
|
|
135 | /* 0xd8 */ "\xd8", "\xd9", "\xda", "\xdb", "\xdc", "\xdd", "\xde", "\xdf", |
|
|
136 | /* 0xe0 */ "\xe0", "\xe1", "\xe2", "\xe3", "\xe4", "\xe5", "\xe6", "\xe7", |
|
|
137 | /* 0xe8 */ "\xe8", "\xe9", "\xea", "\xeb", "\xec", "\xed", "\xee", "\xef", |
|
|
138 | /* 0xf0 */ "\xf0", "\xf1", "\xf2", "\xf3", "\xf4", "\xf5", "\xf6", "\xf7", |
|
|
139 | /* 0xf8 */ "\xf8", "\xf9", "\xfa", "\xfb", "\xfc", "\xfd", "\xfe", "\xff", |
|
|
140 | }; |
|
|
141 | |
52 | |
142 | /* a flag to indicate the use of UTF8 */ |
53 | void text(const psiconv_config config,psiconv_list list, |
143 | static psiconv_encoding encoding=PSICONV_ENCODING_CP1252; |
54 | psiconv_string_t data,const encoding enc) |
144 | |
55 | { |
145 | |
|
|
146 | /* The order of these must match the enum psiconv_border_kind (data.h) */ |
|
|
147 | static const char *border_strings[] = { |
|
|
148 | "none", "solid", "double", "dotted", "dashed", "dashed", "dotted" |
|
|
149 | }; |
|
|
150 | |
|
|
151 | /* The order of these must match the enum psiconv_justify (data.h) */ |
|
|
152 | static const char *justify_strings[] = { |
|
|
153 | "left", "center", "right", "justify" |
|
|
154 | }; |
|
|
155 | |
|
|
156 | /* The order of these must match the enum psiconv_super_sub (data.h) */ |
|
|
157 | static const char *vertical_strings[] = { |
|
|
158 | "baseline", "super", "sub" |
|
|
159 | }; |
|
|
160 | |
|
|
161 | |
|
|
162 | /* |
|
|
163 | * Support routines for particular formatting structures |
|
|
164 | */ |
|
|
165 | |
|
|
166 | static void fput_name(FILE * of, const char *string) { |
|
|
167 | int i; |
56 | int i; |
168 | |
57 | for (i = 0; i < psiconv_unicode_strlen(data); i++) { |
169 | for (i = 0; i < strlen(string); i++) |
58 | if ((data[i] == 0x06) || (data[i] == 0x07) || (data[i] == 0x08)) |
170 | if (isalnum(string[i])) |
59 | output_simple_chars(config,list,"<BR>",enc); |
171 | putc(string[i], of); |
60 | else if ((data[i] == 0x0b) || (data[i] == 0x0c)) |
|
|
61 | output_simple_chars(config,list,"-",enc); |
|
|
62 | else if (data[i] == 0x0f) |
|
|
63 | output_simple_chars(config,list," ",enc); |
|
|
64 | else if (data[i] >= 0x20) |
|
|
65 | output_char(config,list,data[i],enc); |
|
|
66 | } |
172 | } |
67 | } |
173 | |
68 | |
174 | static void fput_text(FILE * of, const char *text, int length, int *pwasspace) { |
69 | void header(const psiconv_config config, psiconv_list list, const encoding enc) |
175 | int j; |
70 | { |
176 | int space; |
71 | output_simple_chars(config,list,"<!DOCTYPE html PUBLIC " |
177 | char ** table; |
72 | "\"-//W3C//DTD HTML 4.01 Transitional//EN\" " |
178 | if (encoding == PSICONV_ENCODING_UTF8){ |
73 | "\"http://www.w3.org/TR/html4/loose.dtd\">\n", |
179 | table = (char**) utf_table; |
74 | enc); |
|
|
75 | output_simple_chars(config,list,"<HTML>\n",enc); |
|
|
76 | output_simple_chars(config,list,"<HEAD>\n",enc); |
|
|
77 | output_simple_chars(config,list,"<META HTTP-EQUIV=\"Content-Type\" " |
|
|
78 | "CONTENT=\"text/html; charset=",enc); |
|
|
79 | output_simple_chars(config,list,enc==ENCODING_UTF8?"UTF-8": |
|
|
80 | enc==ENCODING_UCS2?"UTF-16BE": |
|
|
81 | enc==ENCODING_ASCII?"US-ASCII": |
|
|
82 | "",enc); |
|
|
83 | output_simple_chars(config,list,"\">\n",enc); |
|
|
84 | output_simple_chars(config,list,"<TITLE>EPOC32 file " |
|
|
85 | "converted by psiconv</TITLE>\n",enc); |
|
|
86 | output_simple_chars(config,list,"</HEAD>\n",enc); |
|
|
87 | output_simple_chars(config,list,"<BODY>\n",enc); |
|
|
88 | } |
|
|
89 | |
|
|
90 | void footer(const psiconv_config config, psiconv_list list, const encoding enc) |
|
|
91 | { |
|
|
92 | output_simple_chars(config,list,"</BODY>\n",enc); |
|
|
93 | output_simple_chars(config,list,"</HTML>\n",enc); |
|
|
94 | } |
|
|
95 | |
|
|
96 | |
|
|
97 | void characters(const psiconv_config config, psiconv_list list, |
|
|
98 | const psiconv_string_t textstr, |
|
|
99 | const psiconv_character_layout layout,const encoding enc) |
|
|
100 | { |
|
|
101 | char tempstr[TEMPSTR_LEN]; |
|
|
102 | |
|
|
103 | output_simple_chars(config,list,"<FONT face=\"",enc); |
|
|
104 | output_simple_chars(config,list, |
|
|
105 | layout->font->screenfont == psiconv_font_serif?"serif": |
|
|
106 | layout->font->screenfont == psiconv_font_sansserif?"sans-serif": |
|
|
107 | layout->font->screenfont == psiconv_font_nonprop?"monospace": |
|
|
108 | layout->font->screenfont == psiconv_font_misc?"fantasy":"", |
|
|
109 | enc); |
|
|
110 | output_simple_chars(config,list,"\"",enc); |
|
|
111 | |
|
|
112 | if ((layout->font_size < 10) || (layout->font_size >= 13)) { |
|
|
113 | output_simple_chars(config,list," size=",enc); |
|
|
114 | output_simple_chars(config,list, |
|
|
115 | layout->font_size < 8 ?"1": |
|
|
116 | layout->font_size < 10 ?"2": |
|
|
117 | layout->font_size < 13 ?"3": |
|
|
118 | layout->font_size < 17 ?"4": |
|
|
119 | layout->font_size < 24 ?"5": |
|
|
120 | layout->font_size < 36 ?"6":"7",enc); |
|
|
121 | } |
|
|
122 | if ((layout->color->red != 0) || (layout->color->green != 0) || |
|
|
123 | (layout->color->blue != 0)) { |
|
|
124 | snprintf(tempstr,TEMPSTR_LEN,"%02x%02x%02x", |
|
|
125 | layout->color->red,layout->color->green,layout->color->blue); |
|
|
126 | output_simple_chars(config,list," color=#",enc); |
|
|
127 | output_simple_chars(config,list,tempstr,enc); |
|
|
128 | } |
|
|
129 | output_simple_chars(config,list,">",enc); |
|
|
130 | |
|
|
131 | |
|
|
132 | if (layout->italic) |
|
|
133 | output_simple_chars(config,list,"<I>",enc); |
|
|
134 | if (layout->bold) |
|
|
135 | output_simple_chars(config,list,"<B>",enc); |
|
|
136 | if (layout->super_sub != psiconv_normalscript) |
|
|
137 | output_simple_chars(config,list, |
|
|
138 | layout->super_sub == psiconv_superscript?"<SUP>": |
|
|
139 | layout->super_sub == psiconv_subscript?"<SUB>": |
|
|
140 | "",enc); |
|
|
141 | if (layout->strikethrough) |
|
|
142 | output_simple_chars(config,list,"<S>",enc); |
|
|
143 | if (layout->underline) |
|
|
144 | output_simple_chars(config,list,"<U>",enc); |
|
|
145 | |
|
|
146 | text(config,list,textstr,enc); |
|
|
147 | |
|
|
148 | if (layout->underline) |
|
|
149 | output_simple_chars(config,list,"</U>",enc); |
|
|
150 | if (layout->strikethrough) |
|
|
151 | output_simple_chars(config,list,"</S>",enc); |
|
|
152 | if (layout->super_sub != psiconv_normalscript) |
|
|
153 | output_simple_chars(config,list, |
|
|
154 | layout->super_sub == psiconv_superscript?"</SUP>": |
|
|
155 | layout->super_sub == psiconv_subscript?"</SUB>": |
|
|
156 | "",enc); |
|
|
157 | if (layout->bold) |
|
|
158 | output_simple_chars(config,list,"</B>",enc); |
|
|
159 | if (layout->italic) |
|
|
160 | output_simple_chars(config,list,"</I>",enc); |
|
|
161 | output_simple_chars(config,list,"</FONT>",enc); |
|
|
162 | } |
|
|
163 | |
|
|
164 | void paragraph(const psiconv_config config, psiconv_list list, |
|
|
165 | psiconv_paragraph para, const encoding enc) |
|
|
166 | { |
|
|
167 | int i,charnr; |
|
|
168 | psiconv_string_t text; |
|
|
169 | psiconv_in_line_layout layout; |
|
|
170 | |
|
|
171 | |
|
|
172 | output_simple_chars(config,list, |
|
|
173 | para->base_paragraph->bullet->on?"<UL><LI":"<P",enc); |
|
|
174 | |
|
|
175 | if (para->base_paragraph->justify_hor == psiconv_justify_centre) |
|
|
176 | output_simple_chars(config,list," align=center",enc); |
|
|
177 | else if (para->base_paragraph->justify_hor == psiconv_justify_right) |
|
|
178 | output_simple_chars(config,list," align=right",enc); |
|
|
179 | else if (para->base_paragraph->justify_hor == psiconv_justify_full) |
|
|
180 | output_simple_chars(config,list," align=justify",enc); |
|
|
181 | |
|
|
182 | output_simple_chars(config,list,">",enc); |
|
|
183 | |
|
|
184 | if (psiconv_list_length(para->in_lines) == 0) { |
|
|
185 | characters(config,list,para->text,para->base_character,enc); |
180 | }else{ |
186 | } else { |
181 | table=(char**) char_table; |
187 | charnr = 0; |
|
|
188 | for (i = 0; i < psiconv_list_length(para->in_lines); i++) { |
|
|
189 | if (!(layout = psiconv_list_get(para->in_lines,i))) { |
|
|
190 | fputs("Internal data structures corruption\n",stderr); |
|
|
191 | exit(1); |
|
|
192 | } |
|
|
193 | if (!(text = malloc(sizeof (*text) * (layout->length + 1)))) { |
|
|
194 | fputs("Out of memory error\n",stderr); |
|
|
195 | exit(1); |
|
|
196 | } |
|
|
197 | memcpy(text,para->text+charnr,layout->length * sizeof(*text)); |
|
|
198 | text[layout->length] = 0; |
|
|
199 | characters(config,list,text,layout->layout,enc); |
|
|
200 | free(text); |
|
|
201 | charnr += layout->length; |
182 | } |
202 | } |
183 | |
203 | } |
184 | for (j = 0; j < length; j++) { |
204 | output_simple_chars(config, list, |
185 | space = (text[j] == ' '); |
205 | para->base_paragraph->bullet->on?"</UL>\n":"\n",enc); |
186 | if (*pwasspace && space) |
206 | } |
187 | fputs(" ", of); |
207 | |
188 | else |
208 | void paragraphs(const psiconv_config config, psiconv_list list, |
189 | fputs(table[(unsigned char) (text[j])], of); |
209 | psiconv_text_and_layout paragraphs, const encoding enc) |
190 | *pwasspace = space; |
210 | { |
|
|
211 | int i; |
|
|
212 | psiconv_paragraph para; |
|
|
213 | for (i = 0; i < psiconv_list_length(paragraphs); i++) { |
|
|
214 | if (!(para = psiconv_list_get(paragraphs,i))) { |
|
|
215 | fputs("Internal datastructure corruption\n",stderr); |
|
|
216 | exit(1); |
191 | } |
217 | } |
|
|
218 | paragraph(config,list,para,enc); |
|
|
219 | } |
192 | } |
220 | } |
193 | |
221 | |
194 | static const char *screenfont_name(psiconv_u8 screenfont) |
222 | void gen_word(const psiconv_config config, psiconv_list list, |
|
|
223 | const psiconv_word_f file, const encoding enc) |
195 | { |
224 | { |
196 | if (screenfont == psiconv_font_sansserif) |
225 | if (!file) |
197 | return "sans-serif"; |
226 | return; |
198 | else if (screenfont == psiconv_font_nonprop) |
227 | |
199 | return "monospace"; |
228 | header(config,list,enc); |
200 | else if (screenfont == psiconv_font_serif) |
229 | paragraphs(config,list,file->paragraphs,enc); |
|
|
230 | footer(config,list,enc); |
|
|
231 | } |
|
|
232 | |
|
|
233 | |
|
|
234 | void gen_texted(const psiconv_config config, psiconv_list list, |
|
|
235 | const psiconv_texted_f file, const encoding enc) |
|
|
236 | { |
|
|
237 | header(config,list,enc); |
|
|
238 | paragraphs(config,list,file->texted_sec->paragraphs,enc); |
|
|
239 | footer(config,list,enc); |
|
|
240 | } |
|
|
241 | |
|
|
242 | int gen_html4(const psiconv_config config, psiconv_list list, |
|
|
243 | const psiconv_file file, const char *dest, |
|
|
244 | const encoding enc) |
|
|
245 | { |
|
|
246 | encoding enc1 = enc; |
|
|
247 | |
|
|
248 | if (enc == ENCODING_PSION) { |
|
|
249 | fputs("Unsupported encoding\n",stderr); |
|
|
250 | return -1; |
|
|
251 | } else if (enc == ENCODING_ASCII) |
|
|
252 | enc1 = ENCODING_ASCII_HTML; |
|
|
253 | |
|
|
254 | if (file->type == psiconv_word_file) { |
|
|
255 | gen_word(config,list,(psiconv_word_f) file->file,enc1); |
201 | return "serif"; |
256 | return 0; |
|
|
257 | } else if (file->type == psiconv_texted_file) { |
|
|
258 | gen_texted(config,list,(psiconv_texted_f) file->file,enc1); |
|
|
259 | return 0; |
202 | else |
260 | } else |
203 | return "serif"; |
261 | return -1; |
204 | } |
262 | } |
|
|
263 | |
205 | |
264 | |
206 | static const char *generic_font_family(const char *font_name) { |
265 | static struct fileformat_s ffs[] = |
207 | static const char *sans_font_names[] = { |
266 | { |
208 | "Arial", "Univers", "Sans Serif" |
|
|
209 | }; |
|
|
210 | static const char *mono_font_names[] = { |
|
|
211 | "Courier New", "Courier", "Mono", "Lineprinter", "Elite", "Swiss", |
|
|
212 | "Courier (compressed)", "Courier (expanded)", "Letter Gothic" |
|
|
213 | }; |
|
|
214 | int i; |
|
|
215 | |
267 | { |
216 | for (i=0; i < sizeof(sans_font_names) / sizeof(sans_font_names[0]); i++) |
268 | "HTML4", |
217 | if (!strcmp(font_name, sans_font_names[i])) |
269 | "HTML 4.01 Transitional, without CSS", |
218 | return "sans-serif"; |
270 | FORMAT_WORD | FORMAT_TEXTED, |
|
|
271 | gen_html4 |
|
|
272 | }, |
219 | |
273 | { |
220 | for (i=0; i < sizeof(mono_font_names) / sizeof(mono_font_names[0]); i++) |
274 | NULL, |
221 | if (!strcmp(font_name, mono_font_names[i])) |
275 | NULL, |
222 | return "monospace"; |
276 | 0, |
223 | |
277 | NULL |
224 | return "serif"; |
|
|
225 | } |
|
|
226 | |
|
|
227 | static int colors_different( |
|
|
228 | const psiconv_color old, |
|
|
229 | const psiconv_color new) |
|
|
230 | { |
|
|
231 | return ((old->red != new->red) || |
|
|
232 | (old->green != new->green) || |
|
|
233 | (old->blue != new->blue)); |
|
|
234 | } |
|
|
235 | |
|
|
236 | |
|
|
237 | /* Borders */ |
|
|
238 | static int borders_different( |
|
|
239 | const psiconv_border old, |
|
|
240 | const psiconv_border new) |
|
|
241 | { |
|
|
242 | return (!old || |
|
|
243 | (old->kind != new->kind) || |
|
|
244 | colors_different(old->color, new->color) || |
|
|
245 | (old->thickness != new->thickness)); |
|
|
246 | } |
|
|
247 | |
|
|
248 | static void fput_border(FILE * of, |
|
|
249 | const char *which, |
|
|
250 | const psiconv_border old, |
|
|
251 | const psiconv_border new) |
|
|
252 | { |
|
|
253 | /* If the border changed at all we'll set all parameters, as they're |
|
|
254 | * fairly closely linked and it's much easier to do it this way */ |
|
|
255 | if (borders_different(old, new)) { |
|
|
256 | fprintf(of, "border-%s-style:%s;", |
|
|
257 | which, border_strings[new->kind]); |
|
|
258 | if ((new->kind != psiconv_border_none) && |
|
|
259 | (new->color->red || new->color->green || new->color->blue)) |
|
|
260 | fprintf(of, "border-%s-color:#%02x%02x%02x;", which, |
|
|
261 | new->color->red, new->color->green, new->color->blue); |
|
|
262 | if ((new->kind == psiconv_border_solid) || |
|
|
263 | (new->kind == psiconv_border_double)) |
|
|
264 | fprintf(of, "border-%s-width:%.0fpx;", |
|
|
265 | which, (new->thickness / 10.0) - 1); |
|
|
266 | else if (new->kind != psiconv_border_none) |
|
|
267 | fprintf(of, "border-%s-width:1px;", which); |
|
|
268 | } |
278 | } |
269 | } |
|
|
270 | |
|
|
271 | /* Paragraph formats */ |
|
|
272 | static int paragraph_layouts_different( |
|
|
273 | const psiconv_paragraph_layout old, |
|
|
274 | const psiconv_paragraph_layout new) |
|
|
275 | { |
|
|
276 | return ((old->space_above != new->space_above) || |
|
|
277 | (old->indent_right != new->indent_right) || |
|
|
278 | (old->space_below != new->space_below) || |
|
|
279 | (old->indent_left != new->indent_left) || |
|
|
280 | (old->indent_first != new->indent_first) || |
|
|
281 | (old->justify_hor != new->justify_hor) || |
|
|
282 | (old->linespacing_exact != new->linespacing_exact) || |
|
|
283 | borders_different(old->left_border, new->left_border) || |
|
|
284 | borders_different(old->right_border, new->right_border) || |
|
|
285 | borders_different(old->top_border, new->top_border) || |
|
|
286 | borders_different(old->bottom_border, new->bottom_border)); |
|
|
287 | } |
|
|
288 | |
|
|
289 | static void fput_paragraph_layout(FILE * of, |
|
|
290 | const psiconv_paragraph_layout old, |
|
|
291 | const psiconv_paragraph_layout new) |
|
|
292 | { |
|
|
293 | if (!old || (old->space_above != new->space_above)) |
|
|
294 | fprintf(of, "margin-top:%.1fpt;", new->space_above); |
|
|
295 | if (!old || (old->indent_right != new->indent_right)) |
|
|
296 | fprintf(of, "margin-right:%.2fcm;", new->indent_right); |
|
|
297 | if (!old || (old->space_below != new->space_below)) |
|
|
298 | fprintf(of, "margin-bottom:%.1fpt;", new->space_below); |
|
|
299 | if (!old || |
|
|
300 | (old->bullet->on != new->bullet->on) || |
|
|
301 | (old->bullet->indent != new->bullet->indent) || |
|
|
302 | (old->indent_left != new->indent_left) || |
|
|
303 | (old->indent_first != new->indent_first)) { |
|
|
304 | psiconv_length_t indent = new->indent_first; |
|
|
305 | psiconv_length_t margin = new->indent_left; |
|
|
306 | /* Bullets with indent set cause strange margin behaviour: */ |
|
|
307 | if (new->bullet->on && new->bullet->indent) { |
|
|
308 | if (indent > 0.0) { |
|
|
309 | margin += indent; |
|
|
310 | indent = new->indent_left - indent; |
|
|
311 | } |
|
|
312 | } |
|
|
313 | fprintf(of, "margin-left:%.2fcm;", margin); |
|
|
314 | fprintf(of, "text-indent:%.2fcm;", indent); |
|
|
315 | } |
|
|
316 | if (!old || (old->justify_hor != new->justify_hor)) |
|
|
317 | fprintf(of, "text-align:%s;", justify_strings[new->justify_hor]); |
|
|
318 | if (!old || (old->linespacing_exact != new->linespacing_exact)) { |
|
|
319 | if (!old || old->linespacing_exact) |
|
|
320 | fputs("line-height:normal;", of); |
|
|
321 | else |
|
|
322 | fprintf(of, "line-height:%.1fpt;", new->linespacing); |
|
|
323 | } |
|
|
324 | fput_border(of, "left", old ? old->left_border : NULL, |
|
|
325 | new->left_border); |
|
|
326 | fput_border(of, "right", old ? old->right_border : NULL, |
|
|
327 | new->right_border); |
|
|
328 | fput_border(of, "top", old ? old->top_border : NULL, |
|
|
329 | new->top_border); |
|
|
330 | fput_border(of, "bottom", old ? old->bottom_border : NULL, |
|
|
331 | new->bottom_border); |
|
|
332 | } |
|
|
333 | |
|
|
334 | /* Character formats */ |
|
|
335 | static int character_layouts_different( |
|
|
336 | const psiconv_character_layout old, |
|
|
337 | const psiconv_character_layout new) |
|
|
338 | { |
|
|
339 | return ((old->font->screenfont != new->font->screenfont) || |
|
|
340 | (strcmp(old->font->name,new->font->name)) || |
|
|
341 | (old->font_size != new->font_size) || |
|
|
342 | (old->color->red != new->color->red) || |
|
|
343 | (old->color->green != new->color->green) || |
|
|
344 | (old->color->blue != new->color->blue) || |
|
|
345 | (old->back_color->red != new->back_color->red) || |
|
|
346 | (old->back_color->green != new->back_color->green) || |
|
|
347 | (old->back_color->blue != new->back_color->blue) || |
|
|
348 | (old->italic != new->italic) || |
|
|
349 | (old->bold != new->bold) || |
|
|
350 | (old->super_sub != new->super_sub) || |
|
|
351 | (old->underline != new->underline) || |
|
|
352 | (old->strikethrough != new->strikethrough)); |
|
|
353 | } |
|
|
354 | |
|
|
355 | static void fput_character_layout(FILE * of, |
|
|
356 | const psiconv_character_layout old, |
|
|
357 | const psiconv_character_layout new, |
|
|
358 | psiconv_word_f wf) |
|
|
359 | { |
|
|
360 | if (!old || (old->font->screenfont != new->font->screenfont) || |
|
|
361 | strcmp(old->font->name,new->font->name)) { |
|
|
362 | fprintf(of, "font-family:%s,%s,%s;", new->font->name, |
|
|
363 | generic_font_family(new->font->name), |
|
|
364 | screenfont_name(new->font->screenfont)); |
|
|
365 | } |
|
|
366 | if (!old || (old->font_size != new->font_size)) |
|
|
367 | fprintf(of, "font-size:%.1f%%;", 100.0 * new->font_size / 10.0); |
|
|
368 | if (!old || (old->bold != new->bold)) |
|
|
369 | fprintf(of, "font-weight:%s;", new->bold ? "bold" : "normal"); |
|
|
370 | if (!old || (old->italic != new->italic)) |
|
|
371 | fprintf(of, "font-style:%s;", new->italic ? "italic" : "normal"); |
|
|
372 | if (!old || (colors_different(old->color, new->color))) |
|
|
373 | fprintf(of, "color:#%02x%02x%02x;", |
|
|
374 | new->color->red, new->color->green, new->color->blue); |
|
|
375 | if (!old || (colors_different(old->back_color, new->back_color))) |
|
|
376 | fprintf(of, "background-color:#%02x%02x%02x;", |
|
|
377 | new->back_color->red, new->back_color->green, new->back_color->blue); |
|
|
378 | if (!old || (old->super_sub != new->super_sub)) |
|
|
379 | fprintf(of, "vertical-align:%s;", vertical_strings[new->super_sub]); |
|
|
380 | if (!old || (old->underline != new->underline) || |
|
|
381 | (old->strikethrough != new->strikethrough)) { |
|
|
382 | fputs("text-decoration:", of); |
|
|
383 | if (new->strikethrough) |
|
|
384 | fputs("line-through ", of); |
|
|
385 | if (new->underline) |
|
|
386 | fputs("underline", of); |
|
|
387 | else if (!new->strikethrough) |
|
|
388 | fputs("none", of); |
|
|
389 | fputs(";", of); |
|
|
390 | } |
|
|
391 | } |
|
|
392 | |
|
|
393 | |
|
|
394 | /* Formatted paragraphs */ |
|
|
395 | static void fput_para(FILE * of, |
|
|
396 | const psiconv_paragraph para, |
|
|
397 | psiconv_word_f wf) |
|
|
398 | { |
|
|
399 | psiconv_paragraph_layout base_para = para->base_paragraph; |
|
|
400 | psiconv_character_layout base_char = para->base_character; |
|
|
401 | psiconv_character_layout cur_char; |
|
|
402 | psiconv_character_layout *layout_stack; |
|
|
403 | psiconv_in_line_layout inl; |
|
|
404 | psiconv_word_style sty; |
|
|
405 | int spans = 0; |
|
|
406 | int wasspace = 0; |
|
|
407 | int i, j, loc; |
|
|
408 | char ** table; |
|
|
409 | |
|
|
410 | if (encoding == PSICONV_ENCODING_UTF8){ |
|
|
411 | table= (char**) utf_table; |
|
|
412 | }else{ |
|
|
413 | table= (char**) char_table; |
|
|
414 | } |
|
|
415 | |
|
|
416 | layout_stack = calloc(psiconv_list_length(para->in_lines), |
|
|
417 | sizeof(*layout_stack)); |
|
|
418 | fputs("<P", of); |
|
|
419 | sty = psiconv_get_style(wf->styles_sec, para->base_style); |
|
|
420 | cur_char = sty->character; |
|
|
421 | |
|
|
422 | if (sty->name) { |
|
|
423 | fputs(" CLASS=\"", of); |
|
|
424 | fput_name(of, sty->name); |
|
|
425 | putc('"', of); |
|
|
426 | } |
|
|
427 | |
|
|
428 | if (paragraph_layouts_different(sty->paragraph, base_para) || |
|
|
429 | character_layouts_different(cur_char, base_char)) { |
|
|
430 | fputs(" STYLE=\"", of); |
|
|
431 | fput_paragraph_layout(of, sty->paragraph, base_para); |
|
|
432 | fput_character_layout(of, cur_char, base_char, wf); |
|
|
433 | cur_char = base_char; |
|
|
434 | putc('"', of); |
|
|
435 | } |
|
|
436 | putc('>', of); |
|
|
437 | |
|
|
438 | if (base_para->bullet->on) { |
|
|
439 | fputs("<SPAN STYLE=\"", of); |
|
|
440 | if (base_para->bullet->font != base_char->font) { |
|
|
441 | fprintf(of, "font-family:%s,%s,%s;", |
|
|
442 | base_para->bullet->font->name, |
|
|
443 | generic_font_family(base_para->bullet->font->name), |
|
|
444 | screenfont_name(base_para->bullet->font->screenfont)); |
|
|
445 | } |
|
|
446 | if (base_para->bullet->font_size != base_char->font_size) |
|
|
447 | fprintf(of, "font-size:%.1f%%;", |
|
|
448 | 100.0 * base_para->bullet->font_size / 10.0); |
|
|
449 | if ((base_para->bullet->color->red != base_char->color->red) || |
|
|
450 | (base_para->bullet->color->green != base_char->color->green) || |
|
|
451 | (base_para->bullet->color->blue != base_char->color->blue)) |
|
|
452 | fprintf(of, "color:#%02x%02x%02x;", |
|
|
453 | base_para->bullet->color->red, |
|
|
454 | base_para->bullet->color->green, |
|
|
455 | base_para->bullet->color->blue); |
|
|
456 | fprintf(of, "\">%s </SPAN>", |
|
|
457 | table[base_para->bullet->character]); |
|
|
458 | wasspace = TRUE; |
|
|
459 | } |
|
|
460 | |
|
|
461 | loc = 0; |
|
|
462 | for (i = 0; i < psiconv_list_length(para->in_lines); i++) { |
|
|
463 | inl = psiconv_list_get(para->in_lines, i); |
|
|
464 | if (character_layouts_different(cur_char, inl->layout)) { |
|
|
465 | for (j = 0; j < spans; j++) |
|
|
466 | if (!character_layouts_different(inl->layout, layout_stack[j])) |
|
|
467 | break; |
|
|
468 | if (j < spans) { |
|
|
469 | while (spans > j) { |
|
|
470 | fputs("</SPAN>",of); |
|
|
471 | spans--; |
|
|
472 | } |
|
|
473 | } else { |
|
|
474 | fputs("<SPAN STYLE=\"", of); |
|
|
475 | fput_character_layout(of, cur_char, inl->layout, wf); |
|
|
476 | fputs("\">",of); |
|
|
477 | layout_stack[spans++] = cur_char; |
|
|
478 | } |
|
|
479 | cur_char = inl->layout; |
|
|
480 | } |
|
|
481 | fput_text(of, ¶->text[loc], inl->length, &wasspace); |
|
|
482 | loc += inl->length; |
|
|
483 | } |
|
|
484 | |
|
|
485 | while (spans > 0) { |
|
|
486 | fputs("</SPAN>",of); |
|
|
487 | spans--; |
|
|
488 | } |
|
|
489 | |
|
|
490 | if (loc < strlen(para->text)) { |
|
|
491 | fput_text(of, ¶->text[loc], strlen(para->text) - loc, &wasspace); |
|
|
492 | } |
|
|
493 | |
|
|
494 | if (strlen(para->text) == 0) |
|
|
495 | fputs(" ", of); |
|
|
496 | |
|
|
497 | fputs("</P>\n", of); |
|
|
498 | free(layout_stack); |
|
|
499 | } |
|
|
500 | |
|
|
501 | static void fput_style(FILE * of, |
|
|
502 | const psiconv_word_style normal, |
|
|
503 | const psiconv_word_style sty, |
|
|
504 | psiconv_word_f wf) |
|
|
505 | { |
|
|
506 | if (sty->name == NULL) |
|
|
507 | fputs(" P {", of); |
|
|
508 | else { |
|
|
509 | fputs(" P.", of); |
|
|
510 | fput_name(of, sty->name); |
|
|
511 | fputs(" {", of); |
|
|
512 | } |
|
|
513 | fput_paragraph_layout(of, normal ? normal->paragraph : NULL, sty->paragraph); |
|
|
514 | fput_character_layout(of, normal ? normal->character : NULL, sty->character, wf); |
|
|
515 | fputs("}\n", of); |
|
|
516 | } |
|
|
517 | |
|
|
518 | static int psiconv_gen_html4(const char *filename, const psiconv_file file, |
|
|
519 | const char *dest, const psiconv_encoding encoding_type) |
|
|
520 | { |
|
|
521 | FILE * of; |
|
|
522 | int i; |
|
|
523 | psiconv_paragraph para; |
|
|
524 | psiconv_word_style normal, sty; |
|
|
525 | psiconv_word_f wf; |
|
|
526 | |
|
|
527 | encoding=encoding_type; |
|
|
528 | |
|
|
529 | if (file->type == psiconv_word_file) |
|
|
530 | wf = file->file; |
|
|
531 | else { |
|
|
532 | /* Fall back on the normal HTML generator */ |
|
|
533 | return psiconv_gen_html(filename,file,dest,encoding_type); |
|
|
534 | } |
|
|
535 | |
|
|
536 | if (! (of = fopen(filename,"w"))) |
|
|
537 | return -1; |
|
|
538 | |
|
|
539 | fputs("<!doctype html public \"-//W3C//DTD HTML 4.0 STRICT//EN\">", of); |
|
|
540 | fputs("\n<HTML>\n<HEAD>\n <META NAME=\"GENERATOR\"", of); |
|
|
541 | fputs(" CONTENT=\"psiconv-" VERSION "\">\n", of); |
|
|
542 | |
|
|
543 | fputs(" <META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html", of); |
|
|
544 | if (encoding == PSICONV_ENCODING_UTF8) |
|
|
545 | fputs("; CHARSET=UTF-8", of); |
|
|
546 | fputs("\">\n", of); |
|
|
547 | |
|
|
548 | if (wf->page_sec->header->text) { |
|
|
549 | if (psiconv_list_length(wf->page_sec->header->text->paragraphs) > 0) { |
|
|
550 | fputs(" <TITLE>", of); |
|
|
551 | para = psiconv_list_get(wf->page_sec->header->text->paragraphs, 0); |
|
|
552 | i = 0; |
|
|
553 | fput_text(of, para->text, strlen(para->text), &i); |
|
|
554 | fputs("</TITLE>\n", of); |
|
|
555 | } |
|
|
556 | } |
|
|
557 | |
|
|
558 | normal = wf->styles_sec->normal; |
|
|
559 | fputs(" <STYLE TYPE=\"text/css\"><!--\n", of); |
|
|
560 | fprintf(of," BODY { background-color: #%02x%02x%02x }\n", |
|
|
561 | normal->paragraph->back_color->red, |
|
|
562 | normal->paragraph->back_color->green, |
|
|
563 | normal->paragraph->back_color->blue); |
|
|
564 | fput_style(of, NULL, normal, wf); |
|
|
565 | for (i = 0; i < psiconv_list_length(wf->styles_sec->styles); i++) { |
|
|
566 | sty = psiconv_list_get(wf->styles_sec->styles, i); |
|
|
567 | fput_style(of, normal, sty, wf); |
|
|
568 | } |
|
|
569 | fputs(" --></STYLE>\n</HEAD>\n<BODY>\n", of); |
|
|
570 | if (wf->page_sec->header->text) { |
|
|
571 | for (i = 0; i < psiconv_list_length(wf->paragraphs); i++) { |
|
|
572 | para = psiconv_list_get(wf->paragraphs, i); |
|
|
573 | fput_para(of, para, wf); |
|
|
574 | } |
|
|
575 | } |
|
|
576 | fputs("</BODY>\n</HTML>\n", of); |
|
|
577 | |
|
|
578 | return fclose(of); |
|
|
579 | } |
|
|
580 | |
|
|
581 | static struct psiconv_fileformat_s ff = |
|
|
582 | { |
|
|
583 | "HTML4", |
|
|
584 | "HTML 4.0 with cascading style sheets", |
|
|
585 | psiconv_gen_html4 |
|
|
586 | }; |
279 | }; |
587 | |
280 | |
|
|
281 | |
588 | void init_html4(void) |
282 | void init_html4(void) |
589 | { |
283 | { |
|
|
284 | int i; |
|
|
285 | for (i = 0; ffs[i].name; i++) |
590 | psiconv_list_add(fileformat_list,&ff); |
286 | psiconv_list_add(fileformat_list,ffs+i); |
591 | } |
287 | } |
592 | |
|
|