[MPlayer-dev-eng] [PATCH] Use libunrar when available (2nd try)

Zuxy Meng zuxy.meng at gmail.com
Wed May 31 12:53:12 CEST 2006


Hi,

This time temporary files are completely avoided, thanks to Eugene,
author of RAR. Also, libunique isn't completely discarded and
continues to work as a fallback of external libunrar.so/unrar.dll.

-- 
Zuxy
Beauty is truth,
While truth is beauty.
PGP KeyID: E8555ED6
-------------- next part --------------
--- main/unrarlib.c	2005-04-16 02:48:03.000000000 +0800
+++ main.new/unrarlib.c	2006-05-31 18:38:58.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);
@@ -2725,5 +2734,196 @@
  ****************************************************************************
  ************************************************************************** */
 
+/* -- The following code's added by MPlayer --------------------------------*/
+#ifndef _WIN32
+#define PASCAL
+#define CALLBACK
+#include <dlfcn.h>
+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)
+    {
+#if 0
+#ifndef _WIN32
+        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", GetLastError() returns %d\n",
+               GetLastError());
+#endif /* _WIN32 */
+#endif
+        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);
+#if 0
+#ifndef _WIN32
+        mp_msg(MSGT_VOBSUB, MSGL_DBG2, "UnRAR: dlsym failed: %s\n", dlerror()); 
+#else
+        mp_msg(
+               MSGT_VOBSUB,
+               MSGL_DBG2,
+               "UnRAR: GetProcAddress() failed, GetLastError() returns %d\n",
+               GetLastError());
+#endif /* _WIN32 */
+#endif
+        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 MPlayer specific code --------------------------------- */
 /* end of file urarlib.c */


More information about the MPlayer-dev-eng mailing list