libc.c 28.5 KB
Newer Older
1
2
3
/*****************************************************************************
 * libc.c: Extra libc function for some systems.
 *****************************************************************************
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
4
 * Copyright (C) 2002-2006 the VideoLAN team
5
 * $Id$
6
7
8
 *
 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
 *          Samuel Hocevar <sam@zoy.org>
9
 *          Gildas Bazin <gbazin@videolan.org>
10
 *          Derk-Jan Hartman <hartman at videolan dot org>
11
 *          Christophe Massiot <massiot@via.ecp.fr>
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
12
 *          Rémi Denis-Courmont <rem à videolan.org>
13
14
15
16
17
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
18
 *
19
20
21
22
23
24
25
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
26
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
27
 *****************************************************************************/
28
29
30
31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
33

34
35
36
37
38
39
40
41
#undef iconv_t
#undef iconv_open
#undef iconv
#undef iconv_close

#if defined(HAVE_ICONV)
#   include <iconv.h>
#endif
42
43
44
45

#ifdef HAVE_DIRENT_H
#   include <dirent.h>
#endif
46

47
#ifdef HAVE_FORK
Pierre Ynard's avatar
Pierre Ynard committed
48
#   include <signal.h>
49
50
51
#   include <unistd.h>
#   include <errno.h>
#   include <sys/wait.h>
52
#   include <sys/socket.h>
53
#   include <sys/poll.h>
54
55
56
#   ifndef PF_LOCAL
#       define PF_LOCAL PF_UNIX
#   endif
57
58
#endif

59
#if defined(WIN32) || defined(UNDER_CE)
60
61
62
#   undef _wopendir
#   undef _wreaddir
#   undef _wclosedir
63
#   undef rewinddir
64
65
66
67
#   define WIN32_LEAN_AND_MEAN
#   include <windows.h>
#endif

68
69
70
71
/*****************************************************************************
 * vlc_*dir_wrapper: wrapper under Windows to return the list of drive letters
 * when called with an empty argument or just '\'
 *****************************************************************************/
geal's avatar
geal committed
72
#if defined(WIN32)
73
74
#   include <assert.h>

75
76
typedef struct vlc_DIR
{
77
    _WDIR *p_real_dir;
78
    int i_drives;
79
    struct _wdirent dd_dir;
80
    bool b_insert_back;
81
82
} vlc_DIR;

83
void *vlc_wopendir( const wchar_t *wpath )
84
{
85
86
    vlc_DIR *p_dir = NULL;
    _WDIR *p_real_dir = NULL;
87

88
89
    if ( wpath == NULL || wpath[0] == '\0'
          || (wcscmp (wpath, L"\\") == 0) )
90
91
92
    {
        /* Special mode to list drive letters */
        p_dir = malloc( sizeof(vlc_DIR) );
93
94
        if( !p_dir )
            return NULL;
95
        p_dir->p_real_dir = NULL;
96
#if defined(UNDER_CE)
geal's avatar
geal committed
97
        p_dir->i_drives = NULL;
98
#else
99
        p_dir->i_drives = GetLogicalDrives();
geal's avatar
geal committed
100
#endif
101
102
103
        return (void *)p_dir;
    }

104
    p_real_dir = _wopendir( wpath );
105
106
107
108
    if ( p_real_dir == NULL )
        return NULL;

    p_dir = malloc( sizeof(vlc_DIR) );
109
110
111
112
113
    if( !p_dir )
    {
        _wclosedir( p_real_dir );
        return NULL;
    }
114
    p_dir->p_real_dir = p_real_dir;
115
116
117

    assert (wpath[0]); // wpath[1] is defined
    p_dir->b_insert_back = !wcscmp (wpath + 1, L":\\");
118
119
120
    return (void *)p_dir;
}

