~ubuntu-branches/ubuntu/raring/geany/raring-proposed

« back to all changes in this revision

Viewing changes to src/encodings.c

  • Committer: Package Import Robot
  • Author(s): Chow Loong Jin
  • Date: 2011-12-10 07:43:26 UTC
  • mfrom: (3.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20111210074326-s8yqbew5i20h33tf
Tags: 0.21-1ubuntu1
* Merge from Debian Unstable, remaining changes:
  - debian/patches/20_use_evince_viewer.patch:
     + use evince as viewer for pdf and dvi files
  - debian/patches/20_use_x_terminal_emulator.patch:
     + use x-terminal-emulator as terminal
  - debian/control
     + Add breaks on geany-plugins-common << 0.20
* Also fixes bugs:
  - Filter for MATLAB/Octave files filters everythign (LP: 885505)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 *      encodings.c - this file is part of Geany, a fast and lightweight IDE
3
3
 *
4
 
 *      Copyright 2005-2010 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
5
 
 *      Copyright 2006-2010 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
 
4
 *      Copyright 2005-2011 Enrico Tröger <enrico(dot)troeger(at)uvena(dot)de>
 
5
 *      Copyright 2006-2011 Nick Treleaven <nick(dot)treleaven(at)btinternet(dot)com>
6
6
 *
7
7
 *      This program is free software; you can redistribute it and/or modify
8
8
 *      it under the terms of the GNU General Public License as published by
18
18
 *      along with this program; if not, write to the Free Software
19
19
 *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 *
21
 
 *  $Id: encodings.c 5221 2010-09-09 17:21:05Z ntrel $
 
21
 *  $Id: encodings.c 5908 2011-09-02 21:45:20Z colombanw $
22
22
 */
23
23
 
24
24
/*
51
51
#endif
52
52
 
53
53
/* <meta http-equiv="content-type" content="text/html; charset=UTF-8" /> */
54
 
#define PATTERN_HTMLMETA "<meta[ \t\n\r\f]http-equiv[ \t\n\r\f]*=[ \t\n\r\f]*\"content-type\"[ \t\n\r\f]+content[ \t\n\r\f]*=[ \t\n\r\f]*\"text/x?html;[ \t\n\r\f]*charset=([a-z0-9_-]+)\"[ \t\n\r\f]*/?>"
 
54
#define PATTERN_HTMLMETA "<meta[ \t\n\r\f]+http-equiv[ \t\n\r\f]*=[ \t\n\r\f]*\"?content-type\"?[ \t\n\r\f]+content[ \t\n\r\f]*=[ \t\n\r\f]*\"text/x?html;[ \t\n\r\f]*charset=([a-z0-9_-]+)\"[ \t\n\r\f]*/?>"
55
55
/* " geany_encoding=utf-8 " or " coding: utf-8 " */
56
 
#define PATTERN_CODING "coding[\t ]*[:=][\t ]*([a-z0-9-]+)[\t ]*"
 
56
#define PATTERN_CODING "coding[\t ]*[:=][\t ]*\"?([a-z0-9-]+)\"?[\t ]*"
57
57
 
58
58
/* precompiled regexps */
59
59
static regex_t pregs[2];
72
72
 
73
73
static void init_encodings(void)
74
74
{
75
 
        fill(0, WESTEUROPEAN, GEANY_ENCODING_ISO_8859_14, "ISO-8859-14", _("Celtic"));
76
 
        fill(1, WESTEUROPEAN, GEANY_ENCODING_ISO_8859_7, "ISO-8859-7", _("Greek"));
77
 
        fill(2, WESTEUROPEAN, GEANY_ENCODING_WINDOWS_1253, "WINDOWS-1253", _("Greek"));
78
 
        fill(3, WESTEUROPEAN, GEANY_ENCODING_ISO_8859_10, "ISO-8859-10", _("Nordic"));
79
 
        fill(4, WESTEUROPEAN, GEANY_ENCODING_ISO_8859_3, "ISO-8859-3", _("South European"));
80
 
        fill(5, WESTEUROPEAN, GEANY_ENCODING_IBM_850, "IBM850", _("Western"));
81
 
        fill(6, WESTEUROPEAN, GEANY_ENCODING_ISO_8859_1, "ISO-8859-1", _("Western"));
82
 
        fill(7, WESTEUROPEAN, GEANY_ENCODING_ISO_8859_15, "ISO-8859-15", _("Western"));
83
 
        fill(8, WESTEUROPEAN, GEANY_ENCODING_WINDOWS_1252, "WINDOWS-1252", _("Western"));
 
75
        fill(0,         WESTEUROPEAN,   GEANY_ENCODING_ISO_8859_14,             "ISO-8859-14",          _("Celtic"));
 
76
        fill(1,         WESTEUROPEAN,   GEANY_ENCODING_ISO_8859_7,              "ISO-8859-7",           _("Greek"));
 
77
        fill(2,         WESTEUROPEAN,   GEANY_ENCODING_WINDOWS_1253,    "WINDOWS-1253",         _("Greek"));
 
78
        fill(3,         WESTEUROPEAN,   GEANY_ENCODING_ISO_8859_10,             "ISO-8859-10",          _("Nordic"));
 
79
        fill(4,         WESTEUROPEAN,   GEANY_ENCODING_ISO_8859_3,              "ISO-8859-3",           _("South European"));
 
80
        fill(5,         WESTEUROPEAN,   GEANY_ENCODING_IBM_850,                 "IBM850",                       _("Western"));
 
81
        fill(6,         WESTEUROPEAN,   GEANY_ENCODING_ISO_8859_1,              "ISO-8859-1",           _("Western"));
 
82
        fill(7,         WESTEUROPEAN,   GEANY_ENCODING_ISO_8859_15,             "ISO-8859-15",          _("Western"));
 
83
        fill(8,         WESTEUROPEAN,   GEANY_ENCODING_WINDOWS_1252,    "WINDOWS-1252",         _("Western"));
84
84
 
85
 
        fill(0, EASTEUROPEAN, GEANY_ENCODING_ISO_8859_4, "ISO-8859-4", _("Baltic"));
86
 
        fill(1, EASTEUROPEAN, GEANY_ENCODING_ISO_8859_13, "ISO-8859-13", _("Baltic"));
87
 
        fill(2, EASTEUROPEAN, GEANY_ENCODING_WINDOWS_1257, "WINDOWS-1257", _("Baltic"));
88
 
        fill(3, EASTEUROPEAN, GEANY_ENCODING_IBM_852, "IBM852", _("Central European"));
89
 
        fill(4, EASTEUROPEAN, GEANY_ENCODING_ISO_8859_2, "ISO-8859-2", _("Central European"));
90
 
        fill(5, EASTEUROPEAN, GEANY_ENCODING_WINDOWS_1250, "WINDOWS-1250", _("Central European"));
91
 
        fill(6, EASTEUROPEAN, GEANY_ENCODING_IBM_855, "IBM855", _("Cyrillic"));
92
 
        fill(7, EASTEUROPEAN, GEANY_ENCODING_ISO_8859_5, "ISO-8859-5", _("Cyrillic"));
 
85
        fill(0,         EASTEUROPEAN,   GEANY_ENCODING_ISO_8859_4,              "ISO-8859-4",           _("Baltic"));
 
86
        fill(1,         EASTEUROPEAN,   GEANY_ENCODING_ISO_8859_13,             "ISO-8859-13",          _("Baltic"));
 
87
        fill(2,         EASTEUROPEAN,   GEANY_ENCODING_WINDOWS_1257,    "WINDOWS-1257",         _("Baltic"));
 
88
        fill(3,         EASTEUROPEAN,   GEANY_ENCODING_IBM_852,                 "IBM852",                       _("Central European"));
 
89
        fill(4,         EASTEUROPEAN,   GEANY_ENCODING_ISO_8859_2,              "ISO-8859-2",           _("Central European"));
 
90
        fill(5,         EASTEUROPEAN,   GEANY_ENCODING_WINDOWS_1250,    "WINDOWS-1250",         _("Central European"));
 
91
        fill(6,         EASTEUROPEAN,   GEANY_ENCODING_IBM_855,                 "IBM855",                       _("Cyrillic"));
 
92
        fill(7,         EASTEUROPEAN,   GEANY_ENCODING_ISO_8859_5,              "ISO-8859-5",           _("Cyrillic"));
93
93
        /* ISO-IR-111 not available on Windows */
94
 
        fill(8, EASTEUROPEAN, GEANY_ENCODING_ISO_IR_111, "ISO-IR-111", _("Cyrillic"));
95
 
        fill(9, EASTEUROPEAN, GEANY_ENCODING_KOI8_R, "KOI8-R", _("Cyrillic"));
96
 
        fill(10, EASTEUROPEAN, GEANY_ENCODING_WINDOWS_1251, "WINDOWS-1251", _("Cyrillic"));
97
 
        fill(11, EASTEUROPEAN, GEANY_ENCODING_CP_866, "CP866", _("Cyrillic/Russian"));
98
 
        fill(12, EASTEUROPEAN, GEANY_ENCODING_KOI8_U, "KOI8-U", _("Cyrillic/Ukrainian"));
99
 
        fill(13, EASTEUROPEAN, GEANY_ENCODING_ISO_8859_16, "ISO-8859-16", _("Romanian"));
 
94
        fill(8,         EASTEUROPEAN,   GEANY_ENCODING_ISO_IR_111,              "ISO-IR-111",           _("Cyrillic"));
 
95
        fill(9,         EASTEUROPEAN,   GEANY_ENCODING_KOI8_R,                  "KOI8-R",                       _("Cyrillic"));
 
96
        fill(10,        EASTEUROPEAN,   GEANY_ENCODING_WINDOWS_1251,    "WINDOWS-1251",         _("Cyrillic"));
 
97
        fill(11,        EASTEUROPEAN,   GEANY_ENCODING_CP_866,                  "CP866",                        _("Cyrillic/Russian"));
 
98
        fill(12,        EASTEUROPEAN,   GEANY_ENCODING_KOI8_U,                  "KOI8-U",                       _("Cyrillic/Ukrainian"));
 
99
        fill(13,        EASTEUROPEAN,   GEANY_ENCODING_ISO_8859_16,             "ISO-8859-16",          _("Romanian"));
100
100
 
101
 
        fill(0, MIDDLEEASTERN, GEANY_ENCODING_IBM_864, "IBM864", _("Arabic"));
102
 
        fill(1, MIDDLEEASTERN, GEANY_ENCODING_ISO_8859_6, "ISO-8859-6", _("Arabic"));
103
 
        fill(2, MIDDLEEASTERN, GEANY_ENCODING_WINDOWS_1256, "WINDOWS-1256", _("Arabic"));
104
 
        fill(3, MIDDLEEASTERN, GEANY_ENCODING_IBM_862, "IBM862", _("Hebrew"));
 
101
        fill(0,         MIDDLEEASTERN,  GEANY_ENCODING_IBM_864,                 "IBM864",                       _("Arabic"));
 
102
        fill(1,         MIDDLEEASTERN,  GEANY_ENCODING_ISO_8859_6,              "ISO-8859-6",           _("Arabic"));
 
103
        fill(2,         MIDDLEEASTERN,  GEANY_ENCODING_WINDOWS_1256,    "WINDOWS-1256",         _("Arabic"));
 
104
        fill(3,         MIDDLEEASTERN,  GEANY_ENCODING_IBM_862,                 "IBM862",                       _("Hebrew"));
105
105
        /* not available at all, ? */
106
 
        fill(4, MIDDLEEASTERN, GEANY_ENCODING_ISO_8859_8_I, "ISO-8859-8-I", _("Hebrew"));
107
 
        fill(5, MIDDLEEASTERN, GEANY_ENCODING_WINDOWS_1255, "WINDOWS-1255", _("Hebrew"));
108
 
        fill(6, MIDDLEEASTERN, GEANY_ENCODING_ISO_8859_8, "ISO-8859-8", _("Hebrew Visual"));
109
 
 
110
 
        fill(0, ASIAN, GEANY_ENCODING_ARMSCII_8, "ARMSCII-8", _("Armenian"));
111
 
        fill(1, ASIAN, GEANY_ENCODING_GEOSTD8, "GEORGIAN-ACADEMY", _("Georgian"));
112
 
        fill(2, ASIAN, GEANY_ENCODING_TIS_620, "TIS-620", _("Thai"));
113
 
        fill(3, ASIAN, GEANY_ENCODING_IBM_857, "IBM857", _("Turkish"));
114
 
        fill(4, ASIAN, GEANY_ENCODING_WINDOWS_1254, "WINDOWS-1254", _("Turkish"));
115
 
        fill(5, ASIAN, GEANY_ENCODING_ISO_8859_9, "ISO-8859-9", _("Turkish"));
116
 
        fill(6, ASIAN, GEANY_ENCODING_TCVN, "TCVN", _("Vietnamese"));
117
 
        fill(7, ASIAN, GEANY_ENCODING_VISCII, "VISCII", _("Vietnamese"));
118
 
        fill(8, ASIAN, GEANY_ENCODING_WINDOWS_1258, "WINDOWS-1258", _("Vietnamese"));
119
 
 
120
 
        fill(0, UNICODE, GEANY_ENCODING_UTF_7, "UTF-7", _("Unicode"));
121
 
        fill(1, UNICODE, GEANY_ENCODING_UTF_8, "UTF-8", _("Unicode"));
122
 
        fill(2, UNICODE, GEANY_ENCODING_UTF_16LE, "UTF-16LE", _("Unicode"));
123
 
        fill(3, UNICODE, GEANY_ENCODING_UTF_16BE, "UTF-16BE", _("Unicode"));
124
 
        fill(4, UNICODE, GEANY_ENCODING_UCS_2LE, "UCS-2LE", _("Unicode"));
125
 
        fill(5, UNICODE, GEANY_ENCODING_UCS_2BE, "UCS-2BE", _("Unicode"));
126
 
        fill(6, UNICODE, GEANY_ENCODING_UTF_32LE, "UTF-32LE", _("Unicode"));
127
 
        fill(7, UNICODE, GEANY_ENCODING_UTF_32BE, "UTF-32BE", _("Unicode"));
128
 
 
129
 
        fill(0, EASTASIAN, GEANY_ENCODING_GB18030, "GB18030", _("Chinese Simplified"));
130
 
        fill(1, EASTASIAN, GEANY_ENCODING_GB2312, "GB2312", _("Chinese Simplified"));
131
 
        fill(2, EASTASIAN, GEANY_ENCODING_GBK, "GBK", _("Chinese Simplified"));
 
106
        fill(4,         MIDDLEEASTERN,  GEANY_ENCODING_ISO_8859_8_I,    "ISO-8859-8-I",         _("Hebrew"));
 
107
        fill(5,         MIDDLEEASTERN,  GEANY_ENCODING_WINDOWS_1255,    "WINDOWS-1255",         _("Hebrew"));
 
108
        fill(6,         MIDDLEEASTERN,  GEANY_ENCODING_ISO_8859_8,              "ISO-8859-8",           _("Hebrew Visual"));
 
109
 
 
110
        fill(0,         ASIAN,                  GEANY_ENCODING_ARMSCII_8,               "ARMSCII-8",            _("Armenian"));
 
111
        fill(1,         ASIAN,                  GEANY_ENCODING_GEOSTD8,                 "GEORGIAN-ACADEMY",     _("Georgian"));
 
112
        fill(2,         ASIAN,                  GEANY_ENCODING_TIS_620,                 "TIS-620",                      _("Thai"));
 
113
        fill(3,         ASIAN,                  GEANY_ENCODING_IBM_857,                 "IBM857",                       _("Turkish"));
 
114
        fill(4,         ASIAN,                  GEANY_ENCODING_WINDOWS_1254,    "WINDOWS-1254",         _("Turkish"));
 
115
        fill(5,         ASIAN,                  GEANY_ENCODING_ISO_8859_9,              "ISO-8859-9",           _("Turkish"));
 
116
        fill(6,         ASIAN,                  GEANY_ENCODING_TCVN,                    "TCVN",                         _("Vietnamese"));
 
117
        fill(7,         ASIAN,                  GEANY_ENCODING_VISCII,                  "VISCII",                       _("Vietnamese"));
 
118
        fill(8,         ASIAN,                  GEANY_ENCODING_WINDOWS_1258,    "WINDOWS-1258",         _("Vietnamese"));
 
119
 
 
120
        fill(0,         UNICODE,                GEANY_ENCODING_UTF_7,                   "UTF-7",                        _("Unicode"));
 
121
        fill(1,         UNICODE,                GEANY_ENCODING_UTF_8,                   "UTF-8",                        _("Unicode"));
 
122
        fill(2,         UNICODE,                GEANY_ENCODING_UTF_16LE,                "UTF-16LE",                     _("Unicode"));
 
123
        fill(3,         UNICODE,                GEANY_ENCODING_UTF_16BE,                "UTF-16BE",                     _("Unicode"));
 
124
        fill(4,         UNICODE,                GEANY_ENCODING_UCS_2LE,                 "UCS-2LE",                      _("Unicode"));
 
125
        fill(5,         UNICODE,                GEANY_ENCODING_UCS_2BE,                 "UCS-2BE",                      _("Unicode"));
 
126
        fill(6,         UNICODE,                GEANY_ENCODING_UTF_32LE,                "UTF-32LE",                     _("Unicode"));
 
127
        fill(7,         UNICODE,                GEANY_ENCODING_UTF_32BE,                "UTF-32BE",                     _("Unicode"));
 
128
 
 
129
        fill(0,         EASTASIAN,              GEANY_ENCODING_GB18030,                 "GB18030",                      _("Chinese Simplified"));
 
130
        fill(1,         EASTASIAN,              GEANY_ENCODING_GB2312,                  "GB2312",                       _("Chinese Simplified"));
 
131
        fill(2,         EASTASIAN,              GEANY_ENCODING_GBK,                             "GBK",                          _("Chinese Simplified"));
132
132
        /* maybe not available on Linux */
133
 
        fill(3, EASTASIAN, GEANY_ENCODING_HZ, "HZ", _("Chinese Simplified"));
134
 
        fill(4, EASTASIAN, GEANY_ENCODING_BIG5, "BIG5", _("Chinese Traditional"));
135
 
        fill(5, EASTASIAN, GEANY_ENCODING_BIG5_HKSCS, "BIG5-HKSCS", _("Chinese Traditional"));
136
 
        fill(6, EASTASIAN, GEANY_ENCODING_EUC_TW, "EUC-TW", _("Chinese Traditional"));
137
 
        fill(7, EASTASIAN, GEANY_ENCODING_EUC_JP, "EUC-JP", _("Japanese"));
138
 
        fill(8, EASTASIAN, GEANY_ENCODING_ISO_2022_JP, "ISO-2022-JP", _("Japanese"));
139
 
        fill(9, EASTASIAN, GEANY_ENCODING_SHIFT_JIS, "SHIFT_JIS", _("Japanese"));
140
 
        fill(10, EASTASIAN, GEANY_ENCODING_CP_932, "CP932", _("Japanese"));
141
 
        fill(11, EASTASIAN, GEANY_ENCODING_EUC_KR, "EUC-KR", _("Korean"));
142
 
        fill(12, EASTASIAN, GEANY_ENCODING_ISO_2022_KR, "ISO-2022-KR", _("Korean"));
143
 
        fill(13, EASTASIAN, GEANY_ENCODING_JOHAB, "JOHAB", _("Korean"));
144
 
        fill(14, EASTASIAN, GEANY_ENCODING_UHC, "UHC", _("Korean"));
145
 
 
146
 
        fill(0, NONE, GEANY_ENCODING_NONE, "None", _("Without encoding"));
 
133
        fill(3,         EASTASIAN,              GEANY_ENCODING_HZ,                              "HZ",                           _("Chinese Simplified"));
 
134
        fill(4,         EASTASIAN,              GEANY_ENCODING_BIG5,                    "BIG5",                         _("Chinese Traditional"));
 
135
        fill(5,         EASTASIAN,              GEANY_ENCODING_BIG5_HKSCS,              "BIG5-HKSCS",           _("Chinese Traditional"));
 
136
        fill(6,         EASTASIAN,              GEANY_ENCODING_EUC_TW,                  "EUC-TW",                       _("Chinese Traditional"));
 
137
        fill(7,         EASTASIAN,              GEANY_ENCODING_EUC_JP,                  "EUC-JP",                       _("Japanese"));
 
138
        fill(8,         EASTASIAN,              GEANY_ENCODING_ISO_2022_JP,             "ISO-2022-JP",          _("Japanese"));
 
139
        fill(9,         EASTASIAN,              GEANY_ENCODING_SHIFT_JIS,               "SHIFT_JIS",            _("Japanese"));
 
140
        fill(10,        EASTASIAN,              GEANY_ENCODING_CP_932,                  "CP932",                        _("Japanese"));
 
141
        fill(11,        EASTASIAN,              GEANY_ENCODING_EUC_KR,                  "EUC-KR",                       _("Korean"));
 
142
        fill(12,        EASTASIAN,              GEANY_ENCODING_ISO_2022_KR,             "ISO-2022-KR",          _("Korean"));
 
143
        fill(13,        EASTASIAN,              GEANY_ENCODING_JOHAB,                   "JOHAB",                        _("Korean"));
 
144
        fill(14,        EASTASIAN,              GEANY_ENCODING_UHC,                             "UHC",                          _("Korean"));
 
145
 
 
146
        fill(0,         NONE,                   GEANY_ENCODING_NONE,                    "None",                         _("Without encoding"));
 
147
}
 
148
 
 
149
 
 
150
/* compares two encoding names in a permissive fashion.
 
151
 * e.g. "utf8" matches "UTF-8", "iso8859_1" matches "ISO-8859-1", etc. */
 
152
static gboolean encodings_charset_equals(const gchar *a, const gchar *b)
 
153
{
 
154
        gboolean was_alpha = FALSE; /* whether last character of previous word was a letter */
 
155
        gboolean need_sep = FALSE; /* whether we're expecting an implicit separator */
 
156
 
 
157
        while (*a && *b)
 
158
        {
 
159
                gboolean is_alpha;
 
160
 
 
161
                if (g_ascii_toupper(*a) == g_ascii_toupper(*b) &&
 
162
                        ((is_alpha = g_ascii_isalpha(*a)) || g_ascii_isdigit(*a)))
 
163
                {
 
164
                        /* either there was a real separator, or we need a implicit one (a chage from alpha to
 
165
                         * numeric or so) */
 
166
                        if (! need_sep || (was_alpha != is_alpha))
 
167
                        {
 
168
                                a++;
 
169
                                b++;
 
170
                                was_alpha = is_alpha;
 
171
                                need_sep = FALSE;
 
172
                        }
 
173
                        else
 
174
                                return FALSE;
 
175
                }
 
176
                else
 
177
                {
 
178
                        guint n_sep = 0;
 
179
 
 
180
                        if (! g_ascii_isalnum(*a))
 
181
                        {
 
182
                                a++;
 
183
                                n_sep++;
 
184
                        }
 
185
                        if (! g_ascii_isalnum(*b))
 
186
                        {
 
187
                                b++;
 
188
                                n_sep++;
 
189
                        }
 
190
                        if (n_sep < 1)
 
191
                                return FALSE;
 
192
                        else if (n_sep < 2)
 
193
                                need_sep = TRUE;
 
194
                }
 
195
        }
 
196
        return *a == *b;
147
197
}
148
198
 
149
199
 
157
207
        i = 0;
158
208
        while (i < GEANY_ENCODINGS_MAX)
159
209
        {
160
 
                if (strcmp(charset, encodings[i].charset) == 0)
 
210
                if (encodings_charset_equals(charset, encodings[i].charset))
161
211
                        return i;
162
212
 
163
213
                ++i;
176
226
        i = 0;
177
227
        while (i < GEANY_ENCODINGS_MAX)
178
228
        {
179
 
                if (strcmp(charset, encodings[i].charset) == 0)
 
229
                if (encodings_charset_equals(charset, encodings[i].charset))
180
230
                        return &encodings[i];
181
231
 
182
232
                ++i;
186
236
}
187
237
 
188
238
 
 
239
static const gchar *encodings_normalize_charset(const gchar *charset)
 
240
{
 
241
        const GeanyEncoding *encoding;
 
242
 
 
243
        encoding = encodings_get_from_charset(charset);
 
244
        if (encoding != NULL)
 
245
                return encoding->charset;
 
246
 
 
247
        return NULL;
 
248
}
 
249
 
 
250
 
189
251
const GeanyEncoding *encodings_get_from_index(gint idx)
190
252
{
191
253
        g_return_val_if_fail(idx >= 0 && idx < GEANY_ENCODINGS_MAX, NULL);
219
281
        g_return_val_if_fail(enc->name != NULL, NULL);
220
282
        g_return_val_if_fail(enc->charset != NULL, NULL);
221
283
 
222
 
    return g_strdup_printf("%s (%s)", enc->name, enc->charset);
 
284
        return g_strdup_printf("%s (%s)", enc->name, enc->charset);
223
285
}
224
286
 
225
287
 
282
344
        gchar *encoding = NULL;
283
345
        regmatch_t pmatch[10];
284
346
 
285
 
        if (G_UNLIKELY(! pregs_loaded) || G_UNLIKELY(buffer == NULL))
 
347
        if (G_UNLIKELY(! pregs_loaded || buffer == NULL))
286
348
                return NULL;
287
349
 
288
350
        if (size > 512)
500
562
}
501
563
 
502
564
 
503
 
/**
504
 
 *  Tries to convert @a buffer into UTF-8 encoding and store the detected original encoding in
505
 
 *  @a used_encoding.
506
 
 *
507
 
 *  @param buffer the input string to convert.
508
 
 *  @param size the length of the string, or -1 if the string is nul-terminated.
509
 
 *  @param used_encoding return location of the detected encoding of the input string, or @c NULL.
510
 
 *
511
 
 *  @return If the conversion was successful, a newly allocated nul-terminated string,
512
 
 *    which must be freed with @c g_free(). Otherwise @c NULL.
513
 
 **/
514
 
gchar *encodings_convert_to_utf8(const gchar *buffer, gsize size, gchar **used_encoding)
515
 
{
516
 
        gchar *locale_charset = NULL;
517
 
        gchar *regex_charset = NULL;
 
565
static gchar *encodings_check_regexes(const gchar *buffer, gsize size)
 
566
{
 
567
        guint i;
 
568
 
 
569
        for (i = 0; i < G_N_ELEMENTS(pregs); i++)
 
570
        {
 
571
                gchar *charset;
 
572
 
 
573
                if ((charset = regex_match(&pregs[i], buffer, size)) != NULL)
 
574
                        return charset;
 
575
        }
 
576
        return NULL;
 
577
}
 
578
 
 
579
 
 
580
static gchar *encodings_convert_to_utf8_with_suggestion(const gchar *buffer, gsize size,
 
581
                const gchar *suggested_charset, gchar **used_encoding)
 
582
{
 
583
        const gchar *locale_charset = NULL;
518
584
        const gchar *charset;
519
585
        gchar *utf8_content;
520
 
        gboolean check_regex = FALSE;
 
586
        gboolean check_suggestion = suggested_charset != NULL;
521
587
        gboolean check_locale = FALSE;
522
 
        gint i, len, preferred_charset;
 
588
        gint i, preferred_charset;
523
589
 
524
590
        if ((gint)size == -1)
525
591
        {
526
592
                size = strlen(buffer);
527
593
        }
528
594
 
529
 
        /* first try to read the encoding from the file content */
530
 
        len = (gint) G_N_ELEMENTS(pregs);
531
 
        for (i = 0; i < len && ! check_regex; i++)
532
 
        {
533
 
                if ((regex_charset = regex_match(&pregs[i], buffer, size)) != NULL)
534
 
                        check_regex = TRUE;
535
 
        }
536
 
 
537
595
        /* current locale is not UTF-8, we have to check this charset */
538
 
        check_locale = ! g_get_charset((const gchar**) &charset);
 
596
        check_locale = ! g_get_charset(&locale_charset);
539
597
 
540
598
        /* First check for preferred charset, if specified */
541
599
        preferred_charset = file_prefs.default_open_encoding;
553
611
                if (G_UNLIKELY(i == encodings[GEANY_ENCODING_NONE].idx))
554
612
                        continue;
555
613
 
556
 
                if (check_regex)
 
614
                if (check_suggestion)
557
615
                {
558
 
                        check_regex = FALSE;
559
 
                        charset = regex_charset;
 
616
                        check_suggestion = FALSE;
 
617
                        charset = encodings_normalize_charset(suggested_charset);
 
618
                        if (charset == NULL) /* we failed at normalizing suggested encoding, try it as is */
 
619
                                charset = suggested_charset;
560
620
                        i = -2; /* keep i below the start value to have it again at -1 on the next loop run */
561
621
                }
562
622
                else if (check_locale)
598
658
                                }
599
659
                                *used_encoding = g_strdup(charset);
600
660
                        }
601
 
                        g_free(regex_charset);
602
661
                        return utf8_content;
603
662
                }
