--- mplayer/unrarlib.c 2006-06-07 13:00:35.000000000 +0800 +++ mplayer.new/unrarlib.c 2006-06-21 17:51:44.000000000 +0800 @@ -365,6 +365,11 @@ struct Decode *Dec, int Size); static int my_stricomp(char *Str1,char *Str2); +static int libunrar_get(void** output, + unsigned long* size, + char* filename, + void* rarfile, + char* libpassword); /* ------------------------------------------------------------------------ */ @@ -395,6 +400,10 @@ #endif + /* call libunrar.so first, use original code as a fallback */ + if (libunrar_get(output, size, filename, rarfile, libpassword)) + return TRUE; + InitCRC(); /* init some vars */ if(ArgName) free(ArgName); @@ -2724,6 +2733,206 @@ **************************************************************************** **************************************************************************** ************************************************************************** */ +#include "mp_msg.h" +#ifndef _WIN32 +#include "config.h" +#define PASCAL +#define CALLBACK +#ifdef HAVE_LIBDL +#include +#else +#define dlopen(x, y) 0 +#define dlsym(x, y) 0 +#define dlclose(x) 0 +#endif /* HAVE_LIBDL */ +typedef void* HANDLE; +#define LIBUNRAR_NAME "libunrar.so" +#define PATHDELIMSTR "/" +#else /* _WIN32 */ +#define dlopen(x, y) LoadLibraryA(x) +#define dlsym GetProcAddress +#define dlclose FreeLibrary +#define LIBUNRAR_NAME "unrar.dll" +#define PATHDELIMSTR "\\" +#endif /* _WIN32 */ + +#define ERAR_EOPEN 15 +#define RAR_OM_EXTRACT 1 +#define RAR_SKIP 0 +#define RAR_TEST 1 + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD +}; + +static HANDLE PASCAL (*RAROpenArchive)(struct RAROpenArchiveData *ArchiveData); +static int PASCAL (*RARCloseArchive)(HANDLE hArcData); +static int PASCAL (*RARReadHeader)(HANDLE hArcData,struct RARHeaderData *HeaderData); +static int PASCAL (*RARProcessFile)(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +static void PASCAL (*RARSetPassword)(HANDLE hArcData,char *Password); +static void PASCAL (*RARSetCallback)( + HANDLE hArcData, + int PASCAL (*CallbackProc)(unsigned msg, long UserData, long P1, long P2), + long UserData + ); + +static int CALLBACK CallbackProc(unsigned msg, long UserData, long P1, long P2) +{ + char** p = (char**)UserData; + if (msg == UCM_PROCESSDATA) + { + memcpy(*p, (void*)P1, P2); + *p += P2; + } + return 0; +} +static void* init_func_pointers() +{ + void* libhdl = dlopen(LIBUNRAR_NAME, RTLD_LAZY); + if (!libhdl) + { +#ifndef _WIN32 +#ifdef HAVE_LIBDL + mp_msg(MSGT_VOBSUB, MSGL_DBG2, "UnRAR: Cannot load "LIBUNRAR_NAME": %s\n", dlerror()); +#else + mp_msg(MSGT_VOBSUB, MSGL_DBG2, "UnRAR: Cannot load "LIBUNRAR_NAME": dlopen not supported"); +#endif /* HAVE_LIBDL */ +#else + mp_msg( + MSGT_VOBSUB, + MSGL_DBG2, + "UnRAR: Cannot load "LIBUNRAR_NAME", GetLastError() returns %d\n", + GetLastError()); +#endif /* _WIN32 */ + return NULL; + } + + RAROpenArchive = dlsym(libhdl, "RAROpenArchive"); + RARSetPassword = dlsym(libhdl, "RARSetPassword"); + RARReadHeader = dlsym(libhdl, "RARReadHeader"); + RARProcessFile = dlsym(libhdl, "RARProcessFile"); + RARCloseArchive = dlsym(libhdl, "RARCloseArchive"); + RARSetCallback = dlsym(libhdl, "RARSetCallback"); + + if (!RAROpenArchive || !RARSetPassword || + !RARReadHeader || !RARProcessFile || + !RARCloseArchive || !RARSetCallback) + { + dlclose(libhdl); +#ifndef _WIN32 +#ifdef HAVE_LIBDL + mp_msg(MSGT_VOBSUB, MSGL_DBG2, "UnRAR: dlsym failed: %s\n", dlerror()); +#else + mp_msg(MSGT_VOBSUB, MSGL_DBG2, "UnRAR: dlsym failed: dlsym not supported"); +#endif /* HAVE_LIBDL */ +#else + mp_msg( + MSGT_VOBSUB, + MSGL_DBG2, + "UnRAR: GetProcAddress() failed, GetLastError() returns %d\n", + GetLastError()); +#endif /* _WIN32 */ + return NULL; + } + + return libhdl; +} + +static int libunrar_get(void **output, + unsigned long *size, + char *filename, + void *rarfile, + char *libpassword) +{ + struct RAROpenArchiveData opendata = {rarfile, RAR_OM_EXTRACT, ERAR_EOPEN, NULL, 0, 0, 0}; + struct RARHeaderData headerdata; + int ret = 0; + HANDLE rarhdl; + void* libhdl; + void* p = NULL; + + *output = NULL; + *size = 0; + + /* No, we don't recurse into directories */ + if (strstr(filename, PATHDELIMSTR)) + return 0; + + if ((libhdl = init_func_pointers()) == NULL) + return 0; + + rarhdl = RAROpenArchive(&opendata); + if (!rarhdl || opendata.OpenResult) + goto byebye; + + if (libpassword && strlen(libpassword)) + RARSetPassword(rarhdl, libpassword); + + headerdata.CmtBufSize = 0; + + while (1) + { + if (RARReadHeader(rarhdl, &headerdata)) + goto byebye; + + // We won't extract subdirs + if (headerdata.Flags & 0xe0 == 0xe0 || strcasecmp(headerdata.FileName, filename)) + { + if (RARProcessFile(rarhdl, RAR_SKIP, NULL, NULL)) + break; + } + else + { + *size = headerdata.UnpSize; + p = *output = malloc(*size); + if (!output) + break; + RARSetCallback(rarhdl, CallbackProc, (long)&p); + if (!RARProcessFile(rarhdl, RAR_TEST, NULL, NULL)) + ret = 1; + else + { + free(*output); + *output = NULL; + } + break; + } + } +byebye: + RARCloseArchive(rarhdl); + dlclose(libhdl); + return ret; +} /* end of file urarlib.c */