001/* 002 * (C) Copyright 2017 Nuxeo (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Guillaume Renard <[email protected]> 018 */ 019package org.nuxeo.ecm.core.utils; 020 021import java.io.File; 022import java.io.FileOutputStream; 023import java.io.IOException; 024import java.io.InputStream; 025import java.util.Collection; 026import java.util.HashSet; 027import java.util.List; 028import java.util.zip.ZipOutputStream; 029 030import org.nuxeo.common.utils.StringUtils; 031import org.nuxeo.common.utils.ZipUtils; 032import org.nuxeo.ecm.core.api.Blob; 033import org.nuxeo.ecm.core.api.Blobs; 034import org.nuxeo.runtime.api.Framework; 035 036/** 037 * Blob utility methods. 038 * 039 * @since 9.3 040 */ 041public class BlobUtils { 042 043 public static enum ZIP_ENTRY_ENCODING_OPTIONS { 044 ascii 045 } 046 047 public static final String ZIP_ENTRY_ENCODING_PROPERTY = "zip.entry.encoding"; 048 049 protected static String escapeEntryPath(String path) { 050 String zipEntryEncoding = Framework.getProperty(ZIP_ENTRY_ENCODING_PROPERTY); 051 if (zipEntryEncoding != null && zipEntryEncoding.equals(ZIP_ENTRY_ENCODING_OPTIONS.ascii.toString())) { 052 return StringUtils.toAscii(path, true); 053 } 054 return path; 055 } 056 057 protected static String getFileName(Blob blob) { 058 String entry = blob.getFilename(); 059 if (entry == null) { 060 entry = "Unknown_" + System.identityHashCode(blob); 061 } 062 return escapeEntryPath(entry); 063 } 064 065 /** 066 * Zip the given blob. 067 * 068 * @param blob the blob 069 * @param filename if no filename is given, the blob's filename will be used 070 * @return a zip containing the blob 071 * @throws IOException 072 */ 073 public static Blob zip(Blob blob, String filename) throws IOException { 074 if (filename == null || (filename = filename.trim()).length() == 0) { 075 filename = blob.getFilename(); 076 } 077 File file = Framework.createTempFile("nxops-createzip-", ".tmp"); 078 ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file)); 079 Framework.trackFile(file, file); 080 try { 081 zip(blob, out); 082 } finally { 083 out.finish(); 084 out.close(); 085 } 086 return Blobs.createBlob(file, "application/zip", null, filename); 087 } 088 089 protected static void zip(Blob blob, ZipOutputStream out) throws IOException { 090 String entry = getFileName(blob); 091 InputStream in = blob.getStream(); 092 try { 093 ZipUtils._zip(entry, in, out); 094 } finally { 095 in.close(); 096 } 097 } 098 099 /** 100 * Zip a list of blob. 101 * 102 * @param blobs the blob list 103 * @param fileName if no filename is given, the first blob's filename will be used 104 * @return a zip containing the list of blob 105 * @throws IOException 106 */ 107 public static Blob zip(List<Blob> blobs, String fileName) throws IOException { 108 if (fileName == null || (fileName = fileName.trim()).length() == 0) { 109 fileName = blobs.isEmpty() ? null : blobs.get(0).getFilename(); 110 } 111 File file = Framework.createTempFile("nxops-createzip-", ".tmp"); 112 ZipOutputStream out = new ZipOutputStream(new FileOutputStream(file)); 113 Framework.trackFile(file, file); 114 try { 115 zip(blobs, out); 116 } finally { 117 out.finish(); 118 out.close(); 119 } 120 return Blobs.createBlob(file, "application/zip", null, fileName); 121 } 122 123 protected static void zip(List<Blob> blobs, ZipOutputStream out) throws IOException { 124 // use a set to avoid zipping entries with same names 125 Collection<String> names = new HashSet<String>(); 126 int cnt = 1; 127 for (Blob blob : blobs) { 128 String entry = getFileName(blob); 129 if (!names.add(entry)) { 130 entry = "renamed_" + (cnt++) + "_" + entry; 131 } 132 InputStream in = blob.getStream(); 133 try { 134 ZipUtils._zip(entry, in, out); 135 } finally { 136 in.close(); 137 } 138 } 139 } 140 141}