604
663
        }
 
664
 
 
665
        return NULL;
 
666
}
 
667
 
 
668
 
 
669
/**
 
670
 *  Tries to convert @a buffer into UTF-8 encoding and store the detected original encoding in
 
671
 *  @a used_encoding.
 
672
 *
 
673
 *  @param buffer the input string to convert.
 
674
 *  @param size the length of the string, or -1 if the string is nul-terminated.
 
675
 *  @param used_encoding return location of the detected encoding of the input string, or @c NULL.
 
676
 *
 
677
 *  @return If the conversion was successful, a newly allocated nul-terminated string,
 
678
 *    which must be freed with @c g_free(). Otherwise @c NULL.
 
679
 **/
 
680
gchar *encodings_convert_to_utf8(const gchar *buffer, gsize size, gchar **used_encoding)
 
681
{
 
682
        gchar *regex_charset;
 
683
        gchar *utf8;
 
684
 
 
685
        /* first try to read the encoding from the file content */
 
686
        regex_charset = encodings_check_regexes(buffer, size);
 
687
        utf8 = encodings_convert_to_utf8_with_suggestion(buffer, size, regex_charset, used_encoding);
605
688
        g_free(regex_charset);
606
689
 
607
 
        return NULL;
 
690
        return utf8;
608
691
}
609
692
 
