Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-text-context.c
4 : : * Date: Fri Feb 25 23:58:56 2008
5 : : *
6 : : * GNU PDF Library - Encoded Text Context
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2008-2011 Free Software Foundation, Inc. */
11 : :
12 : : /* This program is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU General Public License as published by
14 : : * the Free Software Foundation, either version 3 of the License, or
15 : : * (at your option) any later version.
16 : : *
17 : : * This program is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU General Public License for more details.
21 : : *
22 : : * You should have received a copy of the GNU General Public License
23 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : : */
25 : :
26 : : #include <config.h>
27 : :
28 : : #include <string.h>
29 : : #include <stdio.h>
30 : : #include <locale.h>
31 : : #include <localename.h> /* From gnulib sources. */
32 : : #include <localcharset.h> /* From gnulib sources. */
33 : : #include <streq.h> /* From gnulib sources. */
34 : :
35 : : #include <pdf-types.h>
36 : : #include <pdf-text.h>
37 : : #include <pdf-text-context.h>
38 : :
39 : : /* Host Language code Length */
40 : : #define PDF_TEXT_HLL 3
41 : :
42 : : /* Structure containing the specific context configuration for the Text
43 : : * Encoding Module */
44 : : typedef struct pdf_text_context_s {
45 : : /* Host encoding configured in the system */
46 : : pdf_char_t *host_encoding;
47 : : /* 2-character LANG ID */
48 : : pdf_char_t host_language_id[PDF_TEXT_HLL];
49 : : /* 2-character Country ID */
50 : : pdf_char_t host_country_id[PDF_TEXT_HLL];
51 : : /* System endianness */
52 : : enum pdf_endianness_e host_endianness;
53 : : /* Default EOL character in the system */
54 : : pdf_text_eol_t host_eol;
55 : : } pdf_text_context_t;
56 : :
57 : :
58 : : /* This context will be initialized only once at program startup, and it will
59 : : * be treated as constant from then on, so there shouldn't be any problem
60 : : * with multiple threading and reentrancy */
61 : : static pdf_text_context_t text_context;
62 : : static pdf_bool_t text_context_initialized = PDF_FALSE;
63 : :
64 : : /* Definition of the different platform-dependent EOL types, in UTF-8. This
65 : : * array is based on the `enum pdf_text_eol_types' enumeration. */
66 : : static const struct pdf_text_eol_s pdf_text_eol_types [PDF_TEXT_EOLMAX] = {
67 : : { { PDF_TEXT_DEF_CR, PDF_TEXT_DEF_LF, 0x00 } }, /* PDF_TEXT_EOL_WINDOWS */
68 : : { { PDF_TEXT_DEF_LF, 0x00, 0x00 } }, /* PDF_TEXT_EOL_UNIX */
69 : : { { 0xC2, PDF_TEXT_DEF_NEL, 0x00 } }, /* PDF_TEXT_EOL_EBCDIC */
70 : : { { PDF_TEXT_DEF_CR, 0x00, 0x00 } } /* PDF_TEXT_EOL_MACOS */
71 : : };
72 : :
73 : : /* Function to detect the endianness of the system. Can be either Big Endian
74 : : * (like PPC systems) or Little Endian (like Intel systems). PDF_IS_BIG_ENDIAN
75 : : * is filled in config.h at configure level. */
76 : : static void
77 : : pdf_text_detect_host_endianness (void)
78 : : {
79 : : #if PDF_IS_BIG_ENDIAN
80 : : PDF_DEBUG_BASE("TextContext: Host is 'Big Endian'");
81 : : text_context.host_endianness = PDF_TEXT_BIG_ENDIAN;
82 : : #else
83 : : PDF_DEBUG_BASE("TextContext: Host is 'Little Endian'");
84 : 745 : text_context.host_endianness = PDF_TEXT_LITTLE_ENDIAN;
85 : : #endif
86 : : }
87 : :
88 : : static pdf_bool_t
89 : : pdf_text_detect_host_encoding (pdf_error_t **error)
90 : : {
91 : : const pdf_char_t *charset;
92 : :
93 : : /* Get host encoding and check it */
94 : 745 : charset = locale_charset ();
95 [ + - - + ]: 745 : if (!charset || (strlen (charset) < 3))
96 : : {
97 [ # # ]: 0 : pdf_set_error (error,
98 : : PDF_EDOMAIN_BASE_TEXT,
99 : : PDF_ETEXTENC,
100 : : "couldn't detect host encoding: "
101 : : "invalid charset, '%s'",
102 : : charset ? charset : "unknown");
103 : 0 : return PDF_FALSE;
104 : : }
105 : :
106 : 745 : text_context.host_encoding = strdup (charset);
107 : :
108 : : PDF_DEBUG_BASE ("TextContext: Host Encoding is '%s'",
109 : : text_context.host_encoding);
110 : :
111 : 745 : return PDF_TRUE;
112 : : }
113 : :
114 : : static pdf_bool_t
115 : 745 : pdf_text_detect_host_language_and_country (pdf_error_t **error)
116 : : {
117 : : const pdf_char_t *locale_name;
118 : :
119 : : /* Initialize context strings */
120 : 745 : memset (&text_context.host_language_id[0], 0, PDF_TEXT_HLL);
121 : 745 : memset (&text_context.host_country_id[0], 0, PDF_TEXT_HLL);
122 : :
123 : : /* Get system default locale name and check it */
124 : 745 : locale_name = gl_locale_name (LC_CTYPE, "LC_CTYPE");
125 [ - + ]: 745 : if (!locale_name)
126 : : {
127 : 0 : pdf_set_error (error,
128 : : PDF_EDOMAIN_BASE_TEXT,
129 : : PDF_ETEXTENC,
130 : : "couldn't detect host language and country: "
131 : : "locale name not detected");
132 : 0 : return PDF_FALSE;
133 : : }
134 : :
135 [ + - + - ]: 1490 : if (!STREQ (locale_name, "C", 'C', 0, 0, 0, 0, 0, 0, 0, 0) &&
136 : 745 : !STREQ (locale_name, "POSIX", 'P', 'O', 'S', 'I', 'X', 0, 0, 0, 0))
137 : : {
138 : : /* Store language ID */
139 : 745 : strncpy (&(text_context.host_language_id[0]),
140 : : locale_name,
141 : : PDF_TEXT_HLL - 1);
142 : :
143 : : /* If available, store country ID */
144 [ + - ][ + - ]: 745 : if((strlen (locale_name) >= 5) &&
145 : 745 : (locale_name[2] == '_'))
146 : : {
147 : 745 : strncpy(&(text_context.host_country_id[0]),
148 : : &locale_name[3],
149 : : PDF_TEXT_HLL - 1);
150 : : }
151 : : }
152 : :
153 : : PDF_DEBUG_BASE("TextContext: Locale name is '%s'",
154 : : locale_name);
155 : : PDF_DEBUG_BASE("TextContext: Language ID is '%.2s'",
156 : : text_context.host_language_id);
157 : : PDF_DEBUG_BASE("TextContext: Country ID is '%.2s'",
158 : : text_context.host_country_id);
159 : 745 : return PDF_TRUE;
160 : : }
161 : :
162 : : static void
163 : : pdf_text_detect_host_eol (void)
164 : : {
165 : : /* The EOL sequence (a.k.a Newline function) may be represented by different
166 : : * characters, depending on the platform
167 : : *
168 : : * Mac OS 9.x and earlier ---> CR (Carriage Return), U+000D (Not supported)
169 : : * Mac OS X, Unix, GNU/Linux ---> LF (Line Feed), U+000A
170 : : * Windows ---> CRLF (Carriage Return + Line Feed), <U+000D,U+000A>
171 : : * EBCDIC-based OS --> NEL (Next Line), U+0085 (Not supported)
172 : : */
173 : : #ifdef PDF_HOST_WIN32
174 : : {
175 : : text_context.host_eol =
176 : : (pdf_text_eol_t)&pdf_text_eol_types[PDF_TEXT_EOL_WINDOWS];
177 : : }
178 : : #else
179 : : {
180 : 745 : text_context.host_eol =
181 : : (pdf_text_eol_t)&pdf_text_eol_types[PDF_TEXT_EOL_UNIX];
182 : : }
183 : : #endif
184 : : }
185 : :
186 : : void
187 : 745 : pdf_text_context_deinit (void)
188 : : {
189 [ + - ]: 745 : if (text_context.host_encoding)
190 : : {
191 : 745 : pdf_dealloc (text_context.host_encoding);
192 : 745 : text_context.host_encoding = NULL;
193 : : }
194 : :
195 : 745 : text_context_initialized = PDF_FALSE;
196 : : PDF_DEBUG_BASE ("Text context correctly deinitialized...");
197 : 745 : }
198 : :
199 : : pdf_bool_t
200 : 745 : pdf_text_context_init (pdf_error_t **error)
201 : : {
202 : : /* Get system endianness */
203 : : pdf_text_detect_host_endianness ();
204 : :
205 : : /* Get language and country ID from locale */
206 [ - + ]: 745 : if (!pdf_text_detect_host_language_and_country (error))
207 : 0 : return PDF_FALSE;
208 : :
209 : : /* Get host encoding from system */
210 [ - + ]: 745 : if (!pdf_text_detect_host_encoding (error))
211 : 0 : return PDF_FALSE;
212 : :
213 : : /* Detect host default EOL sequence */
214 : : pdf_text_detect_host_eol ();
215 : :
216 : : /* Mark the context as initialized */
217 : 745 : text_context_initialized = PDF_TRUE;
218 : :
219 : : PDF_DEBUG_BASE ("Text context correctly initialized...");
220 : 745 : return PDF_TRUE;
221 : : }
222 : :
223 : : pdf_bool_t
224 : 2488 : pdf_text_context_initialized (void)
225 : : {
226 : 2488 : return text_context_initialized;
227 : : }
228 : :
229 : : enum pdf_endianness_e
230 : 0 : pdf_text_context_get_host_endianness (void)
231 : : {
232 : 0 : return text_context.host_endianness;
233 : : }
234 : :
235 : : const pdf_char_t *
236 : 28 : pdf_text_context_get_host_encoding (void)
237 : : {
238 : 28 : return text_context.host_encoding;
239 : : }
240 : :
241 : : const pdf_char_t *
242 : 32 : pdf_text_context_get_host_language (void)
243 : : {
244 : 32 : return (const pdf_char_t *)text_context.host_language_id;
245 : : }
246 : :
247 : : const pdf_char_t *
248 : 0 : pdf_text_context_get_host_country (void)
249 : : {
250 : 0 : return (const pdf_char_t *)text_context.host_country_id;
251 : : }
252 : :
253 : : pdf_text_eol_t
254 : 18 : pdf_text_context_get_host_eol (enum pdf_text_eol_types eol_type)
255 : : {
256 [ + + ]: 18 : return (eol_type == PDF_TEXT_EOL_HOST ?
257 : : text_context.host_eol :
258 : 16 : (pdf_text_eol_t) &(pdf_text_eol_types [eol_type]));
259 : : }
260 : :
261 : : /* End of pdf-text-context.c */
|