diff --git a/src/framework/File.cpp b/src/framework/File.cpp
index d9d0e52..e034f51 100644
--- a/src/framework/File.cpp
+++ b/src/framework/File.cpp
@@ -1484,8 +1484,10 @@ int idFile_InZip::Seek( long offset, fsOrigin_t origin ) {
 		}
 		case FS_SEEK_SET: {
 			// set the file position in the zip file (also sets the current file info)
-			unzSetCurrentFileInfoPosition( z, zipFilePos );
-			unzOpenCurrentFile( z );
+			if ( unzSetCurrentFileInfoPosition( z, zipFilePos ) != UNZ_OK ||
+				unzOpenCurrentFile( z ) != UNZ_OK ) {
+				return -1;
+			}
 			if ( offset < 0 ) {
 				return -1;
 			}
diff --git a/src/framework/FileSystem.cpp b/src/framework/FileSystem.cpp
index c077330..8ac5ea8 100644
--- a/src/framework/FileSystem.cpp
+++ b/src/framework/FileSystem.cpp
@@ -5795,7 +5795,6 @@ idFileSystemLocal::ReadFileFromZip
 */
 idFile_InZip * idFileSystemLocal::ReadFileFromZip( pack_t *pak, fileInPack_t *pakFile, const char *relativePath ) {
 	unz_s *			zfi;
-	FILE *			fp;
 	idFile_InZip *file = new idFile_InZip();
 
 	// open a new file on the pakfile
@@ -5806,16 +5805,14 @@ idFile_InZip * idFileSystemLocal::ReadFileFromZip( pack_t *pak, fileInPack_t *pa
 	file->name = relativePath;
 	file->fullPath = pak->pakFilename + "/" + relativePath;
 	zfi = (unz_s *)file->z;
-	// in case the file was new
-	fp = zfi->file;
 	// set the file position in the zip file (also sets the current file info)
-	unzSetCurrentFileInfoPosition( pak->handle, pakFile->pos );
-	// copy the file info into the unzip structure
-	memcpy( zfi, pak->handle, sizeof(unz_s) );
-	// we copy this back into the structure
-	zfi->file = fp;
+	if ( unzSetCurrentFileInfoPosition( file->z, pakFile->pos ) != UNZ_OK ) {
+		common->FatalError( "Couldn't seek in %s", pak->pakFilename.c_str() );
+	}
 	// open the file in the zip
-	unzOpenCurrentFile( file->z );
+	if ( unzOpenCurrentFile( file->z ) != UNZ_OK ) {
+		common->FatalError( "Couldn't open %s from %s", relativePath, pak->pakFilename.c_str() );
+	}
 	file->zipFilePos = pakFile->pos;
 	file->fileSize = zfi->cur_file_info.uncompressed_size;
 	return file;
diff --git a/src/framework/Unzip.cpp b/src/framework/Unzip.cpp
index b2682f5..2794f3c 100644
--- a/src/framework/Unzip.cpp
+++ b/src/framework/Unzip.cpp
@@ -2,6 +2,9 @@
 
 
 #include "Unzip.h"
+#ifdef __EMSCRIPTEN__
+#include <limits>
+#endif
 
 /* unzip.h -- IO for uncompress .zip files using zlib 
    Version 0.15 beta, Mar 19th, 1998,
@@ -1102,7 +1105,10 @@ static int unzlocal_getShort (FILE* fin, uLong *pX)
 {
 	short	v;
 
-	fread( &v, sizeof(v), 1, fin );
+	if ( fread( &v, sizeof(v), 1, fin ) != 1 ) {
+		*pX = 0;
+		return UNZ_ERRNO;
+	}
 
 	*pX = LittleShort( v);
 	return UNZ_OK;
@@ -1131,7 +1137,10 @@ static int unzlocal_getLong (FILE *fin, uLong *pX)
 {
 	int		v;
 
-	fread( &v, sizeof(v), 1, fin );
+	if ( fread( &v, sizeof(v), 1, fin ) != 1 ) {
+		*pX = 0;
+		return UNZ_ERRNO;
+	}
 
 	*pX = LittleLong( v);
 	return UNZ_OK;
@@ -1279,20 +1288,109 @@ static uLong unzlocal_SearchCentralDir(FILE *fin)
 	return uPosFound;
 }
 
+#ifdef __EMSCRIPTEN__
+struct unz_central_dir_cache_s {
+	unsigned int references;
+	uLong size;
+	unsigned char *data;
+};
+
+static void unzlocal_ReleaseCentralDirectory( unz_s *s ) {
+	if ( s->central_dir_file != NULL ) {
+		fclose( s->central_dir_file );
+		s->central_dir_file = NULL;
+	}
+	if ( s->central_dir_cache == NULL ) {
+		return;
+	}
+	if ( --s->central_dir_cache->references == 0 ) {
+		TRYFREE( s->central_dir_cache->data );
+		TRYFREE( s->central_dir_cache );
+	}
+	s->central_dir_cache = NULL;
+}
+
+static int unzlocal_CacheCentralDirectory( unz_s *s ) {
+	unz_central_dir_cache_s *cache;
+	FILE *stream;
+
+	s->central_dir_cache = NULL;
+	s->central_dir_file = NULL;
+	if ( s->size_central_dir == 0 || s->size_central_dir > 64 * 1024 * 1024 ||
+		s->size_central_dir > static_cast<uLong>( std::numeric_limits<int>::max() ) ) {
+		return UNZ_OK;
+	}
+	cache = (unz_central_dir_cache_s *)ALLOC( sizeof( unz_central_dir_cache_s ) );
+	if ( cache == NULL ) {
+		return UNZ_OK;
+	}
+	cache->references = 1;
+	cache->size = s->size_central_dir;
+	cache->data = (unsigned char *)ALLOC( (int)cache->size );
+	if ( cache->data == NULL ) {
+		TRYFREE( cache );
+		return UNZ_OK;
+	}
+	if ( fseek( s->file, s->offset_central_dir + s->byte_before_the_zipfile, SEEK_SET ) != 0 ||
+		fread( cache->data, 1, cache->size, s->file ) != cache->size ) {
+		TRYFREE( cache->data );
+		TRYFREE( cache );
+		return UNZ_ERRNO;
+	}
+	stream = fmemopen( cache->data, cache->size, "rb" );
+	if ( stream == NULL ) {
+		TRYFREE( cache->data );
+		TRYFREE( cache );
+		return UNZ_OK;
+	}
+	s->central_dir_cache = cache;
+	s->central_dir_file = stream;
+	return UNZ_OK;
+}
+
+static void unzlocal_RetainCentralDirectory( unz_s *s ) {
+	unz_central_dir_cache_s *cache = s->central_dir_cache;
+	FILE *stream;
+
+	s->central_dir_cache = NULL;
+	s->central_dir_file = NULL;
+	if ( cache == NULL ) {
+		return;
+	}
+	stream = fmemopen( cache->data, cache->size, "rb" );
+	if ( stream == NULL ) {
+		return;
+	}
+	cache->references++;
+	s->central_dir_cache = cache;
+	s->central_dir_file = stream;
+}
+#endif
+
 extern unzFile unzReOpen (const char* path, unzFile file)
 {
 	unz_s *s;
 	FILE * fin;
+	if (file==NULL)
+		return NULL;
 
     fin=fopen(path,"rb");
 	if (fin==NULL)
 		return NULL;
 
 	s=(unz_s*)ALLOC(sizeof(unz_s));
+	if (s==NULL)
+	{
+		fclose(fin);
+		return NULL;
+	}
 	memcpy(s, (unz_s*)file, sizeof(unz_s));
 
 	s->file = fin;
     s->pfile_in_zip_read = NULL;
+#ifdef __EMSCRIPTEN__
+	unzlocal_RetainCentralDirectory(s);
+#endif
 
 	return (unzFile)s;	
 }
@@ -1372,8 +1470,8 @@ extern unzFile unzOpen (const char* path)
 	if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if ((central_pos<us.offset_central_dir+us.size_central_dir) && 
-		(err==UNZ_OK))
+	if ((us.offset_central_dir>central_pos ||
+		us.size_central_dir>central_pos-us.offset_central_dir) && (err==UNZ_OK))
 		err=UNZ_BADZIPFILE;
 
 	if (err!=UNZ_OK)
@@ -1387,9 +1485,25 @@ extern unzFile unzOpen (const char* path)
 		                    (us.offset_central_dir+us.size_central_dir);
 	us.central_pos = central_pos;
     us.pfile_in_zip_read = NULL;
-	
+#ifdef __EMSCRIPTEN__
+	us.central_dir_cache = NULL;
+	us.central_dir_file = NULL;
+	if (unzlocal_CacheCentralDirectory(&us)!=UNZ_OK)
+	{
+		fclose(fin);
+		return NULL;
+	}
+#endif
 
 	s=(unz_s*)ALLOC(sizeof(unz_s));
+	if (s==NULL)
+	{
+#ifdef __EMSCRIPTEN__
+		unzlocal_ReleaseCentralDirectory(&us);
+#endif
+		fclose(fin);
+		return NULL;
+	}
 	*s=us;
 //	unzGoToFirstFile((unzFile)s);	
 	return (unzFile)s;	
@@ -1411,6 +1525,9 @@ extern int unzClose (unzFile file)
     if (s->pfile_in_zip_read!=NULL)
         unzCloseCurrentFile(file);
 
+#ifdef __EMSCRIPTEN__
+	unzlocal_ReleaseCentralDirectory(s);
+#endif
 	fclose(s->file);
 	TRYFREE(s);
 	return UNZ_OK;
@@ -1468,68 +1585,107 @@ static int unzlocal_GetCurrentFileInfoInternal (unzFile file,
 	int err=UNZ_OK;
 	uLong uMagic;
 	long lSeek=0;
+	FILE *central_file;
+	long central_position;
+#ifdef __EMSCRIPTEN__
+	uLong central_relative = 0;
+#endif
 
 	if (file==NULL)
 		return UNZ_PARAMERROR;
 	s=(unz_s*)file;
-	if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
+	memset(&file_info, 0, sizeof(file_info));
+	memset(&file_info_internal, 0, sizeof(file_info_internal));
+	central_file = s->file;
+	central_position = s->pos_in_central_dir + s->byte_before_the_zipfile;
+#ifdef __EMSCRIPTEN__
+	if (s->central_dir_file!=NULL)
+	{
+		if (s->pos_in_central_dir<s->offset_central_dir)
+			return UNZ_BADZIPFILE;
+		central_relative = s->pos_in_central_dir-s->offset_central_dir;
+		if (central_relative>s->central_dir_cache->size ||
+			s->central_dir_cache->size-central_relative<SIZECENTRALDIRITEM)
+			return UNZ_BADZIPFILE;
+		central_file = s->central_dir_file;
+		central_position = central_relative;
+	}
+#endif
+	if (fseek(central_file,central_position,SEEK_SET)!=0)
 		err=UNZ_ERRNO;
 
 
 	/* we check the magic */
 	if (err==UNZ_OK)
-		if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
+		if (unzlocal_getLong(central_file,&uMagic) != UNZ_OK)
 			err=UNZ_ERRNO;
 		else if (uMagic!=0x02014b50)
 			err=UNZ_BADZIPFILE;
 
-	if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.version) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.version_needed) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.flag) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.compression_method) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
+	if (unzlocal_getLong(central_file,&file_info.dosDate) != UNZ_OK)
 		err=UNZ_ERRNO;
 
     unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
 