610
693
 
676
759
}
677
760
 
678
761
 
 
762
typedef struct
 
763
{
 
764
        gchar           *data;  /* null-terminated data */
 
765
        gsize            size;  /* actual data size */
 
766
        gsize            len;   /* string length of data */
 
767
        gchar           *enc;
 
768
        gboolean         bom;
 
769
        gboolean         partial;
 
770
} BufferData;
 
771
 
 
772
 
 
773
/* convert data with the specified encoding */
 
774
static gboolean
 
775
handle_forced_encoding(BufferData *buffer, const gchar *forced_enc)
 
776
{
 
777
        GeanyEncodingIndex enc_idx;
 
778
 
 
779
        if (utils_str_equal(forced_enc, "UTF-8"))
 
780
        {
 
781
                if (! g_utf8_validate(buffer->data, buffer->len, NULL))
 
782
                {
 
783
                        return FALSE;
 
784
                }
 
785
        }
 
786
        else
 
787
        {
 
788
                gchar *converted_text = encodings_convert_to_utf8_from_charset(
 
789
                                                                                buffer->data, buffer->size, forced_enc, FALSE);
 
790
                if (converted_text == NULL)
 
791
                {
 
792
                        return FALSE;
 
793
                }
 
794
                else
 
795
                {
 
796
                        setptr(buffer->data, converted_text);
 
797
                        buffer->len = strlen(converted_text);
 
798
                }
 
799
        }
 
800
        enc_idx = encodings_scan_unicode_bom(buffer->data, buffer->size, NULL);
 
801
        buffer->bom = (enc_idx == GEANY_ENCODING_UTF_8);
 
802
        buffer->enc = g_strdup(forced_enc);
 
803
        return TRUE;
 
804
}
 