121
struct _wdirent *vlc_wreaddir( void *_p_dir )
122
123
124
125
126
127
128
129
{
    vlc_DIR *p_dir = (vlc_DIR *)_p_dir;
    DWORD i_drives;

    if ( p_dir->p_real_dir != NULL )
    {
        if ( p_dir->b_insert_back )
        {
130
            /* Adds "..", gruik! */
131
132
133
            p_dir->dd_dir.d_ino = 0;
            p_dir->dd_dir.d_reclen = 0;
            p_dir->dd_dir.d_namlen = 2;
134
            wcscpy( p_dir->dd_dir.d_name, L".." );
135
            p_dir->b_insert_back = false;
136
137
            return &p_dir->dd_dir;
        }
138

139
        return _wreaddir( p_dir->p_real_dir );
140
141
142
143
    }

    /* Drive letters mode */
    i_drives = p_dir->i_drives;
geal's avatar
geal committed
144
145
146
147
#ifdef UNDER_CE
    swprintf( p_dir->dd_dir.d_name, L"\\");
    p_dir->dd_dir.d_namlen = wcslen(p_dir->dd_dir.d_name);
#else
ivoire's avatar
ivoire committed
148
    unsigned int i;
149
150
151
152
153
154
155
156
157
    if ( !i_drives )
        return NULL; /* end */

    for ( i = 0; i < sizeof(DWORD)*8; i++, i_drives >>= 1 )
        if ( i_drives & 1 ) break;

    if ( i >= 26 )
        return NULL; /* this should not happen */

158
159
    swprintf( p_dir->dd_dir.d_name, L"%c:\\", 'A' + i );
    p_dir->dd_dir.d_namlen = wcslen(p_dir->dd_dir.d_name);
160
    p_dir->i_drives &= ~(1UL << i);
geal's avatar
geal committed
161
#endif
162
163
164
    return &p_dir->dd_dir;
}

165
void vlc_rewinddir( void *_p_dir )
166
167
168
169
{
    vlc_DIR *p_dir = (vlc_DIR *)_p_dir;

    if ( p_dir->p_real_dir != NULL )
170
        _wrewinddir( p_dir->p_real_dir );
171
}
172
#endif
173

174
175
/* This one is in the libvlccore exported symbol list */
int vlc_wclosedir( void *_p_dir )
176
{
geal's avatar
geal committed
177
#if defined(WIN32)
178
    vlc_DIR *p_dir = (vlc_DIR *)_p_dir;
179
    int i_ret = 0;
180
181

    if ( p_dir->p_real_dir != NULL )
182
183
184
185
186
187
        i_ret = _wclosedir( p_dir->p_real_dir );

    free( p_dir );
    return i_ret;
#else
    return closedir( _p_dir );
188
#endif
189
}
190

191
192
193
194
#ifdef ENABLE_NLS
# include <libintl.h>
#endif

195
196
197
198
199
/**
 * In-tree plugins share their gettext domain with LibVLC.
 */
char *vlc_gettext( const char *msgid )
{
200
#ifdef ENABLE_NLS
201
    return dgettext( PACKAGE_NAME, msgid );
202
203
204
#else
    return (char *)msgid;
#endif
205
206
}

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
/*****************************************************************************
 * Local conversion routine from ISO_6937 to UTF-8 charset. Support for this
 * is still missing in libiconv, hence multiple operating systems lack it.
 * The conversion table adds Euro sign (0xA4) as per ETSI EN 300 468 Annex A
 *****************************************************************************/
