Merge pull request #155 from Blizzard/unzip
add zip.extract(src, dst) method.
This commit is contained in:
commit
6f2d3b9f18
@ -5,29 +5,74 @@
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
int do_mkdir(const char* path)
|
||||
{
|
||||
struct stat sb;
|
||||
char sub_path[1024];
|
||||
int i, length;
|
||||
|
||||
// if it already exists, return.
|
||||
if (stat(path, &sb) == 0)
|
||||
return 1;
|
||||
|
||||
// find the parent folder name.
|
||||
length = strlen(path);
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (path[i] == '/' || path[i] == '\\')
|
||||
break;
|
||||
}
|
||||
|
||||
// if we found one, create it.
|
||||
if (i > 0)
|
||||
{
|
||||
memcpy(sub_path, path, i);
|
||||
sub_path[i] = '\0';
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
if (sub_path[i - 1] == ':')
|
||||
{
|
||||
sub_path[i + 0] = '/';
|
||||
sub_path[i + 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!do_mkdir(sub_path))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// now finally create the actual folder we want.
|
||||
#if PLATFORM_WINDOWS
|
||||
return _mkdir(path) == 0;
|
||||
#else
|
||||
return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int os_mkdir(lua_State* L)
|
||||
{
|
||||
int z;
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
z = CreateDirectory(path, NULL);
|
||||
#else
|
||||
z = (mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0);
|
||||
#endif
|
||||
|
||||
int z = do_mkdir(path);
|
||||
if (!z)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to create directory '%s'", path);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,13 @@ static const luaL_Reg http_functions[] = {
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
static const luaL_Reg zip_functions[] = {
|
||||
{ "extract", zip_extract },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initialize the Premake Lua environment.
|
||||
*/
|
||||
@ -111,6 +118,10 @@ int premake_init(lua_State* L)
|
||||
luaL_register(L, "http", http_functions);
|
||||
#endif
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
luaL_register(L, "zip", zip_functions);
|
||||
#endif
|
||||
|
||||
/* push the application metadata */
|
||||
lua_pushstring(L, LUA_COPYRIGHT);
|
||||
lua_setglobal(L, "_COPYRIGHT");
|
||||
|
@ -127,6 +127,10 @@ int http_get(lua_State* L);
|
||||
int http_download(lua_State* L);
|
||||
#endif
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
int zip_extract(lua_State* L);
|
||||
#endif
|
||||
|
||||
/* Engine interface */
|
||||
int premake_init(lua_State* L);
|
||||
int premake_execute(lua_State* L, int argc, const char** argv, const char* script);
|
||||
|
229
src/host/zip_extract.c
Normal file
229
src/host/zip_extract.c
Normal file
@ -0,0 +1,229 @@
|
||||
/**
|
||||
* \file os_unzip.c
|
||||
* \brief Unzip file using libzip library.
|
||||
* \author battle.net -- abrunasso.int@blizzard.com
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
|
||||
#include <zip.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
// File Attribute for Unix
|
||||
#define FA_IFIFO 0010000 /* named pipe (fifo) */
|
||||
#define FA_IFCHR 0020000 /* character special */
|
||||
#define FA_IFDIR 0040000 /* directory */
|
||||
#define FA_IFBLK 0060000 /* block special */
|
||||
#define FA_IFREG 0100000 /* regular */
|
||||
#define FA_IFLNK 0120000 /* symbolic link */
|
||||
#define FA_IFSOCK 0140000 /* socket */
|
||||
|
||||
#define FA_ISUID 0004000 /* set user id on execution */
|
||||
#define FA_ISGID 0002000 /* set group id on execution */
|
||||
#define FA_ISTXT 0001000 /* sticky bit */
|
||||
#define FA_IRWXU 0000700 /* RWX mask for owner */
|
||||
#define FA_IRUSR 0000400 /* R for owner */
|
||||
#define FA_IWUSR 0000200 /* W for owner */
|
||||
#define FA_IXUSR 0000100 /* X for owner */
|
||||
#define FA_IRWXG 0000070 /* RWX mask for group */
|
||||
#define FA_IRGRP 0000040 /* R for group */
|
||||
#define FA_IWGRP 0000020 /* W for group */
|
||||
#define FA_IXGRP 0000010 /* X for group */
|
||||
#define FA_IRWXO 0000007 /* RWX mask for other */
|
||||
#define FA_IROTH 0000004 /* R for other */
|
||||
#define FA_IWOTH 0000002 /* W for other */
|
||||
#define FA_IXOTH 0000001 /* X for other */
|
||||
#define FA_ISVTX 0001000 /* save swapped text even after use */
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static int is_symlink(zip_uint8_t opsys, zip_uint32_t attrib)
|
||||
{
|
||||
if (opsys == ZIP_OPSYS_DOS)
|
||||
return (attrib & 0x400) == 0x400; // FILE_ATTRIBUTE_REPARSE_POINT
|
||||
|
||||
if (opsys == ZIP_OPSYS_UNIX)
|
||||
return ((attrib >> 16) & FA_IFLNK) == FA_IFLNK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int is_directory(zip_uint8_t opsys, zip_uint32_t attrib)
|
||||
{
|
||||
if (opsys == ZIP_OPSYS_DOS)
|
||||
return (attrib & 0x10) == 0x10; // FILE_ATTRIBUTE_DIRECTORY
|
||||
|
||||
if (opsys == ZIP_OPSYS_UNIX)
|
||||
return ((attrib >> 16) & FA_IFDIR) == FA_IFDIR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_link(const char* filename, const char* bytes, size_t count)
|
||||
{
|
||||
#if PLATFORM_POSIX
|
||||
return symlink(bytes, filename);
|
||||
#else
|
||||
FILE* fp = fopen(filename, "wb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("Error creating file:\n %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
fwrite(bytes, sizeof(char), count, fp);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern int do_mkdir(const char* path);
|
||||
|
||||
static void parse_path(const char* full_name, char* filename, char* directory)
|
||||
{
|
||||
char *ssc;
|
||||
size_t orig_length = strlen(full_name);
|
||||
size_t l = 0;
|
||||
size_t dir_size;
|
||||
|
||||
ssc = strstr(full_name, "/");
|
||||
do
|
||||
{
|
||||
l = strlen(ssc) + 1;
|
||||
full_name = &full_name[strlen(full_name) - l + 2];
|
||||
ssc = strstr(full_name, "/");
|
||||
} while (ssc);
|
||||
|
||||
// full_name currently pointing to beginning of filename
|
||||
memcpy(filename, full_name, strlen(full_name));
|
||||
filename[strlen(full_name)] = 0; // Null terminate it
|
||||
|
||||
dir_size = orig_length - strlen(filename);
|
||||
// full_name points to beginning of original string(with directory)
|
||||
full_name = &full_name[strlen(full_name) - orig_length];
|
||||
|
||||
// Extract directory from full name by removing filename
|
||||
memcpy(directory, full_name, dir_size);
|
||||
directory[dir_size] = 0;
|
||||
}
|
||||
|
||||
|
||||
static int extract(const char* src, const char* destination)
|
||||
{
|
||||
int err = 0;
|
||||
FILE *fp = NULL;
|
||||
struct zip *z_archive = zip_open(src, 0, &err);
|
||||
int i;
|
||||
zip_int64_t entries;
|
||||
char buffer[4096];
|
||||
char appended_full_name[512];
|
||||
char directory[512];
|
||||
char filename[512];
|
||||
size_t result;
|
||||
zip_int64_t bytes_read;
|
||||
|
||||
if (!z_archive)
|
||||
{
|
||||
printf("%s does not exist\n", src);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0, entries = zip_get_num_entries(z_archive, 0); i < entries; ++i)
|
||||
{
|
||||
struct zip_file* zf = zip_fopen_index(z_archive, i, 0);
|
||||
if (!zf)
|
||||
continue;
|
||||
|
||||
zip_uint8_t opsys;
|
||||
zip_uint32_t attrib;
|
||||
zip_file_get_external_attributes(z_archive, i, 0, &opsys, &attrib);
|
||||
|
||||
const char* full_name = zip_get_name(z_archive, i, 0);
|
||||
|
||||
sprintf(appended_full_name, "%s/%s", destination, full_name);
|
||||
parse_path(appended_full_name, filename, directory);
|
||||
do_mkdir(directory);
|
||||
|
||||
// is this a symbolic link?
|
||||
if (is_symlink(opsys, attrib))
|
||||
{
|
||||
bytes_read = zip_fread(zf, buffer, sizeof(buffer));
|
||||
buffer[bytes_read] = '\0';
|
||||
if (write_link(appended_full_name, buffer, bytes_read) != 0)
|
||||
{
|
||||
printf(" Failed to create symbolic link [%s->%s]\n", appended_full_name, buffer);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// If blank filename it's just a directory so create it and move on
|
||||
if (!is_directory(opsys, attrib) && strlen(filename) > 0)
|
||||
{
|
||||
// mark as read-write, so we can overwrite the file if it already exists.
|
||||
chmod(appended_full_name, 0666);
|
||||
|
||||
fp = fopen(appended_full_name, "wb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("Error reading file:\n %s\n", appended_full_name);
|
||||
return -1;
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
// Read content from zipped file
|
||||
bytes_read = zip_fread(zf, buffer, sizeof(buffer));
|
||||
if (bytes_read == 0) break;
|
||||
// Write that content to file
|
||||
result = fwrite(buffer, sizeof(char), (size_t)bytes_read, fp);
|
||||
// If all bytes read weren't written, report error
|
||||
if (result != (size_t)bytes_read)
|
||||
{
|
||||
printf(" Writing data to %s failed\n %d bytes were written\n %d bytes were attempted to be written\n File may be corrupt\n",
|
||||
appended_full_name, (int)result, (int)bytes_read);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// mark read-only, but maintain the other properties.
|
||||
if (opsys == ZIP_OPSYS_UNIX)
|
||||
chmod(appended_full_name, (attrib >> 16) & ~0222);
|
||||
else
|
||||
chmod(appended_full_name, 0444);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
zip_fclose(zf);
|
||||
}
|
||||
zip_close(z_archive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int zip_extract(lua_State* L)
|
||||
{
|
||||
const char* src = luaL_checkstring(L, 1);
|
||||
const char* dst = luaL_checkstring(L, 2);
|
||||
|
||||
int res = extract(src, dst);
|
||||
|
||||
lua_pushnumber(L, res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user