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