-	if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
+	if (unzlocal_getLong(central_file,&file_info.crc) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
+	if (unzlocal_getLong(central_file,&file_info.compressed_size) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
+	if (unzlocal_getLong(central_file,&file_info.uncompressed_size) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.size_filename) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.size_file_extra) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.size_file_comment) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.disk_num_start) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
+	if (unzlocal_getShort(central_file,&file_info.internal_fa) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
+	if (unzlocal_getLong(central_file,&file_info.external_fa) != UNZ_OK)
 		err=UNZ_ERRNO;
 
-	if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
+	if (unzlocal_getLong(central_file,&file_info_internal.offset_curfile) != UNZ_OK)
 		err=UNZ_ERRNO;
 
+#ifdef __EMSCRIPTEN__
+	if (err==UNZ_OK && s->central_dir_file!=NULL)
+	{
+		uLong remaining = s->central_dir_cache->size-central_relative-SIZECENTRALDIRITEM;
+		if (file_info.size_filename>remaining)
+			err=UNZ_BADZIPFILE;
+		else
+			remaining -= file_info.size_filename;
+		if (err==UNZ_OK && file_info.size_file_extra>remaining)
+			err=UNZ_BADZIPFILE;
+		else if (err==UNZ_OK)
+			remaining -= file_info.size_file_extra;
+		if (err==UNZ_OK && file_info.size_file_comment>remaining)
+			err=UNZ_BADZIPFILE;
+	}
+#endif
+
 	lSeek+=file_info.size_filename;
 	if ((err==UNZ_OK) && (szFileName!=NULL))
 	{
@@ -1543,7 +1699,7 @@ static int unzlocal_GetCurrentFileInfoInternal (unzFile file,
 			uSizeRead = fileNameBufferSize;
 
 		if ((file_info.size_filename>0) && (fileNameBufferSize>0))
-			if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
+			if (fread(szFileName,(uInt)uSizeRead,1,central_file)!=1)
 				err=UNZ_ERRNO;
 		lSeek -= uSizeRead;
 	}
@@ -1558,12 +1714,12 @@ static int unzlocal_GetCurrentFileInfoInternal (unzFile file,
 			uSizeRead = extraFieldBufferSize;
 
 		if (lSeek!=0)
-			if (fseek(s->file,lSeek,SEEK_CUR)==0)
+			if (fseek(central_file,lSeek,SEEK_CUR)==0)
 				lSeek=0;
 			else
 				err=UNZ_ERRNO;
 		if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
-			if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
+			if (fread(extraField,(uInt)uSizeRead,1,central_file)!=1)
 				err=UNZ_ERRNO;
 		lSeek += file_info.size_file_extra - uSizeRead;
 	}
@@ -1583,12 +1739,12 @@ static int unzlocal_GetCurrentFileInfoInternal (unzFile file,
 			uSizeRead = commentBufferSize;
 
 		if (lSeek!=0)
-			if (fseek(s->file,lSeek,SEEK_CUR)==0)
+			if (fseek(central_file,lSeek,SEEK_CUR)==0)
 				lSeek=0;
 			else
 				err=UNZ_ERRNO;
 		if ((file_info.size_file_comment>0) && (commentBufferSize>0))
-			if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
+			if (fread(szComment,(uInt)uSizeRead,1,central_file)!=1)
 				err=UNZ_ERRNO;
 		lSeek+=file_info.size_file_comment - uSizeRead;
 	}
@@ -1702,7 +1858,7 @@ extern int unzSetCurrentFileInfoPosition (unzFile file, unsigned long pos )
 											   &s->cur_file_info_internal,
 											   NULL,0,NULL,0,NULL,0);
 	s->current_file_ok = (err == UNZ_OK);
-	return UNZ_OK;
+	return err;
 }
 
 /*
diff --git a/src/framework/Unzip.h b/src/framework/Unzip.h
index 5d5579f..77648d6 100644
--- a/src/framework/Unzip.h
+++ b/src/framework/Unzip.h
@@ -140,11 +140,19 @@ typedef struct
 } file_in_zip_read_info_s;
 
 
+#ifdef __EMSCRIPTEN__
+struct unz_central_dir_cache_s;
+#endif
+
 /* unz_s contain internal information about the zipfile
 */
 typedef struct
 {
 	FILE* file;                 /* io structore of the zipfile */
+#ifdef __EMSCRIPTEN__
+	FILE* central_dir_file;     /* independent memory view over the shared central directory */
+	struct unz_central_dir_cache_s* central_dir_cache;
+#endif
 	unz_global_info gi;       /* public global information */
 	unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/
 	unsigned long num_file;             /* number of the current file in the zipfile*/
