ZipUtilities.java

/*
 * GovWay - A customizable API Gateway 
 * https://govway.org
 * 
 * Copyright (c) 2005-2024 Link.it srl (https://link.it). 
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3, as published by
 * the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */


package org.openspcoop2.utils.io;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import org.openspcoop2.utils.UtilsException;
import org.openspcoop2.utils.resources.FileSystemUtilities;

/**
 * ZipUtilities
 *
 *
 * @author Poli Andrea (apoli@link.it)
 * @author $Author$
 * @version $Rev$, $Date$
 */
public class ZipUtilities {

	public static byte[] zip(byte[] content,String name) throws UtilsException{
		try {
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			ZipOutputStream zipOut = new ZipOutputStream(bout);
			ByteArrayInputStream bin = new ByteArrayInputStream(content);
			ZipEntry zipEntry = new ZipEntry(name);
			zipOut.putNextEntry(zipEntry);
			zipOut.write(content);
			zipOut.flush();
			zipOut.close();
			bin.close();
			bout.flush();
			bout.close();
			return bout.toByteArray();
		}catch(Exception e){
			throw new UtilsException("Errore durante la scrittura dello zip: "+e.getMessage(),e);
		}
	}
	
	public static byte[] zip(List<Entry> entries) throws UtilsException{
		try {
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			ZipOutputStream zipOut = new ZipOutputStream(bout);
			
			for (Entry entry : entries) {
				String name = entry.getName();
				ZipEntry zipEntry = new ZipEntry(name);
				zipOut.putNextEntry(zipEntry);
				zipOut.write(entry.getContent());
			}
			
			zipOut.flush();
			zipOut.close();
			bout.flush();
			bout.close();
			return bout.toByteArray();
		}catch(Exception e){
			throw new UtilsException("Errore durante la scrittura dello zip: "+e.getMessage(),e);
		}
	}
	
	public static byte[] unzip(byte[] zipContent) throws UtilsException{
		try {
			ByteArrayOutputStream bout = new ByteArrayOutputStream();
			ByteArrayInputStream bin = new ByteArrayInputStream(zipContent);
			ZipInputStream zis = new ZipInputStream(bin);
			int count = 0;
			ZipEntry zipEntry = zis.getNextEntry();
	        while(zipEntry != null){
	        	count++;
	        	if(count>1) {
	        		throw new UtilsException("Errore, il metodo supporta solamente archivi zip contenente un file");
	        	}
	        	int len;
	        	byte[] buffer = new byte[1024];
	            while ((len = zis.read(buffer)) > 0) {
	            	bout.write(buffer, 0, len);
	            }
	            zipEntry = zis.getNextEntry();
	        }
	        zis.closeEntry();
	        zis.close();
	        bout.flush();
	        bout.close();
	        bin.close();
	        return bout.toByteArray();
		}catch(Exception e){
			throw new UtilsException("Errore durante la lettura dello zip: "+e.getMessage(),e);
		}
	}

	public static List<Entry> read(byte[] zipContent) throws UtilsException{
		try {
			List<Entry> list = new ArrayList<>();
			
			ByteArrayInputStream in = new ByteArrayInputStream(zipContent);
			ZipInputStream zipIn = new ZipInputStream(in);
		    ZipEntry entry;
		    while ((entry = zipIn.getNextEntry()) != null) {
		        String name = entry.getName();
		    	//System.out.println(name);
		        
		        if(name!=null && !( name.endsWith("/") || name.endsWith("\\") ) ){
		        	Entry zentry = new Entry();
	        		zentry.setName(name);
	        		
	        		ByteArrayOutputStream bout = new ByteArrayOutputStream();
	        		byte contents[] = new byte[4096];
	        		int direct;
	        		while ((direct = zipIn.read(contents, 0, contents.length)) >= 0) {
	        			//System.out.println("Read " + direct + "bytes content.");
	        			bout.write(contents, 0, direct);
	        		}
	        		bout.flush();
	        		bout.close();
	        		
	        		zentry.setContent(bout.toByteArray());
	        		list.add(zentry);
		        }
		        
		        zipIn.closeEntry();
		    }
		    zipIn.close();
		    in.close();

	        return list;
	        
		}catch(Exception e){
			throw new UtilsException("Errore durante la lettura dello zip: "+e.getMessage(),e);
		}
	}

	
	public static String getRootDir(String entry) throws UtilsException{
		try{
			String rootDir = null;
			String dir = entry;
			int indexOf=dir.indexOf(File.separatorChar);
			if(indexOf<=0){
				throw new UtilsException("Errore durante l'identificazione della directory radice presente all'interno dello zip ("+indexOf+")");
			}
			dir = dir.substring(0,indexOf);
			if(dir==null || "".equals(dir)){
				throw new UtilsException("Errore durante l'identificazione della directory radice presente all'interno dello zip ("+dir+")");
			}
			rootDir=dir+File.separatorChar;
			return rootDir;
		}catch(UtilsException ex){
			throw ex;
		}catch(Exception e){
			throw new UtilsException("Errore durante l'identificazione della directory radice presente all'interno dello zip: "+e.getMessage(),e);
		}
	}
	
