xref: /third_party/lame/frontend/main.c (revision 159b3361)
1/*
2 *      Command line frontend program
3 *
4 *      Copyright (c) 1999 Mark Taylor
5 *                    2000 Takehiro TOMINAGA
6 *                    2010-2012 Robert Hegemann
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the
20 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24/* $Id$ */
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <assert.h>
31#include <stdio.h>
32
33#ifdef STDC_HEADERS
34# include <stdlib.h>
35# include <string.h>
36#else
37# ifndef HAVE_STRCHR
38#  define strchr index
39#  define strrchr rindex
40# endif
41char   *strchr(), *strrchr();
42# ifndef HAVE_MEMCPY
43#  define memcpy(d, s, n) bcopy ((s), (d), (n))
44#  define memmove(d, s, n) bcopy ((s), (d), (n))
45# endif
46#endif
47
48#ifdef HAVE_FCNTL_H
49# include <fcntl.h>
50#endif
51
52#ifdef __sun__
53/* woraround for SunOS 4.x, it has SEEK_* defined here */
54#include <unistd.h>
55#endif
56
57#ifdef __OS2__
58#define INCL_DOS
59#include <os2.h>
60#define PRTYC_IDLE 1
61#define PRTYC_REGULAR 2
62#define PRTYD_MINIMUM -31
63#define PRTYD_MAXIMUM 31
64#endif
65
66#if defined(_WIN32)
67# include <windows.h>
68#endif
69
70#ifdef __EMX__
71# include <float.h>
72#endif
73
74
75/*
76 main.c is example code for how to use libmp3lame.a.  To use this library,
77 you only need the library and lame.h.  All other .h files are private
78 to the library.
79*/
80#include "lame.h"
81
82#include "console.h"
83#include "main.h"
84
85/* PLL 14/04/2000 */
86#if macintosh
87#include <console.h>
88#endif
89
90#ifdef WITH_DMALLOC
91#include <dmalloc.h>
92#endif
93
94
95static int c_main(int argc, char *argv[]);
96extern int lame_main(lame_t gf, int argc, char *argv[]);
97
98
99/************************************************************************
100*
101* main
102*
103* PURPOSE:  MPEG-1,2 Layer III encoder with GPSYCHO
104* psychoacoustic model.
105*
106************************************************************************/
107
108
109#if defined( _WIN32 ) && !defined(__MINGW32__)
110static void
111set_process_affinity()
112{
113#if 0
114    /* rh 061207
115       the following fix seems to be a workaround for a problem in the
116       parent process calling LAME. It would be better to fix the broken
117       application => code disabled.
118     */
119#if defined(_WIN32)
120    /* set affinity back to all CPUs.  Fix for EAC/lame on SMP systems from
121       "Todd Richmond" <todd.richmond@openwave.com> */
122    typedef BOOL(WINAPI * SPAMFunc) (HANDLE, DWORD_PTR);
123    SPAMFunc func;
124    SYSTEM_INFO si;
125
126    if ((func = (SPAMFunc) GetProcAddress(GetModuleHandleW(L"KERNEL32.DLL"),
127                                          "SetProcessAffinityMask")) != NULL) {
128        GetSystemInfo(&si);
129        func(GetCurrentProcess(), si.dwActiveProcessorMask);
130    }
131#endif
132#endif
133}
134#endif
135
136#if defined(WIN32)
137
138/**
139 *  Long Filename support for the WIN32 platform
140 *
141 */
142
143void
144dosToLongFileName(char *filename)
145{
146    const size_t MSIZE = PATH_MAX + 1 - 4; /*  we wanna add ".mp3" later */
147    WIN32_FIND_DATAA lpFindFileData;
148    HANDLE  h = FindFirstFileA(filename, &lpFindFileData);
149    if (h != INVALID_HANDLE_VALUE) {
150        size_t  a;
151        char   *q, *p;
152        FindClose(h);
153        for (a = 0; a < MSIZE; a++) {
154            if ('\0' == lpFindFileData.cFileName[a])
155                break;
156        }
157        if (a >= MSIZE || a == 0)
158            return;
159        q = strrchr(filename, '\\');
160        p = strrchr(filename, '/');
161        if (p - q > 0)
162            q = p;
163        if (q == NULL)
164            q = strrchr(filename, ':');
165        if (q == NULL)
166            strncpy(filename, lpFindFileData.cFileName, a);
167        else {
168            a += q - filename + 1;
169            if (a >= MSIZE)
170                return;
171            strncpy(++q, lpFindFileData.cFileName, MSIZE - a);
172        }
173    }
174}
175
176BOOL
177SetPriorityClassMacro(DWORD p)
178{
179    HANDLE  op = GetCurrentProcess();
180    return SetPriorityClass(op, p);
181}
182
183void
184setProcessPriority(int priority)
185{
186    switch (priority) {
187    case 0:
188    case 1:
189        SetPriorityClassMacro(IDLE_PRIORITY_CLASS);
190        console_printf("==> Priority set to Low.\n");
191        break;
192    default:
193    case 2:
194        SetPriorityClassMacro(NORMAL_PRIORITY_CLASS);
195        console_printf("==> Priority set to Normal.\n");
196        break;
197    case 3:
198    case 4:
199        SetPriorityClassMacro(HIGH_PRIORITY_CLASS);
200        console_printf("==> Priority set to High.\n");
201        break;
202    }
203}
204#endif
205
206
207#if defined(__OS2__)
208/* OS/2 priority functions */
209void
210setProcessPriority(int priority)
211{
212    int     rc;
213
214    switch (priority) {
215
216    case 0:
217        rc = DosSetPriority(0, /* Scope: only one process */
218                            PRTYC_IDLE, /* select priority class (idle, regular, etc) */
219                            0, /* set delta */
220                            0); /* Assume current process */
221        console_printf("==> Priority set to 0 (Low priority).\n");
222        break;
223
224    case 1:
225        rc = DosSetPriority(0, /* Scope: only one process */
226                            PRTYC_IDLE, /* select priority class (idle, regular, etc) */
227                            PRTYD_MAXIMUM, /* set delta */
228                            0); /* Assume current process */
229        console_printf("==> Priority set to 1 (Medium priority).\n");
230        break;
231
232    case 2:
233        rc = DosSetPriority(0, /* Scope: only one process */
234                            PRTYC_REGULAR, /* select priority class (idle, regular, etc) */
235                            PRTYD_MINIMUM, /* set delta */
236                            0); /* Assume current process */
237        console_printf("==> Priority set to 2 (Regular priority).\n");
238        break;
239
240    case 3:
241        rc = DosSetPriority(0, /* Scope: only one process */
242                            PRTYC_REGULAR, /* select priority class (idle, regular, etc) */
243                            0, /* set delta */
244                            0); /* Assume current process */
245        console_printf("==> Priority set to 3 (High priority).\n");
246        break;
247
248    case 4:
249        rc = DosSetPriority(0, /* Scope: only one process */
250                            PRTYC_REGULAR, /* select priority class (idle, regular, etc) */
251                            PRTYD_MAXIMUM, /* set delta */
252                            0); /* Assume current process */
253        console_printf("==> Priority set to 4 (Maximum priority). I hope you enjoy it :)\n");
254        break;
255
256    default:
257        console_printf("==> Invalid priority specified! Assuming idle priority.\n");
258    }
259}
260#endif
261
262
263/***********************************************************************
264*
265*  Message Output
266*
267***********************************************************************/
268
269
270#if defined( _WIN32 ) && !defined(__MINGW32__)
271/* Idea for unicode support in LAME, work in progress
272 * - map UTF-16 to UTF-8
273 * - advantage, the rest can be kept unchanged (mostly)
274 * - make sure, fprintf on console is in correct code page
275 *   + normal text in source code is in ASCII anyway
276 *   + ID3 tags and filenames coming from command line need attention
277 * - call wfopen with UTF-16 names where needed
278 *
279 * why not wchar_t all the way?
280 * well, that seems to be a big mess and not portable at all
281 */
282#ifndef NDEBUG
283#define _CRTDBG_MAP_ALLOC
284#include <stdlib.h>
285#include <crtdbg.h>
286#endif
287#include <wchar.h>
288#include <mbstring.h>
289
290static wchar_t *mbsToUnicode(const char *mbstr, int code_page)
291{
292  int n = MultiByteToWideChar(code_page, 0, mbstr, -1, NULL, 0);
293  wchar_t* wstr = malloc( n*sizeof(wstr[0]) );
294  if ( wstr !=0 ) {
295    n = MultiByteToWideChar(code_page, 0, mbstr, -1, wstr, n);
296    if ( n==0 ) {
297      free( wstr );
298      wstr = 0;
299    }
300  }
301  return wstr;
302}
303
304static char *unicodeToMbs(const wchar_t *wstr, int code_page)
305{
306  int n = 1+WideCharToMultiByte(code_page, 0, wstr, -1, 0, 0, 0, 0);
307  char* mbstr = malloc( n*sizeof(mbstr[0]) );
308  if ( mbstr !=0 ) {
309    n = WideCharToMultiByte(code_page, 0, wstr, -1, mbstr, n, 0, 0);
310    if( n == 0 ){
311      free( mbstr );
312      mbstr = 0;
313    }
314  }
315  return mbstr;
316}
317
318char* mbsToMbs(const char* str, int cp_from, int cp_to)
319{
320  wchar_t* wstr = mbsToUnicode(str, cp_from);
321  if ( wstr != 0 ) {
322    char* local8bit = unicodeToMbs(wstr, cp_to);
323    free( wstr );
324    return local8bit;
325  }
326  return 0;
327}
328
329enum { cp_utf8, cp_console, cp_actual };
330
331wchar_t *utf8ToUnicode(const char *mbstr)
332{
333  return mbsToUnicode(mbstr, CP_UTF8);
334}
335
336char *unicodeToUtf8(const wchar_t *wstr)
337{
338  return unicodeToMbs(wstr, CP_UTF8);
339}
340
341char* utf8ToLocal8Bit(const char* str)
342{
343  return mbsToMbs(str, CP_UTF8, CP_ACP);
344}
345
346char* utf8ToConsole8Bit(const char* str)
347{
348  return mbsToMbs(str, CP_UTF8, GetConsoleOutputCP());
349}
350
351char* local8BitToUtf8(const char* str)
352{
353  return mbsToMbs(str, CP_ACP, CP_UTF8);
354}
355
356char* console8BitToUtf8(const char* str)
357{
358  return mbsToMbs(str, GetConsoleOutputCP(), CP_UTF8);
359}
360
361char* utf8ToLatin1(char const* str)
362{
363  return mbsToMbs(str, CP_UTF8, 28591); /* Latin-1 is code page 28591 */
364}
365
366unsigned short* utf8ToUtf16(char const* mbstr) /* additional Byte-Order-Marker */
367{
368  int n = MultiByteToWideChar(CP_UTF8, 0, mbstr, -1, NULL, 0);
369  wchar_t* wstr = malloc( (n+1)*sizeof(wstr[0]) );
370  if ( wstr !=0 ) {
371    wstr[0] = 0xfeff; /* BOM */
372    n = MultiByteToWideChar(CP_UTF8, 0, mbstr, -1, wstr+1, n);
373    if ( n==0 ) {
374      free( wstr );
375      wstr = 0;
376    }
377  }
378  return wstr;
379}
380
381static
382void setDebugMode()
383{
384#ifndef NDEBUG
385    if ( IsDebuggerPresent() ) {
386        // Get current flag
387        int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
388        //tmpFlag |= _CRTDBG_DELAY_FREE_MEM_DF;
389        tmpFlag |= _CRTDBG_ALLOC_MEM_DF|_CRTDBG_LEAK_CHECK_DF;
390        // Set flag to the new value.
391        _CrtSetDbgFlag( tmpFlag );
392        _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
393        _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
394    }
395#endif
396}
397
398int wmain(int argc, wchar_t* argv[])
399{
400  char **utf8_argv;
401  int i, ret;
402  setDebugMode();
403  utf8_argv = calloc(argc, sizeof(char*));
404  for (i = 0; i < argc; ++i) {
405    utf8_argv[i] = unicodeToUtf8(argv[i]);
406  }
407  ret = c_main(argc, utf8_argv);
408  for (i = 0; i < argc; ++i) {
409    free( utf8_argv[i] );
410  }
411  free( utf8_argv );
412  return ret;
413}
414
415FILE* lame_fopen(char const* file, char const* mode)
416{
417    FILE* fh = 0;
418    wchar_t* wfile = utf8ToUnicode(file);
419    wchar_t* wmode = utf8ToUnicode(mode);
420    if (wfile != 0 && wmode != 0) {
421        fh = _wfopen(wfile, wmode);
422    }
423    else {
424        fh = fopen(file, mode);
425    }
426    free(wfile);
427    free(wmode);
428    return fh;
429}
430
431char* lame_getenv(char const* var)
432{
433    char* str = 0;
434    wchar_t* wvar = utf8ToUnicode(var);
435    if (wvar != 0) {
436        wchar_t* wstr = _wgetenv(wvar);
437        if (wstr != 0) {
438            str = unicodeToUtf8(wstr);
439        }
440    }
441    free(wvar);
442    return str;
443}
444
445#else
446
447FILE* lame_fopen(char const* file, char const* mode)
448{
449    return fopen(file, mode);
450}
451
452char* lame_getenv(char const* var)
453{
454    char* str = getenv(var);
455    if (str) {
456        return strdup(str);
457    }
458    return 0;
459}
460
461int main(int argc, char *argv[])
462{
463    return c_main(argc, argv);
464}
465
466#endif
467
468
469
470
471static int
472c_main(int argc, char *argv[])
473{
474    lame_t  gf;
475    int     ret;
476
477#if macintosh
478    argc = ccommand(&argv);
479#endif
480#ifdef __EMX__
481    /* This gives wildcard expansion on Non-POSIX shells with OS/2 */
482    _wildcard(&argc, &argv);
483
484    /* This prevents SIGFPE */
485    _control87(MCW_EM, MCW_EM);
486#endif
487#if defined( _WIN32 ) && !defined(__MINGW32__)
488    set_process_affinity();
489#endif
490
491    frontend_open_console();
492    gf = lame_init(); /* initialize libmp3lame */
493    if (NULL == gf) {
494        error_printf("fatal error during initialization\n");
495        ret = 1;
496    }
497    else {
498        ret = lame_main(gf, argc, argv);
499        lame_close(gf);
500    }
501    frontend_close_console();
502    return ret;
503}
504