From d9fd9c91779af7d57c48b4e8578b7bb74a59ad2c Mon Sep 17 00:00:00 2001
From: Timo Strunk <Timo.Strunk@nanomatch.com>
Date: Sat, 6 Sep 2014 20:47:16 +0200
Subject: [PATCH] Added funtion to list a compressed 7zip file as a directory

---
 decompress/7zip_support.c | 150 +++++++++++++++++++++++++++++++++++++-
 decompress/7zip_support.h |   3 +
 2 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/decompress/7zip_support.c b/decompress/7zip_support.c
index cdec20c973..4b223d8daa 100644
--- a/decompress/7zip_support.c
+++ b/decompress/7zip_support.c
@@ -21,6 +21,7 @@
 
 #include <string.h>
 #include "../miscellaneous.h"
+#include "../file_path.h"
 
 #include "../deps/7zip/7z.h"
 #include "../deps/7zip/7zAlloc.h"
@@ -28,6 +29,8 @@
 #include "../deps/7zip/7zFile.h"
 #include "../deps/7zip/7zVersion.h"
 
+
+
 static ISzAlloc g_Alloc = { SzAlloc, SzFree };
 
 static int Buf_EnsureSize(CBuf *dest, size_t size)
@@ -225,7 +228,6 @@ int read_7zip_file(const char * archive_path, const char *relative_path, void **
          res = ConvertUtf16toCharString(temp,infile);
 
          UInt64 filesize = f->Size;
-         (void)filesize;
 
          if (strcmp(infile,relative_path) == 0)
          {
@@ -267,3 +269,149 @@ int read_7zip_file(const char * archive_path, const char *relative_path, void **
       RARCH_ERR("\nUnspecified error in 7-ZIP archive, error number was: #%d\n", res);
    return -1;
 }
+
+struct string_list *compressed_7zip_file_list_new(const char *path,
+      const char* ext)
+{
+
+   struct string_list *ext_list = NULL;
+   struct string_list *list = (struct string_list*)string_list_new();
+   if (!list)
+   {
+      RARCH_ERR("Could not allocate list memory in compressed_7zip_file_list_new\n.");
+      return NULL;
+   }
+
+   if (ext)
+      ext_list = string_split(ext, "|");
+
+   /* 7Zip part begin */
+   CFileInStream archiveStream;
+   CLookToRead lookStream;
+   CSzArEx db;
+   SRes res;
+   ISzAlloc allocImp;
+   ISzAlloc allocTempImp;
+   UInt16 *temp = NULL;
+   size_t tempSize = 0;
+   long outsize = -1;
+
+   //These are the allocation routines - currently using the non-standard 7zip choices.
+   allocImp.Alloc = SzAlloc;
+   allocImp.Free = SzFree;
+   allocTempImp.Alloc = SzAllocTemp;
+   allocTempImp.Free = SzFreeTemp;
+
+   if (InFile_Open(&archiveStream.file, path))
+   {
+      RARCH_ERR("Could not open %s as 7z archive\n.",path);
+      goto error;
+   }
+   FileInStream_CreateVTable(&archiveStream);
+   LookToRead_CreateVTable(&lookStream, False);
+   lookStream.realStream = &archiveStream.s;
+   LookToRead_Init(&lookStream);
+   CrcGenerateTable();
+   SzArEx_Init(&db);
+   res = SzArEx_Open(&db, &lookStream.s, &allocImp, &allocTempImp);
+   if (res == SZ_OK)
+   {
+      UInt32 i;
+      UInt32 blockIndex = 0xFFFFFFFF;
+      Byte *outBuffer = 0;
+      size_t outBufferSize = 0;
+      for (i = 0; i < db.db.NumFiles; i++)
+      {
+         size_t offset = 0;
+         size_t outSizeProcessed = 0;
+         const CSzFileItem *f = db.db.Files + i;
+         size_t len;
+         if (f->IsDir)
+         {
+            /* we skip over everything, which is a directory. */
+            continue;
+         }
+         len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+         if (len > tempSize)
+         {
+            SzFree(NULL, temp);
+            tempSize = len;
+            temp = (UInt16 *) SzAlloc(NULL, tempSize * sizeof(temp[0]));
+            if (temp == 0)
+            {
+               res = SZ_ERROR_MEM;
+               break;
+            }
+         }
+         SzArEx_GetFileNameUtf16(&db, i, temp);
+         char infile[PATH_MAX];
+         res = ConvertUtf16toCharString(temp, infile);
+
+         const char *file_ext = path_get_extension(infile);
+         bool supported_by_core  = false;
+
+         union string_list_elem_attr attr;
+
+         if (string_list_find_elem_prefix(ext_list, ".", file_ext))
+            supported_by_core = true;
+
+         /*
+          * Currently we only support files without subdirs in the archives.
+          * Folders are not supported (differences between win and lin.
+          * Archives within archives should imho never be supported.
+          */
+
+         if (!supported_by_core)
+            continue;
+
+         attr.i = RARCH_COMPRESSED_FILE_IN_ARCHIVE;
+
+         if (!string_list_append(list, infile, attr))
+            goto error;
+
+      }
+   }
+   SzArEx_Free(&db, &allocImp);
+   SzFree(NULL, temp);
+   File_Close(&archiveStream.file);
+
+   if (res != SZ_OK)
+   {
+      //Error handling:
+      if (res == SZ_ERROR_UNSUPPORTED)
+      {
+         RARCH_ERR("7Zip decoder doesn't support this archive\n");
+         goto error;
+      }
+      else if (res == SZ_ERROR_MEM)
+      {
+         RARCH_ERR("7Zip decoder could not allocate memory\n");
+         goto error;
+      }
+      else if (res == SZ_ERROR_CRC)
+      {
+         RARCH_ERR("7Zip decoder encountered a CRC error in the archive\n");
+         goto error;
+      }
+      else
+      {
+         RARCH_ERR(
+               "\nUnspecified error in 7-ZIP archive, error number was: #%d\n",
+               res);
+         goto error;
+      }
+   }
+
+   string_list_free(ext_list);
+   return list;
+
+error:
+   RARCH_ERR("Failed to open compressed_file: \"%s\"\n", path);
+   SzArEx_Free(&db, &allocImp);
+   SzFree(NULL, temp);
+   File_Close(&archiveStream.file);
+   string_list_free(list);
+   string_list_free(ext_list);
+   return NULL;
+
+}
diff --git a/decompress/7zip_support.h b/decompress/7zip_support.h
index d08d5031cc..2c425b21ea 100644
--- a/decompress/7zip_support.h
+++ b/decompress/7zip_support.h
@@ -23,6 +23,9 @@ extern "C" {
 int read_7zip_file(const char * archive_path,
       const char *relative_path, void **buf);
 
+struct string_list *compressed_7zip_file_list_new(const char *path,
+      const char* ext);
+
 #ifdef __cplusplus
 }
 #endif