	public static String getBaseName(String file) throws UtilsException{
		try{
			return (new File(file)).getName();
		}catch(Exception e){
			throw new UtilsException("Errore durante l'identificazione del base name per il file ["+file+"]: "+e.getMessage(),e);
		}
	}
	
	public static String operativeSystemConversion(String entryName){

		char separatorCharWindows = '\\';
		char separatorCharLinux = '/';
		boolean isWindows =  (File.separatorChar == separatorCharWindows);
		
		StringBuilder fixed = new StringBuilder(entryName);
		for( int i = 0; i<fixed.length(); i++){
			
			if(isWindows){
				// se siamo su windows converto tutti i path "linux" in windows mode
				if(fixed.charAt(i) == separatorCharLinux){ 
					fixed.setCharAt(i, File.separatorChar);
				}
			}
			else{
				// se siamo su linux converto tutti i path "windows" in linux mode
				if(fixed.charAt(i) == separatorCharWindows){ 
					fixed.setCharAt(i, File.separatorChar);
				}
			}
			
		}
		
		//System.out.println("Convertito per Windows: "+isWindows);
		
		return fixed.toString();
	}
	
	public static void unzipFile(String zipFile,String dest) throws UtilsException {
		try{
			File destFile = new File(dest);
			if(destFile.exists()==false){
				if(destFile.mkdir()==false){
					throw new Exception("Destinazione ["+dest+"] non esistente e creazione non riuscita");
				}
			}else{
				if(destFile.isDirectory()==false){
					throw new Exception("Destinazione ["+dest+"] non e' una directory");
				}
				if(destFile.canWrite()==false){
					throw new Exception("Destinazione ["+dest+"] non accessibile in scrittura ");
				}
			}

			OutputStream out = null;
			InputStream iZip = null;
			ZipFile zf = null;
			try{
				zf = new ZipFile(zipFile);
				for(Enumeration<?> em = zf.entries(); em.hasMoreElements();){
					ZipEntry ze = (ZipEntry) em.nextElement();
					String targetfile = destFile.getAbsolutePath()+File.separatorChar+ze.getName();

					// Parent
					FileSystemUtilities.mkdirParentDirectory(targetfile);
					
					// File
					if(ze.getName()!=null && ( ze.getName().endsWith("/") || ze.getName().endsWith("\\") ) ){
						
						// Directory
						File fDir = new File(targetfile);
						if(fDir.mkdir()==false){
							try{
								throw new Exception("Creazione directory ["+fDir.getAbsolutePath()+"] per entry ["+ze.getName()+"] non riuscita");
							}finally{
								try{
									if(zf!=null){
										zf.close();
									}
								}catch(Exception eClose){
									// close
								}
							}
						}
				
					}
					else{

						// Creo file
						iZip = zf.getInputStream(ze);			
						out = new FileOutputStream(targetfile);
						byte[] buf = new byte[1024];
						int len;
						while ((len = iZip.read(buf)) > 0) {
							out.write(buf, 0, len);
						}
						iZip.close();
						iZip = null;
						out.flush();
						out.close();
						out = null;
						
					}
				}
			}finally{
				try{
					if(out!=null){
						out.close();
					}
				}catch(Exception eClose){}
				try{
					if(iZip!=null){
						iZip.close();
					}
				}catch(Exception eClose){}
				try{
					if(zf!=null){
						zf.close();
					}
				}catch(Exception eClose){
					// close
				}
			}

		}catch(Exception e){
			throw new UtilsException("Unzip non riuscito: "+e.getMessage(),e);
		}
	}
	
	public static Iterator<ZipEntry> entries(ZipFile zip,boolean ascOrder){
		
		// L'Enumeration ritornato dal metodo standard java.util.zip.ZipFile.entries() 
		// attraversa le entries presenti nello zip nello stesso ordine in cui sono state salvate.
		
		List<String> entryNames = new ArrayList<>();
		Map<String, ZipEntry> map = new HashMap<String, ZipEntry>();
		Enumeration<?> e = zip.entries();
		while(e.hasMoreElements()) {
			ZipEntry zipEntry = (ZipEntry)e.nextElement();
			String entryName = zipEntry.getName();
			entryNames.add(entryName);
			map.put(entryName, zipEntry);
		}
		
		if(ascOrder){
			java.util.Collections.sort(entryNames);
		}
		else{
			java.util.Collections.sort(entryNames,Collections.reverseOrder());
		}
		
		List<ZipEntry> zipEntries = new ArrayList<ZipEntry>();
		for (String entry : entryNames) {
			zipEntries.add(map.remove(entry));
		}
		return zipEntries.iterator();
	}
	
}