805
 
 
806
 
 
807
/* detect encoding and convert to UTF-8 if necessary */
 
808
static gboolean
 
809
handle_encoding(BufferData *buffer, GeanyEncodingIndex enc_idx)
 
810
{
 
811
        g_return_val_if_fail(buffer->enc == NULL, FALSE);
 
812
        g_return_val_if_fail(buffer->bom == FALSE, FALSE);
 
813
 
 
814
        if (buffer->size == 0)
 
815
        {
 
816
                /* we have no data so assume UTF-8, buffer->len can be 0 even we have an empty
 
817
                 * e.g. UTF32 file with a BOM(so size is 4, len is 0) */
 
818
                buffer->enc = g_strdup("UTF-8");
 
819
        }
 
820
        else
 
821
        {
 
822
                /* first check for a BOM */
 
823
                if (enc_idx != GEANY_ENCODING_NONE)
 
824
                {
 
825
                        buffer->enc = g_strdup(encodings[enc_idx].charset);
 
826
                        buffer->bom = TRUE;
 
827
 
 
828
                        if (enc_idx != GEANY_ENCODING_UTF_8) /* the BOM indicated something else than UTF-8 */
 
829
                        {
 
830
                                gchar *converted_text = encodings_convert_to_utf8_from_charset(
 
831
                                                                                buffer->data, buffer->size, buffer->enc, FALSE);
 
832
                                if (converted_text != NULL)
 
833
                                {
 
834
                                        setptr(buffer->data, converted_text);
 
835
                                        buffer->len = strlen(converted_text);
 
836
                                }
 
837
                                else
 
838
                                {
 
839
                                        /* there was a problem converting data from BOM encoding type */
 
840
                                        setptr(buffer->enc, NULL);
 
841
                                        buffer->bom = FALSE;
 
842
                                }
 
843
                        }
 
844
                }
 
845
 
 
846
                if (buffer->enc == NULL)        /* either there was no BOM or the BOM encoding failed */
 
847
                {
 
848
                        /* first try to read the encoding from the file content */
 
849
                        gchar *regex_charset = encodings_check_regexes(buffer->data, buffer->size);
 
850
 
 
851
                        /* try UTF-8 first */
 
852
                        if (encodings_get_idx_from_charset(regex_charset) == GEANY_ENCODING_UTF_8 &&
 
853
                                (buffer->size == buffer->len) && g_utf8_validate(buffer->data, buffer->len, NULL))
 
854
                        {
 
855
                                buffer->enc = g_strdup("UTF-8");
 
856
                        }
 
857
                        else
 
858
                        {
 
859
                                /* detect the encoding */
 
860
                                gchar *converted_text = encodings_convert_to_utf8_with_suggestion(buffer->data,
 
861
                                        buffer->size, regex_charset, &buffer->enc);
 
862
 
 
863
                                if (converted_text == NULL)
 
864
                                {
 
865
                                        g_free(regex_charset);
 
866
                                        return FALSE;
 
867
                                }
 
868
                                setptr(buffer->data, converted_text);
 
869
                                buffer->len = strlen(converted_text);
 
870
                        }
 
871
                        g_free(regex_charset);
 
872
                }
 
873
        }
 
874
        return TRUE;
 
875
}
 