#ifndef __linux__
static const uint16_t to_ucs4[128] =
{
  /* 0x80 */ 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087,
  /* 0x88 */ 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f,
  /* 0x90 */ 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097,
  /* 0x98 */ 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f,
  /* 0xa0 */ 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x20ac, 0x00a5, 0x0000, 0x00a7,
  /* 0xa8 */ 0x00a4, 0x2018, 0x201c, 0x00ab, 0x2190, 0x2191, 0x2192, 0x2193,
  /* 0xb0 */ 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00d7, 0x00b5, 0x00b6, 0x00b7,
  /* 0xb8 */ 0x00f7, 0x2019, 0x201d, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf,
  /* 0xc0 */ 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
  /* 0xc8 */ 0xffff, 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff,
  /* 0xd0 */ 0x2014, 0x00b9, 0x00ae, 0x00a9, 0x2122, 0x266a, 0x00ac, 0x00a6,
  /* 0xd8 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x215b, 0x215c, 0x215d, 0x215e,
  /* 0xe0 */ 0x2126, 0x00c6, 0x00d0, 0x00aa, 0x0126, 0x0000, 0x0132, 0x013f,
  /* 0xe8 */ 0x0141, 0x00d8, 0x0152, 0x00ba, 0x00de, 0x0166, 0x014a, 0x0149,
  /* 0xf0 */ 0x0138, 0x00e6, 0x0111, 0x00f0, 0x0127, 0x0131, 0x0133, 0x0140,
  /* 0xf8 */ 0x0142, 0x00f8, 0x0153, 0x00df, 0x00fe, 0x0167, 0x014b, 0x00ad
};

/* The outer array range runs from 0xc1 to 0xcf, the inner range from 0x40
   to 0x7f.  */
