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
41 char   *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 
95 static int c_main(int argc, char *argv[]);
96 extern 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__)
110 static void
set_process_affinitynull111 set_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 
143 void
dosToLongFileName(char *filename)144 dosToLongFileName(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 
176 BOOL
SetPriorityClassMacro(DWORD p)177 SetPriorityClassMacro(DWORD p)
178 {
179     HANDLE  op = GetCurrentProcess();
180     return SetPriorityClass(op, p);
181 }
182 
183 void
setProcessPriority(int priority)184 setProcessPriority(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 */
209 void
setProcessPriority(int priority)210 setProcessPriority(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 
mbsToUnicode(const char *mbstr, int code_page)290 static 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 
unicodeToMbs(const wchar_t *wstr, int code_page)304 static 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 
mbsToMbs(const char* str, int cp_from, int cp_to)318 char* 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 
329 enum { cp_utf8, cp_console, cp_actual };
330 
utf8ToUnicode(const char *mbstr)331 wchar_t *utf8ToUnicode(const char *mbstr)
332 {
333   return mbsToUnicode(mbstr, CP_UTF8);
334 }
335 
unicodeToUtf8(const wchar_t *wstr)336 char *unicodeToUtf8(const wchar_t *wstr)
337 {
338   return unicodeToMbs(wstr, CP_UTF8);
339 }
340 
utf8ToLocal8Bit(const char* str)341 char* utf8ToLocal8Bit(const char* str)
342 {
343   return mbsToMbs(str, CP_UTF8, CP_ACP);
344 }
345 
utf8ToConsole8Bit(const char* str)346 char* utf8ToConsole8Bit(const char* str)
347 {
348   return mbsToMbs(str, CP_UTF8, GetConsoleOutputCP());
349 }
350 
local8BitToUtf8(const char* str)351 char* local8BitToUtf8(const char* str)
352 {
353   return mbsToMbs(str, CP_ACP, CP_UTF8);
354 }
355 
console8BitToUtf8(const char* str)356 char* console8BitToUtf8(const char* str)
357 {
358   return mbsToMbs(str, GetConsoleOutputCP(), CP_UTF8);
359 }
360 
utf8ToLatin1(char const* str)361 char* utf8ToLatin1(char const* str)
362 {
363   return mbsToMbs(str, CP_UTF8, 28591); /* Latin-1 is code page 28591 */
364 }
365 
utf8ToUtf16(char const* mbstr)366 unsigned 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 
381 static
setDebugModenull382 void 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 
wmain(int argc, wchar_t* argv[])398 int 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 
lame_fopen(char const* file, char const* mode)415 FILE* 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 
lame_getenv(char const* var)431 char* 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 
lame_fopen(char const* file, char const* mode)447 FILE* lame_fopen(char const* file, char const* mode)
448 {
449     return fopen(file, mode);
450 }
451 
lame_getenv(char const* var)452 char* lame_getenv(char const* var)
453 {
454     char* str = getenv(var);
455     if (str) {
456         return strdup(str);
457     }
458     return 0;
459 }
460 
main(int argc, char *argv[])461 int main(int argc, char *argv[])
462 {
463     return c_main(argc, argv);
464 }
465 
466 #endif
467 
468 
469 
470 
471 static int
c_main(int argc, char *argv[])472 c_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