876
 
 
877
 
 
878
static void
 
879
handle_bom(BufferData *buffer)
 
880
{
 
881
        guint bom_len;
 
882
 
 
883
        encodings_scan_unicode_bom(buffer->data, buffer->size, &bom_len);
 
884
        g_return_if_fail(bom_len != 0);
 
885
 
 
886
        /* use filedata->len here because the contents are already converted into UTF-8 */
 
887
        buffer->len -= bom_len;
 
888
        /* overwrite the BOM with the remainder of the file contents, plus the NULL terminator. */
 
889
        g_memmove(buffer->data, buffer->data + bom_len, buffer->len + 1);
 
890
        buffer->data = g_realloc(buffer->data, buffer->len + 1);
 
891
}
 
892
 
 
893
 
 
894
/* loads textfile data, verifies and converts to forced_enc or UTF-8. Also handles BOM. */
 
895
static gboolean handle_buffer(BufferData *buffer, const gchar *forced_enc)
 
896
{
 
897
        GeanyEncodingIndex tmp_enc_idx;
 
898
 
 
899
        /* temporarily retrieve the encoding idx based on the BOM to suppress the following warning
 
900
         * if we have a BOM */
 
901
        tmp_enc_idx = encodings_scan_unicode_bom(buffer->data, buffer->size, NULL);
 
902
 
 
903
        /* check whether the size of the loaded data is equal to the size of the file in the
 
904
         * filesystem file size may be 0 to allow opening files in /proc/ which have typically a
 
905
         * file size of 0 bytes */
 
906
        if (buffer->len != buffer->size && buffer->size != 0 && (
 
907
                tmp_enc_idx == GEANY_ENCODING_UTF_8 || /* tmp_enc_idx can be UTF-7/8/16/32, UCS and None */
 
908
                tmp_enc_idx == GEANY_ENCODING_UTF_7))  /* filter UTF-7/8 where no NULL bytes are allowed */
 
909
        {
 
910
                buffer->partial = TRUE;
 
911
        }
 
912
 
 
913
        /* Determine character encoding and convert to UTF-8 */
 
914
        if (forced_enc != NULL)
 
915
        {
 
916
                /* the encoding should be ignored(requested by user), so open the file "as it is" */
 
917
                if (utils_str_equal(forced_enc, encodings[GEANY_ENCODING_NONE].charset))
 
918
                {
 
919
                        buffer->bom = FALSE;
 
920
                        buffer->enc = g_strdup(encodings[GEANY_ENCODING_NONE].charset);
 
921
                }
 
922
                else if (! handle_forced_encoding(buffer, forced_enc))
 
923
                {
 
924
                        return FALSE;
 
925
                }
 
926
        }
 
927
        else if (! handle_encoding(buffer, tmp_enc_idx))
 
928
        {
 
929
                return FALSE;
 
930
        }
 
931
 
 
932
        if (buffer->bom)
 
933
                handle_bom(buffer);
 
934
        return TRUE;
 
935
}
 
