1717
1818#include <sys/stat.h>
1919
20- #ifdef USING_ID3TAG
20+ #if defined( USING_ID3TAG ) || defined( HAVE_LAME_ID3TAG )
2121
2222static char const * id3tagmap [][2 ] =
2323{
@@ -32,49 +32,99 @@ static char const * id3tagmap[][2] =
3232 {NULL , NULL }
3333};
3434
35- #endif /* USING_ID3TAG */
35+ #endif /* USING_ID3TAG || HAVE_LAME_ID3TAG */
3636
3737#if defined(HAVE_LAME )
3838
39+
40+ #if defined _WIN32 || defined _WIN64
41+
42+ #include <wchar.h>
43+ #include <windows.h>
44+
45+ #define UTF16_ID3 1
46+
47+ static unsigned short * utf8_to_utf16 (const char * utf8 )
48+ {
49+ int len = strlen (utf8 );
50+ int wlength = MultiByteToWideChar (CP_UTF8 , MB_ERR_INVALID_CHARS , utf8 , len , 0 , 0 );
51+ if (wlength == 0 ) return NULL ;
52+ LPWSTR wstr = (LPWSTR )calloc ((size_t )(wlength + 2 ), sizeof (wchar_t ));
53+ MultiByteToWideChar (CP_UTF8 , MB_ERR_INVALID_CHARS , utf8 , len , wstr + 1 , wlength );
54+ wstr [0 ] = 0xFEFF ; /* add BOM, it is required by LAME */
55+ return (unsigned short * ) wstr ;
56+ }
57+
58+ #elif defined(HAVE_ICONV )
59+
60+ #include <iconv.h>
61+
62+ #define UTF16_ID3 1
63+
64+ static unsigned short * utf8_to_utf16 (const char * utf8 ) {
65+ size_t inSize , outSize , cstrSize ;
66+ char * in , * out , * cstr ;
67+
68+ inSize = strlen (utf8 );
69+ outSize = inSize * 2 + 2 ; /* worst case, UTF-16 can take max twice as much space as UTF-8 */
70+ in = (char * ) utf8 ;
71+ out = lsx_malloc (outSize );
72+ cstr = out ;
73+
74+ iconv_t conv = iconv_open ("UTF-16" , "UTF-8" );
75+ size_t status = iconv (conv , & in , & inSize , & out , & outSize );
76+ iconv_close (conv );
77+
78+ if (status == ((size_t ) -1 )) {
79+ free (cstr );
80+ return NULL ;
81+ }
82+
83+ cstrSize = out - cstr ;
84+ cstr [cstrSize ] = 0 ; /* add null-terminator, first byte */
85+ cstr [cstrSize + 1 ] = 0 ; /* second byte */
86+ return (unsigned short * ) cstr ;
87+ }
88+
89+ #endif /* HAVE_ICONV */
90+
91+
92+
93+ static void set_id3_field (priv_t * p , const char * field , const char * value )
94+ {
95+ char * buf = lsx_malloc (strlen (field ) + strlen (value ) + 2 );
96+ if (!buf ) return ;
97+ sprintf (buf , "%s=%s" , field , value );
98+
99+ #if defined(UTF16_ID3 )
100+ unsigned short * utf16 = utf8_to_utf16 (buf );
101+ if (utf16 ) {
102+ p -> id3tag_set_fieldvalue_utf16 (p -> gfp , utf16 );
103+ free (utf16 );
104+ } else {
105+ /* the value wasn't valid utf8, fall back to latin1 */
106+ p -> id3tag_set_fieldvalue (p -> gfp , buf );
107+ }
108+ #else
109+ p -> id3tag_set_fieldvalue (p -> gfp , buf );
110+ #endif
111+
112+ free (buf );
113+ }
114+
115+
39116static void write_comments (sox_format_t * ft )
40117{
41118 priv_t * p = (priv_t * ) ft -> priv ;
42119 const char * comment ;
120+ size_t i ;
43121
44122 p -> id3tag_init (p -> gfp );
45123 p -> id3tag_set_pad (p -> gfp , (size_t )ID3PADDING );
46124
47- /* Note: id3tag_set_fieldvalue is not present in LAME 3.97, so we're using
48- the 3.97-compatible methods for all of the tags that 3.97 supported. */
49- /* FIXME: This is no more necessary, since support for LAME 3.97 has ended. */
50- if ((comment = sox_find_comment (ft -> oob .comments , "Title" )))
51- p -> id3tag_set_title (p -> gfp , comment );
52- if ((comment = sox_find_comment (ft -> oob .comments , "Artist" )))
53- p -> id3tag_set_artist (p -> gfp , comment );
54- if ((comment = sox_find_comment (ft -> oob .comments , "Album" )))
55- p -> id3tag_set_album (p -> gfp , comment );
56- if ((comment = sox_find_comment (ft -> oob .comments , "Tracknumber" )))
57- p -> id3tag_set_track (p -> gfp , comment );
58- if ((comment = sox_find_comment (ft -> oob .comments , "Year" )))
59- p -> id3tag_set_year (p -> gfp , comment );
60- if ((comment = sox_find_comment (ft -> oob .comments , "Comment" )))
61- p -> id3tag_set_comment (p -> gfp , comment );
62- if ((comment = sox_find_comment (ft -> oob .comments , "Genre" )))
63- {
64- if (p -> id3tag_set_genre (p -> gfp , comment ))
65- lsx_warn ("\"%s\" is not a recognized ID3v1 genre." , comment );
66- }
67-
68- if ((comment = sox_find_comment (ft -> oob .comments , "Discnumber" )))
69- {
70- char * id3tag_buf = lsx_malloc (strlen (comment ) + 6 );
71- if (id3tag_buf )
72- {
73- sprintf (id3tag_buf , "TPOS=%s" , comment );
74- p -> id3tag_set_fieldvalue (p -> gfp , id3tag_buf );
75- free (id3tag_buf );
76- }
77- }
125+ for (i = 0 ; id3tagmap [i ][0 ]; ++ i )
126+ if ((comment = sox_find_comment (ft -> oob .comments , id3tagmap [i ][1 ])))
127+ set_id3_field (p , id3tagmap [i ][0 ], comment );
78128}
79129
80130#endif /* HAVE_LAME */
0 commit comments