static const uint16_t to_ucs4_comb[15][64] =
{
  /* 0xc1 */
  {
    /* 0x40 */ 0x0000, 0x00c0, 0x0000, 0x0000, 0x0000, 0x00c8, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x00cc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d2,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d9, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x00e0, 0x0000, 0x0000, 0x0000, 0x00e8, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x00ec, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f2,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f9, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc2 */
  {
    /* 0x40 */ 0x0000, 0x00c1, 0x0000, 0x0106, 0x0000, 0x00c9, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x00cd, 0x0000, 0x0000, 0x0139, 0x0000, 0x0143, 0x00d3,
    /* 0x50 */ 0x0000, 0x0000, 0x0154, 0x015a, 0x0000, 0x00da, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x00dd, 0x0179, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x00e1, 0x0000, 0x0107, 0x0000, 0x00e9, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x00ed, 0x0000, 0x0000, 0x013a, 0x0000, 0x0144, 0x00f3,
    /* 0x70 */ 0x0000, 0x0000, 0x0155, 0x015b, 0x0000, 0x00fa, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x00fd, 0x017a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc3 */
  {
    /* 0x40 */ 0x0000, 0x00c2, 0x0000, 0x0108, 0x0000, 0x00ca, 0x0000, 0x011c,
    /* 0x48 */ 0x0124, 0x00ce, 0x0134, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d4,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x015c, 0x0000, 0x00db, 0x0000, 0x0174,
    /* 0x58 */ 0x0000, 0x0176, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x00e2, 0x0000, 0x0109, 0x0000, 0x00ea, 0x0000, 0x011d,
    /* 0x68 */ 0x0125, 0x00ee, 0x0135, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f4,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x015d, 0x0000, 0x00fb, 0x0000, 0x0175,
    /* 0x78 */ 0x0000, 0x0177, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc4 */
  {
    /* 0x40 */ 0x0000, 0x00c3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x0128, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d1, 0x00d5,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0168, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x00e3, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x0129, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f1, 0x00f5,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0169, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc5 */
  {
    /* 0x40 */ 0x0000, 0x0100, 0x0000, 0x0000, 0x0000, 0x0112, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x012a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014c,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016a, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0101, 0x0000, 0x0000, 0x0000, 0x0113, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x012b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x014d,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016b, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc6 */
  {
    /* 0x40 */ 0x0000, 0x0102, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x011e,
    /* 0x48 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016c, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0103, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x011f,
    /* 0x68 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016d, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc7 */
  {
    /* 0x40 */ 0x0000, 0x0000, 0x0000, 0x010a, 0x0000, 0x0116, 0x0000, 0x0120,
    /* 0x48 */ 0x0000, 0x0130, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x017b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0000, 0x0000, 0x010b, 0x0000, 0x0117, 0x0000, 0x0121,
    /* 0x68 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x017c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc8 */
  {
    /* 0x40 */ 0x0000, 0x00c4, 0x0000, 0x0000, 0x0000, 0x00cb, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x00cf, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00d6,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00dc, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0178, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x00e4, 0x0000, 0x0000, 0x0000, 0x00eb, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x00ef, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00f6,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x00fc, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x00ff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xc9 */
  {
    0x0000,
  },
  /* 0xca */
  {
    /* 0x40 */ 0x0000, 0x00c5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016e, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x00e5, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x016f, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xcb */
  {
    /* 0x40 */ 0x0000, 0x0000, 0x0000, 0x00c7, 0x0000, 0x0000, 0x0000, 0x0122,
    /* 0x48 */ 0x0000, 0x0000, 0x0000, 0x0136, 0x013b, 0x0000, 0x0145, 0x0000,
    /* 0x50 */ 0x0000, 0x0000, 0x0156, 0x015e, 0x0162, 0x0000, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0000, 0x0000, 0x00e7, 0x0000, 0x0000, 0x0000, 0x0123,
    /* 0x68 */ 0x0000, 0x0000, 0x0000, 0x0137, 0x013c, 0x0000, 0x0146, 0x0000,
    /* 0x70 */ 0x0000, 0x0000, 0x0157, 0x015f, 0x0163, 0x0000, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xcc */
  {
    0x0000,
  },
  /* 0xcd */
  {
    /* 0x40 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0150,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0170, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0151,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0171, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xce */
  {
    /* 0x40 */ 0x0000, 0x0104, 0x0000, 0x0000, 0x0000, 0x0118, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x012e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x50 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0172, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0105, 0x0000, 0x0000, 0x0000, 0x0119, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x012f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x70 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0173, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  },
  /* 0xcf */
  {
    /* 0x40 */ 0x0000, 0x0000, 0x0000, 0x010c, 0x010e, 0x011a, 0x0000, 0x0000,
    /* 0x48 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x013d, 0x0000, 0x0147, 0x0000,
    /* 0x50 */ 0x0000, 0x0000, 0x0158, 0x0160, 0x0164, 0x0000, 0x0000, 0x0000,
    /* 0x58 */ 0x0000, 0x0000, 0x017d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
    /* 0x60 */ 0x0000, 0x0000, 0x0000, 0x010d, 0x010f, 0x011b, 0x0000, 0x0000,
    /* 0x68 */ 0x0000, 0x0000, 0x0000, 0x0000, 0x013e, 0x0000, 0x0148, 0x0000,
    /* 0x70 */ 0x0000, 0x0000, 0x0159, 0x0161, 0x0165, 0x0000, 0x0000, 0x0000,
    /* 0x78 */ 0x0000, 0x0000, 0x017e, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
  }
};

static size_t ISO6937toUTF8( const unsigned char **inbuf, size_t *inbytesleft,
                             unsigned char **outbuf, size_t *outbytesleft )


{
    if( !inbuf || !(*inbuf) )
        return (size_t)(0);    /* Reset state requested */

    const unsigned char *iptr = *inbuf;
    const unsigned char *iend = iptr + *inbytesleft;
    unsigned char *optr = *outbuf;
    unsigned char *oend = optr + *outbytesleft;
    uint16_t ch;
    int err = 0;

    while ( iptr < iend )
    {
        if( *iptr < 0x80 )
        {
            if( optr >= oend )
            {
                err = E2BIG;
                break;    /* No space in outbuf */
            }
            *optr++ = *iptr++;
            continue;
        }


        if ( optr + 2 >= oend )
        {
            err = E2BIG;
            break;        /* No space in outbuf for multibyte char */
        }

        ch = to_ucs4[*iptr - 0x80];

        if( ch == 0xffff )
        {
            /* Composed character */
            if ( iptr + 1 >= iend )
            {
                err = EINVAL;
                break;    /* No next character */
            }
            if ( iptr[1] < 0x40 || iptr[1] >= 0x80 ||
                 !(ch = to_ucs4_comb[iptr[0] - 0xc1][iptr[1] - 0x40]) )
            {
                err = EILSEQ;
                break;   /* Illegal combination */
            }
            iptr += 2;

        }
        else
        {
            if ( !ch )
            {
                err = EILSEQ;
                break;
            }
            iptr++;
        }

        if ( ch < 0x800 )
        {
            optr[1] = 0x80 | (ch & 0x3f);
            optr[0] = 0xc0 | (ch >> 6);
            optr +=2;
        }
        else
        {
            optr[2] = 0x80 | (ch & 0x3f);
            ch >>= 6;
            optr[1] = 0x80 | (ch & 0x3f);
            optr[0] = 0xe0 | (ch >> 6);
            optr += 3;
        }

    }
    *inbuf = iptr;
    *outbuf = optr;
    *inbytesleft = iend - iptr;
    *outbytesleft = oend - optr;

    if( err )
    {
        errno = err;
        return (size_t)(-1);
    }

    return (size_t)(0);

}
#endif

486
487
488
489
490
/*****************************************************************************
 * iconv wrapper
 *****************************************************************************/
vlc_iconv_t vlc_iconv_open( const char *tocode, const char *fromcode )
{
491
492
493
494
#ifndef __linux__
    if( !strcasecmp(tocode, "UTF-8") && !strcasecmp(fromcode, "ISO_6937") )
        return (vlc_iconv_t)(-2);
#endif
495
496
497
#if defined(HAVE_ICONV)
    return iconv_open( tocode, fromcode );
#else
498
    return (vlc_iconv_t)(-1);
499
500
501
#endif
}

502
size_t vlc_iconv( vlc_iconv_t cd, const char **inbuf, size_t *inbytesleft,
503
504
                  char **outbuf, size_t *outbytesleft )
{
505
506
507
508
509
#ifndef __linux__
    if ( cd == (vlc_iconv_t)(-2) )
        return ISO6937toUTF8( (const unsigned char **)inbuf, inbytesleft,
                              (unsigned char **)outbuf, outbytesleft );
#endif
510
#if defined(HAVE_ICONV)
511
512
    return iconv( cd, (ICONV_CONST char **)inbuf, inbytesleft,
                  outbuf, outbytesleft );
513
#else
514
    abort ();
515
516
517
518
519
#endif
}

int vlc_iconv_close( vlc_iconv_t cd )
{
520
521
522
523
#ifndef __linux__
    if ( cd == (vlc_iconv_t)(-2) )
        return 0;
#endif
524
525
526
#if defined(HAVE_ICONV)
    return iconv_close( cd );
#else
527
    abort ();
528
529
#endif
}
530
531
532
533
534

/*****************************************************************************
 * reduce a fraction
 *   (adapted from libavcodec, author Michael Niedermayer <michaelni@gmx.at>)
 *****************************************************************************/
535
bool vlc_ureduce( unsigned *pi_dst_nom, unsigned *pi_dst_den,
536
                        uint64_t i_nom, uint64_t i_den, uint64_t i_max )
537
{
538
    bool b_exact = 1;
Rémi Denis-Courmont's avatar
fix fix    
Rémi Denis-Courmont committed
539
    uint64_t i_gcd;
540
541
542

    if( i_den == 0 )
    {
543
544
        *pi_dst_nom = 0;
        *pi_dst_den = 1;
545
546
547
548
549
550
551
        return 1;
    }

    i_gcd = GCD( i_nom, i_den );
    i_nom /= i_gcd;
    i_den /= i_gcd;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
552
    if( i_max == 0 ) i_max = INT64_C(0xFFFFFFFF);
553

554
555
    if( i_nom > i_max || i_den > i_max )
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
556
        uint64_t i_a0_num = 0, i_a0_den = 1, i_a1_num = 1, i_a1_den = 0;
557
558
559
560
        b_exact = 0;

        for( ; ; )
        {
Rémi Denis-Courmont's avatar
fix fix    
Rémi Denis-Courmont committed
561
562
563
            uint64_t i_x = i_nom / i_den;
            uint64_t i_a2n = i_x * i_a1_num + i_a0_num;
            uint64_t i_a2d = i_x * i_a1_den + i_a0_den;
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582

            if( i_a2n > i_max || i_a2d > i_max ) break;

            i_nom %= i_den;

            i_a0_num = i_a1_num; i_a0_den = i_a1_den;
            i_a1_num = i_a2n; i_a1_den = i_a2d;
            if( i_nom == 0 ) break;
            i_x = i_nom; i_nom = i_den; i_den = i_x;
        }
        i_nom = i_a1_num;
        i_den = i_a1_den;
    }

    *pi_dst_nom = i_nom;
    *pi_dst_den = i_den;

    return b_exact;
}
583

584
#undef vlc_execve
585
586
587
588
/*************************************************************************
 * vlc_execve: Execute an external program with a given environment,
 * wait until it finishes and return its standard output
 *************************************************************************/
589
590
591
592
int vlc_execve( vlc_object_t *p_object, int i_argc, char *const *ppsz_argv,
                char *const *ppsz_env, const char *psz_cwd,
                const char *p_in, size_t i_in,
                char **pp_data, size_t *pi_data )
593
{
594
    (void)i_argc; // <-- hmph
595
#ifdef HAVE_FORK
596
597
# define BUFSIZE 1024
    int fds[2], i_status;
598

599
    if (socketpair (PF_LOCAL, SOCK_STREAM, 0, fds))
600
601
        return -1;

602
603
604
    pid_t pid = -1;
    if ((fds[0] > 2) && (fds[1] > 2))
        pid = fork ();
605

606
607
608
    switch (pid)
    {
        case -1:
609
            msg_Err (p_object, "unable to fork (%m)");
610
611
612
            close (fds[0]);
            close (fds[1]);
            return -1;
613

614
        case 0:
615
616
617
618
619
        {
            sigset_t set;
            sigemptyset (&set);
            pthread_sigmask (SIG_SETMASK, &set, NULL);

620
621
622
            /* NOTE:
             * Like it or not, close can fail (and not only with EBADF)
             */
623
            if ((dup2 (fds[1], 0) == 0) && (dup2 (fds[1], 1) == 1)
624
625
             && ((psz_cwd == NULL) || (chdir (psz_cwd) == 0)))
                execve (ppsz_argv[0], ppsz_argv, ppsz_env);
626

627
            _exit (EXIT_FAILURE);
628
        }
629
630
    }

631
    close (fds[1]);
632
633

    *pi_data = 0;
634
635
    if (*pp_data)
        free (*pp_data);
636
    *pp_data = NULL;
637

638
639
640
641
    if (i_in == 0)
        shutdown (fds[0], SHUT_WR);

    while (!p_object->b_die)
642
    {
643
644
645
646
647
648
649
650
651
652
653
654
        struct pollfd ufd[1];
        memset (ufd, 0, sizeof (ufd));
        ufd[0].fd = fds[0];
        ufd[0].events = POLLIN;

        if (i_in > 0)
            ufd[0].events |= POLLOUT;

        if (poll (ufd, 1, 10) <= 0)
            continue;

        if (ufd[0].revents & ~POLLOUT)
655
        {
656
657
658
659
660
661
662
663
            char *ptr = realloc (*pp_data, *pi_data + BUFSIZE + 1);
            if (ptr == NULL)
                break; /* safely abort */

            *pp_data = ptr;

            ssize_t val = read (fds[0], ptr + *pi_data, BUFSIZE);
            switch (val)
664
            {
665
666
667
668
669
670
671
                case -1:
                case 0:
                    shutdown (fds[0], SHUT_RD);
                    break;

                default:
                    *pi_data += val;
672
673
674
            }
        }

675
        if (ufd[0].revents & POLLOUT)
676
        {
677
678
            ssize_t val = write (fds[0], p_in, i_in);
            switch (val)
679
            {
680
681
682
683
684
685
686
687
688
                case -1:
                case 0:
                    i_in = 0;
                    shutdown (fds[0], SHUT_WR);
                    break;

                default:
                    i_in -= val;
                    p_in += val;
689
690
            }
        }
691
    }
692

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
    close (fds[0]);

    while (waitpid (pid, &i_status, 0) == -1);

    if (WIFEXITED (i_status))
    {
        i_status = WEXITSTATUS (i_status);
        if (i_status)
            msg_Warn (p_object,  "child %s (PID %d) exited with error code %d",
                      ppsz_argv[0], (int)pid, i_status);
    }
    else
    if (WIFSIGNALED (i_status)) // <-- this should be redumdant a check
    {
        i_status = WTERMSIG (i_status);
        msg_Warn (p_object, "child %s (PID %d) exited on signal %d (%s)",
                  ppsz_argv[0], (int)pid, i_status, strsignal (i_status));
710
711
    }

712
#elif defined( WIN32 ) && !defined( UNDER_CE )
zorglub's avatar
zorglub committed
713
714
    SECURITY_ATTRIBUTES saAttr;
    PROCESS_INFORMATION piProcInfo;
715
    STARTUPINFO siStartInfo;
zorglub's avatar
zorglub committed
716
    BOOL bFuncRetn = FALSE;
717
718
    HANDLE hChildStdinRd, hChildStdinWr, hChildStdoutRd, hChildStdoutWr;
    DWORD i_status;
719
    char *psz_cmd = NULL, *p_env = NULL, *p = NULL;
720
721
722
723
    char **ppsz_parser;
    int i_size;

    /* Set the bInheritHandle flag so pipe handles are inherited. */
zorglub's avatar
zorglub committed
724
725
726
    saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
    saAttr.bInheritHandle = TRUE;
    saAttr.lpSecurityDescriptor = NULL;
727
728

    /* Create a pipe for the child process's STDOUT. */
zorglub's avatar
zorglub committed
729
    if ( !CreatePipe( &hChildStdoutRd, &hChildStdoutWr, &saAttr, 0 ) )
730
    {
zorglub's avatar
zorglub committed
731
        msg_Err( p_object, "stdout pipe creation failed" );
732
733
734
735
736
737
738
        return -1;
    }

    /* Ensure the read handle to the pipe for STDOUT is not inherited. */
    SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0 );

    /* Create a pipe for the child process's STDIN. */
zorglub's avatar
zorglub committed
739
    if ( !CreatePipe( &hChildStdinRd, &hChildStdinWr, &saAttr, 0 ) )
740
    {
zorglub's avatar
zorglub committed
741
        msg_Err( p_object, "stdin pipe creation failed" );
742
743
744
745
746
747
748
749
        return -1;
    }

    /* Ensure the write handle to the pipe for STDIN is not inherited. */
    SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0 );

    /* Set up members of the PROCESS_INFORMATION structure. */
    ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
zorglub's avatar
zorglub committed
750

751
752
    /* Set up members of the STARTUPINFO structure. */
    ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
zorglub's avatar
zorglub committed
753
    siStartInfo.cb = sizeof(STARTUPINFO);
754
755
756
    siStartInfo.hStdError = hChildStdoutWr;
    siStartInfo.hStdOutput = hChildStdoutWr;
    siStartInfo.hStdInput = hChildStdinRd;
757
758
    siStartInfo.wShowWindow = SW_HIDE;
    siStartInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
759
760
761

    /* Set up the command line. */
    psz_cmd = malloc(32768);
762
763
    if( !psz_cmd )
        return -1;
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
    psz_cmd[0] = '\0';
    i_size = 32768;
    ppsz_parser = &ppsz_argv[0];
    while ( ppsz_parser[0] != NULL && i_size > 0 )
    {
        /* Protect the last argument with quotes ; the other arguments
         * are supposed to be already protected because they have been
         * passed as a command-line option. */
        if ( ppsz_parser[1] == NULL )
        {
            strncat( psz_cmd, "\"", i_size );
            i_size--;
        }
        strncat( psz_cmd, *ppsz_parser, i_size );
        i_size -= strlen( *ppsz_parser );
        if ( ppsz_parser[1] == NULL )
        {
            strncat( psz_cmd, "\"", i_size );
            i_size--;
        }
        strncat( psz_cmd, " ", i_size );
        i_size--;
        ppsz_parser++;
    }

    /* Set up the environment. */
    p = p_env = malloc(32768);
791
792
793
794
795
796
    if( !p )
    {
        free( psz_cmd );
        return -1;
    }

797
798
799
800
801
802
803
804
805
806
807
    i_size = 32768;
    ppsz_parser = &ppsz_env[0];
    while ( *ppsz_parser != NULL && i_size > 0 )
    {
        memcpy( p, *ppsz_parser,
                __MIN((int)(strlen(*ppsz_parser) + 1), i_size) );
        p += strlen(*ppsz_parser) + 1;
        i_size -= strlen(*ppsz_parser) + 1;
        ppsz_parser++;
    }
    *p = '\0';
zorglub's avatar
zorglub committed
808

809
810
    /* Create the child process. */
    bFuncRetn = CreateProcess( NULL,
zorglub's avatar
zorglub committed
811
812
813
814
815
          psz_cmd,       // command line
          NULL,          // process security attributes
          NULL,          // primary thread security attributes
          TRUE,          // handles are inherited
          0,             // creation flags
816
817
          p_env,
          psz_cwd,
zorglub's avatar
zorglub committed
818
819
          &siStartInfo,  // STARTUPINFO pointer
          &piProcInfo ); // receives PROCESS_INFORMATION
820
821
822

    free( psz_cmd );
    free( p_env );
zorglub's avatar
zorglub committed
823
824

    if ( bFuncRetn == 0 )
825
    {
zorglub's avatar
zorglub committed
826
        msg_Err( p_object, "child creation failed" );
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
        return -1;
    }

    /* Read from a file and write its contents to a pipe. */
    while ( i_in > 0 && !p_object->b_die )
    {
        DWORD i_written;
        if ( !WriteFile( hChildStdinWr, p_in, i_in, &i_written, NULL ) )
            break;
        i_in -= i_written;
        p_in += i_written;
    }

    /* Close the pipe handle so the child process stops reading. */
    CloseHandle(hChildStdinWr);

    /* Close the write end of the pipe before reading from the
     * read end of the pipe. */
    CloseHandle(hChildStdoutWr);
zorglub's avatar
zorglub committed
846

847
848
    /* Read output from the child process. */
    *pi_data = 0;
849
850
851
    if( *pp_data )
        free( pp_data );
    *pp_data = NULL;
852
853
854
855
856
    *pp_data = malloc( 1025 );  /* +1 for \0 */

    while ( !p_object->b_die )
    {
        DWORD i_read;
zorglub's avatar
zorglub committed
857
        if ( !ReadFile( hChildStdoutRd, &(*pp_data)[*pi_data], 1024, &i_read,
858
859
                        NULL )
              || i_read == 0 )
zorglub's avatar
zorglub committed
860
            break;
861
        *pi_data += i_read;
862
        *pp_data = xrealloc( *pp_data, *pi_data + 1025 );
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
    }

    while ( !p_object->b_die
             && !GetExitCodeProcess( piProcInfo.hProcess, &i_status )
             && i_status != STILL_ACTIVE )
        msleep( 10000 );

    CloseHandle(piProcInfo.hProcess);
    CloseHandle(piProcInfo.hThread);

    if ( i_status )
        msg_Warn( p_object,
                  "child %s returned with error code %ld",
                  ppsz_argv[0], i_status );

878
#else
879
    msg_Err( p_object, "vlc_execve called but no implementation is available" );
880
881
882
883
    return -1;

#endif

884
885
886
    if (*pp_data == NULL)
        return -1;

887
888
889
    (*pp_data)[*pi_data] = '\0';
    return 0;
}