Alexandre Julliard : cabarc: Add support for listing and extracting cabinets.

Alexandre Julliard julliard at winehq.org
Thu Feb 3 12:00:21 CST 2011


Module: wine
Branch: master
Commit: 8ebff12b0513efd541b459ed3858452a0f5c9fdd
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=8ebff12b0513efd541b459ed3858452a0f5c9fdd

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Feb  2 22:48:40 2011 +0100

cabarc: Add support for listing and extracting cabinets.

---

 programs/cabarc/cabarc.c |  204 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 200 insertions(+), 4 deletions(-)

diff --git a/programs/cabarc/cabarc.c b/programs/cabarc/cabarc.c
index 5a10d21..2aeb88e 100644
--- a/programs/cabarc/cabarc.c
+++ b/programs/cabarc/cabarc.c
@@ -69,6 +69,7 @@ static int opt_recurse;
 static int opt_preserve_paths;
 static int opt_reserve_space;
 static int opt_verbose;
+static WCHAR *opt_dest_dir;
 static WCHAR **opt_files;
 
 static void * CDECL cab_alloc( ULONG size )
@@ -258,6 +259,194 @@ static INT_PTR CDECL fci_get_open_info( char *name, USHORT *date, USHORT *time,
     return (INT_PTR)handle;
 }
 
