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