936
 
 
937
 
 
938
/*
 
939
 * Tries to convert @a buffer into UTF-8 encoding. Unlike encodings_convert_to_utf8()
 
940
 * and encodings_convert_to_utf8_from_charset() it handles the possible BOM in the data.
 
941
 *
 
942
 * @param buf a pointer to modifiable null-terminated buffer to convert.
 
943
 *   It may or may not be modified, and should be freed whatever happens.
 
944
 * @param size a pointer to the size of the buffer (expected to be e.g. the on-disk
 
945
 *   file size). It will be updated to the new size.
 
946
 * @param forced_enc forced encoding to use, or @c NULL
 
947
 * @param used_encoding return location for the actually used encoding, or @c NULL
 
948
 * @param has_bom return location to store whether the data had a BOM, or @c NULL
 
949
 * @param partial return location to store whether the conversion may be partial, or @c NULL
 
950
 *
 
951
 * @return @C TRUE if the conversion succeeded, @c FALSE otherwise.
 
952
 */
 
953
gboolean encodings_convert_to_utf8_auto(gchar **buf, gsize *size, const gchar *forced_enc,
 
954
                gchar **used_encoding, gboolean *has_bom, gboolean *partial)
 
955
{
 
956
        BufferData buffer;
 
957
 
 
958
        buffer.data = *buf;
 
959
        buffer.size = *size;
 
960
        /* use strlen to check for null chars */
 
961
        buffer.len = strlen(buffer.data);
 
962
        buffer.enc = NULL;
 
963
        buffer.bom = FALSE;
 
964
        buffer.partial = FALSE;
 
965
 
 
966
        if (! handle_buffer(&buffer, forced_enc))
 
967
                return FALSE;
 
968
 
 
969
        *size = buffer.len;
 
970
        if (used_encoding)
 
971
                *used_encoding = buffer.enc;
 
972
        else
 
973
                g_free(buffer.enc);
 
974
        if (has_bom)
 
975
                *has_bom = buffer.bom;
 
976
        if (partial)
 
977
                *partial = buffer.partial;
 
978
 
 
979
        *buf = buffer.data;
 
980
        return TRUE;
 
981
}