~jcowgill/ubuntu/trusty/easytag/bug-1295882

« back to all changes in this revision

Viewing changes to src/charset.c

  • Committer: Bazaar Package Importer
  • Author(s): Michal Čihař
  • Date: 2008-09-08 21:44:11 UTC
  • mfrom: (3.1.10 hardy)
  • Revision ID: james.westby@ubuntu.com-20080908214411-v237hcgn5d97ecut
Tags: 2.1.4-1.1
* Non-maintainer upload.
* Warn user when ogg vorbis tags will be lost, fix handling of multiple same
  ogg vorbis tags (Closes: #460247).
* Fix lintian warnings:
  - Add watch file.
  - Install icon for menu file (Closes: #477456).
  - Fix section in menu file.
  - Drop version from NAME section of man page to `apropos' and `whatis'
    happy.
  - Include copyright information in debian/copyright.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
 
34
34
#include "charset.h"
35
35
#include "setting.h"
 
36
#include "log.h"
36
37
 
37
38
#ifdef WIN32
38
 
    #include "win32dep.h"
 
39
    #include "win32/win32dep.h"
39
40
#endif
40
41
 
41
42
 
44
45
 ****************/
45
46
 
46
47
#define CHARSET_TRANS_ARRAY_LEN ( sizeof(charset_trans_array) / sizeof((charset_trans_array)[0]) )
47
 
const CharsetInfo charset_trans_array[] = { 
 
48
const CharsetInfo charset_trans_array[] = {
48
49
    {N_("Arabic (IBM-864)"),                  "IBM864"        },
49
50
    {N_("Arabic (ISO-8859-6)"),               "ISO-8859-6"    },
50
51
    {N_("Arabic (Windows-1256)"),             "windows-1256"  },
81
82
    {N_("Turkish (IBM-857)"),                 "IBM857"        },
82
83
    {N_("Turkish (ISO-8859-9)"),              "ISO-8859-9"    },
83
84
    {N_("Turkish (Windows-1254)"),            "windows-1254"  },
84
 
    {N_("Unicode (UTF-7)"),                   "UTF-7"         },
 
85
    //{N_("Unicode (UTF-7)"),                   "UTF-7"         },
85
86
    {N_("Unicode (UTF-8)"),                   "UTF-8"         },
86
 
    
87
 
    {N_("Unicode (UTF-16BE)"),                "UTF-16BE"      },
88
 
    {N_("Unicode (UTF-16LE)"),                "UTF-16LE"      },
 
87
 
 
88
    //{N_("Unicode (UTF-16BE)"),                "UTF-16BE"      },
 
89
    //{N_("Unicode (UTF-16LE)"),                "UTF-16LE"      },
89
90
    //{N_("Unicode (UTF-32BE)"),                "UTF-32BE"      },
90
91
    //{N_("Unicode (UTF-32LE)"),                "UTF-32LE"      },
91
 
    
 
92
 
92
93
    {N_("Vietnamese (VISCII)"),               "VISCII"        },
93
94
    {N_("Vietnamese (Windows-1258)"),         "windows-1258"  },
94
95
    {N_("Visual Hebrew (ISO-8859-8)"),        "ISO-8859-8"    },
165
166
    char *s;
166
167
 
167
168
    va_start (args, enc);
168
 
    for (;;) {
 
169
    for (;;)
 
170
    {
169
171
        s = va_arg (args, char *);
170
172
        if (s == NULL)
171
173
            break;
183
185
 
184
186
    /* "C" is plain ascii */
185
187
    insert_locales (encodings, "ASCII", "C", NULL);
186
 
 
 
188
#if WIN32
 
189
    insert_locales (encodings, "windows-1256", "ar", NULL); // 2006.12.31 - For testing with Arabic
 
190
#else
 
191
    insert_locales (encodings, "ISO-8859-6", "ar", NULL);
 
192
#endif
187
193
    insert_locales (encodings, "ARMSCII-8", "by", NULL);
188
194
    insert_locales (encodings, "BIG5", "zh_TW", NULL);
189
195
    insert_locales (encodings, "CP1251", "be", "bg", NULL);
196
202
    insert_locales (encodings, "EUC-KR", "ko", NULL);
197
203
    /*insert_locales (encodings, "GEORGIAN-ACADEMY", NULL);*/
198
204
    insert_locales (encodings, "GEORGIAN-PS", "ka", NULL);
199
 
    insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "no", "pt", "pt", "sv", NULL);
 
205
    insert_locales (encodings, "ISO-8859-1", "br", "ca", "da", "de", "en", "es", "eu", "fi", "fr", "gl", "it", "nl", "wa", "nb", "nn", "pt", "pt", "sv", NULL);
 
206
#if WIN32
 
207
    insert_locales (encodings, "windows-1250", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL);
 
208
#else
200
209
    insert_locales (encodings, "ISO-8859-2", "cs", "hr", "hu", "pl", "ro", "sk", "sl", "sq", "sr", NULL);
 
210
#endif
201
211
    insert_locales (encodings, "ISO-8859-3", "eo", NULL);
202
212
    insert_locales (encodings, "ISO-8859-5", "mk", "sp", NULL);
 
213
#if WIN32
 
214
    insert_locales (encodings, "windows-1253", "el", NULL);
 
215
#else
203
216
    insert_locales (encodings, "ISO-8859-7", "el", NULL);
 
217
#endif
 
218
#if WIN32
 
219
    insert_locales (encodings, "windows-1254", "tr", NULL);
 
220
#else
204
221
    insert_locales (encodings, "ISO-8859-9", "tr", NULL);
 
222
#endif
205
223
    insert_locales (encodings, "ISO-8859-13", "lt", "lv", "mi", NULL);
206
224
    insert_locales (encodings, "ISO-8859-14", "ga", "cy", NULL);
207
225
    insert_locales (encodings, "ISO-8859-15", "et", NULL);
 
226
#if WIN32
 
227
    insert_locales (encodings, "windows-1251", "ru", NULL);
 
228
#else
208
229
    insert_locales (encodings, "KOI8-R", "ru", NULL);
 
230
#endif
209
231
    insert_locales (encodings, "KOI8-U", "uk", NULL);
210
232
    if (check_locale ("TCVN-5712")) {
211
233
        insert_locales (encodings, "TCVN-5712", "vi", NULL);
213
235
        insert_locales (encodings, "TCVN", "vi", NULL);
214
236
    }
215
237
    insert_locales (encodings, "TIS-620", "th", NULL);
 
238
#if WIN32
 
239
    insert_locales (encodings, "windows-1255", "he", NULL);
 
240
#endif
216
241
    /*insert_locales (encodings, "VISCII", NULL);*/
217
242
}
218
243
 
259
284
 * Return the locale from LANG if exists, else from LC_ALL
260
285
 *
261
286
 * http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html#tag_08_02
262
 
 * 
 
287
 *
263
288
 * LANG
264
289
 *     This variable shall determine the locale category for native language,
265
290
 *     local customs, and coded character set in the absence of the LC_ALL and
266
291
 *     other LC_* ( LC_COLLATE , LC_CTYPE , LC_MESSAGES , LC_MONETARY , LC_NUMERIC ,
267
 
 *     LC_TIME ) environment variables. This can be used by applications to 
 
292
 *     LC_TIME ) environment variables. This can be used by applications to
268
293
 *     determine the language to use for error messages and instructions, collating
269
294
 *     sequences, date formats, and so on.
270
295
 * LC_ALL
310
335
 *     This variable shall determine the locale category for date and time formatting
311
336
 *     information. It affects the behavior of the time functions in strftime().
312
337
 *     Additional semantics of this variable, if any, are implementation-defined.
313
 
 * 
314
 
 * 
 
338
 *
 
339
 *
315
340
 * The values of locale categories shall be determined by a precedence order; the
316
341
 * first condition met below determines the value:
317
 
 * 
 
342
 *
318
343
 *    1. If the LC_ALL environment variable is defined and is not null, the value
319
344
 *       of LC_ALL shall be used.
320
345
 *    2. If the LC_* environment variable ( LC_COLLATE , LC_CTYPE , LC_MESSAGES ,
325
350
 *       the LANG environment variable shall be used.
326
351
 *    4. If the LANG environment variable is not set or is set to the empty string,
327
352
 *       the implementation-defined default locale shall be used.
328
 
 * 
 
353
 *
329
354
 */
330
355
const gchar *get_locale (void)
331
356
{
332
357
    if (g_getenv("LC_ALL"))
333
358
        return g_getenv("LC_ALL");
334
 
    
 
359
 
335
360
    else if (g_getenv("LC_CTYPE"))
336
361
        return g_getenv("LC_CTYPE");
337
 
    
 
362
 
338
363
    else if (g_getenv("LANG"))
339
364
        return g_getenv("LANG");
340
 
    
 
365
 
341
366
    else
342
367
        return NULL;
343
368
}
347
372
 
348
373
/*
349
374
 * convert_string : (don't use with UTF-16 strings)
350
 
 *  - display_error : if TRUE, may return an escaped string and display an error 
 
375
 *  - display_error : if TRUE, may return an escaped string and display an error
351
376
 *                    message (if conversion fails).
352
377
 */
353
378
gchar *convert_string (const gchar *string, const gchar *from_codeset,
366
391
 
367
392
    if (!string)
368
393
        return NULL;
369
 
    
 
394
 
370
395
    output = g_convert(string, length, to_codeset, from_codeset, NULL, &bytes_written, &error);
371
396
    //output = g_convert_with_fallback(string, length, to_codeset, from_codeset, "?", NULL, &bytes_written, &error);
372
397
 
375
400
        gchar *escaped_str = g_strescape(string, NULL);
376
401
        if (display_error)
377
402
        {
378
 
            g_warning("convert_string(): Failed conversion from charset '%s' to '%s'. "
379
 
                      "String '%s'. Errcode %d (%s).\n",
 
403
            Log_Print(LOG_ERROR,"convert_string(): Failed conversion from charset '%s' to '%s'. "
 
404
                      "String '%s'. Errcode %d (%s).",
380
405
                      from_codeset, to_codeset, escaped_str, error->code, error->message);
381
406
        }
382
407
        g_free(escaped_str);
383
408
        g_error_free(error);
384
 
        // Return the input string without converting it. If the string is 
 
409
        // Return the input string without converting it. If the string is
385
410
        // displayed in the UI, it must be in UTF-8!
386
411
        if ( (g_ascii_strcasecmp(to_codeset, "UTF-8"))
387
412
        ||   (g_utf8_validate(string, -1, NULL)) )
392
417
    {
393
418
        // Patch from Alexey Illarionov:
394
419
        //    g_convert returns null-terminated string only with one \0 at the
395
 
        // end. It can cause some garbage at the end of a string for UTF-16. 
 
420
        // end. It can cause some garbage at the end of a string for UTF-16.
396
421
        // The second \0 should be set manually.
397
422
        output = g_realloc(output, bytes_written + 2);
398
423
        if (output != NULL)
399
424
            output[bytes_written] = output[bytes_written + 1] = 0;
400
425
    }
401
 
    
 
426
 
402
427
    //g_print("from %s => len: %d, string: '%s'\n     (%x %x %x %x %x %x %x %x)\n",from_codeset,length,string,string[0],string[1],string[2],string[3],string[4],string[5],string[6],string[7]);
403
428
    //g_print("to   %s => len: %d, output: '%s'\n     (%x %x %x %x %x %x %x %x)\n\n",to_codeset,bytes_written+2,output,output[0],output[1],output[2],output[3],output[4],output[5],output[6],output[7]);
404
429
 
424
449
        const gchar *usercharset;
425
450
        gchar *escaped_str = g_strescape(string, NULL);
426
451
        g_get_charset(&usercharset);
427
 
        g_warning("convert_to_utf8(): Failed conversion from charset '%s'. "
428
 
                  "String '%s'. Errcode %d (%s).\n",
 
452
        Log_Print(LOG_ERROR,"convert_to_utf8(): Failed conversion from charset '%s'. "
 
453
                  "String '%s'. Errcode %d (%s).",
429
454
                  usercharset, escaped_str, error->code, error->message);
430
455
        g_free(escaped_str);
431
456
 
432
457
        if (g_utf8_validate(string, -1, NULL))
433
 
            g_warning("convert_to_utf8(): String was valid UTF-8.\n");
 
458
            Log_Print(LOG_ERROR,"convert_to_utf8(): String was valid UTF-8.");
434
459
        else
435
 
            g_warning("convert_to_utf8(): String was INVALID UTF-8.\n");
 
460
            Log_Print(LOG_ERROR,"convert_to_utf8(): String was INVALID UTF-8.");
436
461
 
437
462
        g_error_free(error);
438
463
        return g_strdup(string);
456
481
        const gchar *usercharset;
457
482
        gchar *escaped_str = g_strescape(string, NULL);
458
483
        g_get_charset(&usercharset);
459
 
        g_warning("convert_from_utf8(): Failed conversion to charset '%s'. "
460
 
                  "String '%s'. Errcode %d (%s).\n",
 
484
        Log_Print(LOG_ERROR,"convert_from_utf8(): Failed conversion to charset '%s'. "
 
485
                  "String '%s'. Errcode %d (%s).",
461
486
                  usercharset, escaped_str, error->code, error->message);
462
487
        g_free(escaped_str);
463
488
 
464
489
        if (g_utf8_validate(string, -1, NULL))
465
 
            g_warning("convert_from_utf8(): String was valid UTF-8.\n");
 
490
            Log_Print(LOG_ERROR,"convert_from_utf8(): String was valid UTF-8.");
466
491
        else
467
 
            g_warning("convert_from_utf8(): String was INVALID UTF-8.\n");
 
492
            Log_Print(LOG_ERROR,"convert_from_utf8(): String was INVALID UTF-8.");
468
493
 
469
494
        g_error_free(error);
470
495
        return g_strdup(string);
515
540
        if (!ret)
516
541
        {
517
542
            gchar *escaped_str = g_strescape(string, NULL);
518
 
            g_warning(_("The filename '%s' couldn't be converted into UTF-8 (%s).\n"),
 
543
            Log_Print(LOG_ERROR,_("The filename '%s' couldn't be converted into UTF-8 (%s)."),
519
544
                        escaped_str, error && error->message ? error->message : _("Invalid UTF-8"));
520
545
            g_clear_error(&error);
521
546
 
544
569
    //const gchar *filename_encoding = NULL;
545
570
 
546
571
    if (!string) return NULL;
547
 
    
 
572
 
548
573
    // Get system encoding from LANG if found (ex : fr_FR.UTF-8 => UTF-8)
549
574
    if (get_locale())
550
575
        char_encoding = strchr(get_locale(), '.');
551
 
    
 
576
 
552
577
    if (char_encoding)
553
578
        char_encoding = char_encoding+1; // Skip the '.'
554
579
    if (char_encoding)
555
580
    {
556
581
        error = NULL;
557
 
        
 
582
 
558
583
        if (FILENAME_CHARACTER_SET_OTHER)
559
584
        {
560
585
            ret = g_convert(string, -1, char_encoding, "UTF-8", NULL, NULL, &error);
561
 
            
 
586
 
562
587
        }else if (FILENAME_CHARACTER_SET_APPROXIMATE)
563
588
        {
564
589
            // iconv_open (3):
569
594
            gchar *enc = g_strconcat(char_encoding, "//TRANSLIT", NULL);
570
595
            ret = g_convert(string, -1, enc, "UTF-8", NULL, NULL, &error);
571
596
            g_free(enc);
572
 
            
 
597
 
573
598
        }else if (FILENAME_CHARACTER_SET_DISCARD)
574
599
        {
575
600
            // iconv_open (3):
581
606
            g_free(enc);
582
607
        }
583
608
    }
584
 
    
 
609
 
585
610
    if (!ret)
586
611
    {
587
612
        // Get system encoding from locale in LANG if found (ex : fr_FR.UTF-8 => fr_FR => ISO-8859-1)
593
618
            ret = g_convert(string, -1, char_encoding, "UTF-8", NULL, NULL, &error);
594
619
        }
595
620
    }
596
 
        
 
621
 
597
622
    if (!ret)
598
623
    {
599
624
        // Failing that, try ISO-8859-1
609
634
            ret = g_strdup(string);
610
635
        }
611
636
    }
612
 
    
 
637
 
613
638
    if (!ret)
614
639
    {
615
640
        // Conversion KO!
616
641
        gchar *escaped_str = g_strescape(string, NULL);
617
 
        g_warning(_("The UTF-8 string '%s' couldn't be converted into filename encoding (%s)\n"),
 
642
        Log_Print(LOG_ERROR,_("The UTF-8 string '%s' couldn't be converted into filename encoding (%s)."),
618
643
                    escaped_str, error && error->message ? error->message : _("Invalid UTF-8"));
619
644
        g_clear_error(&error);
620
645
 
629
654
}
630
655
 
631
656
 
 
657
 
 
658
/*
 
659
 * Function used when reading tags : we check if the string is valid UTF-8 (else
 
660
 *   it may cause problem in EasyTAG)
 
661
 *
 
662
 * Examples :
 
663
 *   - some Ogg Vorbis tags contain ISO-8859-1 characters instead of UTF-8).
 
664
 *   - some Flac tags may be probably encoded to ISO-8859-15 (by using for example
 
665
 *     "metaflac --no-utf8-convert ...") so we convert it from ISO-8859-1 to UTF-8.
 
666
 *
 
667
 * If not valid UTF-8, we try some conversion to try to get the correct string
 
668
 *  - conversion OK : returns the UTF-8 string (new allocated)
 
669
 *  - conversion KO : tries others encodings else returns an 'escaped' string
 
670
 */
 
671
gchar *Try_To_Validate_Utf8_String (const gchar *string)
 
672
{
 
673
    gchar *ret = NULL;
 
674
    GError *error = NULL;
 
675
 
 
676
    if (!string)
 
677
        return NULL;
 
678
 
 
679
    if (g_utf8_validate(string, -1, NULL))
 
680
    {
 
681
        // String already in UTF-8
 
682
        ret = g_strdup(string);
 
683
    }else
 
684
    {
 
685
        const gchar *char_encoding;
 
686
 
 
687
        // Get encoding associated to the locale without using UTF-8 (ex , if LANG=fr_FR.UTF-8 it will return ISO-8859-1)
 
688
        char_encoding = get_encoding_from_locale(get_locale());
 
689
        if (char_encoding)
 
690
        {
 
691
            //g_print("> char_encoding: %s\n",char_encoding);
 
692
            error = NULL;
 
693
            ret = g_convert(string, -1, "UTF-8", char_encoding, NULL, NULL, &error);
 
694
        }
 
695
 
 
696
        if (!ret)
 
697
        {
 
698
            // Failing that, try ISO-8859-1
 
699
            error = NULL;
 
700
            ret = g_convert(string, -1, "UTF-8", "ISO-8859-1", NULL, NULL, &error);
 
701
        }
 
702
 
 
703
        if (!ret)
 
704
        {
 
705
            gchar *escaped_str = g_strescape(string, NULL);
 
706
            Log_Print(LOG_ERROR,_("The string '%s' couldn't be converted into UTF-8 (%s)."),
 
707
                        escaped_str, error && error->message ? error->message : _("Invalid UTF-8"));
 
708
            g_clear_error(&error);
 
709
 
 
710
            ret = escaped_str;
 
711
        }
 
712
    }
 
713
 
 
714
    return ret;
 
715
}
 
716
 
 
717
 
 
718
 
632
719
void Charset_Populate_Combobox (GtkComboBox *combo, gchar *select_charset)
633
720
{
634
721
    guint i;
682
769
gboolean test_conversion_charset (const gchar *from, const gchar *to)
683
770
{
684
771
    gchar *temp;
685
 
    
 
772
 
686
773
    if (!from || !to)
687
774
        return FALSE;
688
 
    
 
775
 
689
776
    // Do a quick test conversion and examine error output
690
777
    if ( strcmp(from,"UTF-16BE") == 0 )
691
778
    {
697
784
    {
698
785
        temp = convert_string("FOO", from, to, FALSE);
699
786
    }
700
 
    
 
787
 
701
788
    if (!temp)
702
789
    {
703
790
        /*// Error in conversion
704
791
        if (error && error->code == G_CONVERT_ERROR_NO_CONVERSION)
705
792
        {
706
 
            g_print("Conversion error from '%s' to '%s' (G_CONVERT_ERROR_NO_CONVERSION)\n",from,to);
 
793
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (G_CONVERT_ERROR_NO_CONVERSION)",from,to);
707
794
        } else if (error && error->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE)
708
795
        {
709
 
            g_print("Conversion error from '%s' to '%s' (G_CONVERT_ERROR_ILLEGAL_SEQUENCE)\n",from,to);
 
796
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (G_CONVERT_ERROR_ILLEGAL_SEQUENCE)",from,to);
710
797
        } else if (error && error->code == G_CONVERT_ERROR_FAILED)
711
798
        {
712
 
            g_print("Conversion error from '%s' to '%s' (G_CONVERT_ERROR_FAILED)\n",from,to);
 
799
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (G_CONVERT_ERROR_FAILED)",from,to);
713
800
        } else if (error && error->code == G_CONVERT_ERROR_PARTIAL_INPUT)
714
801
        {
715
 
            g_print("Conversion error from '%s' to '%s' (G_CONVERT_ERROR_PARTIAL_INPUT)\n",from,to);
 
802
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (G_CONVERT_ERROR_PARTIAL_INPUT)",from,to);
716
803
        } else if (error && error->code == G_CONVERT_ERROR_BAD_URI)
717
804
        {
718
 
            g_print("Conversion error from '%s' to '%s' (G_CONVERT_ERROR_BAD_URI)\n",from,to);
 
805
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (G_CONVERT_ERROR_BAD_URI)",from,to);
719
806
        } else if (error && error->code == G_CONVERT_ERROR_NOT_ABSOLUTE_PATH)
720
807
        {
721
 
            g_print("Conversion error from '%s' to '%s' (G_CONVERT_ERROR_NOT_ABSOLUTE_PATH)\n",from,to);
 
808
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (G_CONVERT_ERROR_NOT_ABSOLUTE_PATH)",from,to);
722
809
        } else
723
810
        {
724
 
            g_print("Conversion error from '%s' to '%s' (unknown : %d)\n",from,to,error->code);
 
811
            Log_Print(LOG_ERROR,"Conversion error from '%s' to '%s' (unknown : %d)",from,to,error->code);
725
812
        }
726
 
        
 
813
 
727
814
        if (error)
728
815
            g_error_free(error);*/
729
816
        return FALSE;