+static INT_PTR CDECL fdi_open( char *file, int oflag, int pmode )
+{
+    int err;
+    return fci_open( file, oflag, pmode, &err, NULL );
+}
+
+static UINT CDECL fdi_read( INT_PTR hf, void *pv, UINT cb )
+{
+    int err;
+    return fci_read( hf, pv, cb, &err, NULL );
+}
+
+static UINT CDECL fdi_write( INT_PTR hf, void *pv, UINT cb )
+{
+    int err;
+    return fci_write( hf, pv, cb, &err, NULL );
+}
+
+static int CDECL fdi_close( INT_PTR hf )
+{
+    int err;
+    return fci_close( hf, &err, NULL );
+}
+
+static LONG CDECL fdi_lseek( INT_PTR hf, LONG dist, int whence )
+{
+    int err;
+    return fci_lseek( hf, dist, whence, &err, NULL );
+}
+
+
+/* create directories leading to a given file */
+static void create_directories( const WCHAR *name )
+{
+    WCHAR *path, *p;
+
+    /* create the directory/directories */
+    path = cab_alloc( (strlenW(name) + 1) * sizeof(WCHAR) );
+    strcpyW(path, name);
+
+    p = strchrW(path, '\\');
+    while (p != NULL)
+    {
+        *p = 0;
+        if (!CreateDirectoryW( path, NULL ))
+            WINE_TRACE("Couldn't create directory %s - error: %d\n", wine_dbgstr_w(path), GetLastError());
+        *p = '\\';
+        p = strchrW(p+1, '\\');
+    }
+    cab_free( path );
+}
+
+/* check if file name matches against one of the files specification */
+static BOOL match_files( const WCHAR *name )
+{
+    int i;
+
+    if (!*opt_files) return TRUE;
+    for (i = 0; opt_files[i]; i++)
+    {
+        unsigned int len = strlenW( opt_files[i] );
+        /* FIXME: do smarter matching, and wildcards */
+        if (!len) continue;
+        if (strncmpiW( name, opt_files[i], len )) continue;
+        if (opt_files[i][len - 1] == '\\' || !name[len] || name[len] == '\\') return TRUE;
+    }
+    return FALSE;
+}
+
+static INT_PTR CDECL list_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
+{
+    WCHAR *nameW;
+
+    switch (fdint)
+    {
+    case fdintCABINET_INFO:
+        return 0;
+    case fdintCOPY_FILE:
+        nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 );
+        if (match_files( nameW ))
+        {
+            char *nameU = strdupWtoA( CP_UNIXCP, nameW );
+            if (opt_verbose)
+            {
+                char attrs[] = "rxash";
+                if (!(pfdin->attribs & _A_RDONLY)) attrs[0] = '-';
+                if (!(pfdin->attribs & _A_EXEC))   attrs[1] = '-';
+                if (!(pfdin->attribs & _A_ARCH))   attrs[2] = '-';
+                if (!(pfdin->attribs & _A_SYSTEM)) attrs[3] = '-';
+                if (!(pfdin->attribs & _A_HIDDEN)) attrs[4] = '-';
+                printf( " %s %9u  %04u/%02u/%02u %02u:%02u:%02u  ", attrs, pfdin->cb,
+                        (pfdin->date >> 9) + 1980, (pfdin->date >> 5) & 0x0f, pfdin->date & 0x1f,
+                        pfdin->time >> 11, (pfdin->time >> 5) & 0x3f, (pfdin->time & 0x1f) * 2 );
+            }
+            printf( "%s\n", nameU );
+            cab_free( nameU );
+        }
+        cab_free( nameW );
+        return 0;
+    default:
+        WINE_FIXME( "Unexpected notification type %d.\n", fdint );
+        return 0;
+    }
+}
+
+static int list_cabinet( char *cab_dir, char *cab_file )
+{
+    ERF erf;
+    int ret = 0;
+    HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read,
+                          fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf );
+
+    if (!FDICopy( fdi, cab_file, cab_dir, 0, list_notify, NULL, NULL )) ret = GetLastError();
+    FDIDestroy( fdi );
+    return ret;
+}
+
+static INT_PTR CDECL extract_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
+{
+    WCHAR *file, *nameW, *path = NULL;
+    INT_PTR ret;
+
+    switch (fdint)
+    {
+    case fdintCABINET_INFO:
+        return 0;
+
+    case fdintCOPY_FILE:
+        nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 );
+        if (opt_preserve_paths)
+        {
+            file = nameW;
+            while (*file == '\\') file++;  /* remove leading backslashes */
+        }
+        else
+        {
+            if ((file = strrchrW( nameW, '\\' ))) file++;
+            else file = nameW;
+        }
+
+        if (opt_dest_dir)
+        {
+            path = cab_alloc( (strlenW(opt_dest_dir) + strlenW(file) + 1) * sizeof(WCHAR) );
+            strcpyW( path, opt_dest_dir );
+            strcatW( path, file );
+        }
+        else path = file;
+
+        if (match_files( file ))
+        {
+            if (opt_verbose)
+            {
+                char *nameU = strdupWtoA( CP_UNIXCP, path );
+                printf( "extracting %s\n", nameU );
+                cab_free( nameU );
+            }
+            create_directories( path );
+            /* FIXME: check for existing file and overwrite mode */
+            ret = (INT_PTR)CreateFileW( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+                                        NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
+        }
+        else ret = 0;
+
+        cab_free( nameW );
+        if (path != file) cab_free( path );
+        return ret;
+
+    case fdintCLOSE_FILE_INFO:
+        CloseHandle( (HANDLE)pfdin->hf );
+        return 0;
+
+    default:
+        WINE_FIXME( "Unexpected notification type %d.\n", fdint );
+        return 0;
+    }
+}
+
+static int extract_cabinet( char *cab_dir, char *cab_file )
+{
+    ERF erf;
+    int ret = 0;
+    HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read,
+                          fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf );
+
+    if (!FDICopy( fdi, cab_file, cab_dir, 0, extract_notify, NULL, NULL )) ret = GetLastError();
+    FDIDestroy( fdi );
+    return ret;
+}
 
 static BOOL add_file( HFCI fci, WCHAR *name )
 {
@@ -468,15 +657,22 @@ int wmain( int argc, WCHAR *argv[] )
     {
     case 'l':
     case 'L':
-        WINE_FIXME( "list not implemented\n" );
-        return 1;
+        return list_cabinet( buffer, file_part );
     case 'n':
     case 'N':
         return new_cabinet( buffer, file_part );
     case 'x':
     case 'X':
-        WINE_FIXME( "extraction not implemented\n" );
-        return 1;
+        if (argc > 1)  /* check for destination dir as last argument */
+        {
+            WCHAR *last = argv[argc - 1];
+            if (last[0] && last[strlenW(last) - 1] == '\\')
+            {
+                opt_dest_dir = last;
+                argv[--argc] = NULL;
+            }
+        }
+        return extract_cabinet( buffer, file_part );
     default:
         usage();
         return 1;




More information about the wine-cvs mailing list