diff --git a/src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java b/src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java
new file mode 100644
index 0000000000000000000000000000000000000000..d0c2d9ed17beb2e91f89536303b128e034fc61bd
--- /dev/null
+++ b/src/main/java/org/olat/fileresource/ZippedDirectoryMediaResource.java
@@ -0,0 +1,118 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.fileresource;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.olat.core.gui.media.MediaResource;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.FileUtils;
+import org.olat.core.util.StringHelper;
+
+/**
+ * 
+ * Initial date: 20.01.2015<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class ZippedDirectoryMediaResource implements MediaResource {
+	
+	private static final OLog log = Tracing.createLoggerFor(ZippedDirectoryMediaResource.class);
+	
+	private final String filename;
+	private final File unzipDir;
+	
+	public ZippedDirectoryMediaResource(String filename, File unzipDir) {
+		this.filename = filename;
+		this.unzipDir = unzipDir;
+	}
+
+	@Override
+	public String getContentType() {
+		return "application/zip";
+	}
+
+	@Override
+	public Long getSize() {
+		return null;
+	}
+
+	@Override
+	public InputStream getInputStream() {
+		return null;
+	}
+
+	@Override
+	public Long getLastModified() {
+		return null;
+	}
+
+	@Override
+	public void prepare(HttpServletResponse hres) {
+		String label = StringHelper.transformDisplayNameToFileSystemName(filename) + ".zip";
+		String urlEncodedLabel = StringHelper.urlEncodeUTF8(label);
+		hres.setHeader("Content-Disposition","attachment; filename*=UTF-8''" + urlEncodedLabel);			
+		hres.setHeader("Content-Description", urlEncodedLabel);
+		
+		try(ZipOutputStream zout = new ZipOutputStream(hres.getOutputStream())) {
+			zout.setLevel(9);
+			
+			final Path unzipPath = unzipDir.toPath();
+			Files.walkFileTree(unzipPath, new SimpleFileVisitor<Path>() {
+				@Override
+				public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+					if(!attrs.isDirectory()) {
+						Path relativeFile = unzipPath.relativize(file);
+						String names = relativeFile.toString();
+						zout.putNextEntry(new ZipEntry(names));
+						
+						try(InputStream in=Files.newInputStream(file)) {
+							FileUtils.copy(in, zout);
+						} catch (Exception e) {
+							log.error("", e);
+						}
+						
+						zout.closeEntry();
+					}
+					return FileVisitResult.CONTINUE;
+				}
+			});
+		} catch (Exception e) {
+			log.error("", e);
+		}
+	}
+
+	@Override
+	public void release() {
+		//
+	}
+}
diff --git a/src/main/java/org/olat/ims/cp/CPManagerImpl.java b/src/main/java/org/olat/ims/cp/CPManagerImpl.java
index d57bd5047f854bbc40abc02982cdd2ac334d7c0e..0d1695f690af476d1b369d6276a3abdf1a40ba73 100644
--- a/src/main/java/org/olat/ims/cp/CPManagerImpl.java
+++ b/src/main/java/org/olat/ims/cp/CPManagerImpl.java
@@ -176,7 +176,6 @@ public class CPManagerImpl extends CPManager {
 			File cpRoot = FileResourceManager.getInstance().unzipFileResource(ores);
 			logDebug("createNewCP: cpRoot=" + cpRoot);
 			logDebug("createNewCP: cpRoot.getAbsolutePath()=" + cpRoot.getAbsolutePath());
-			System.out.println("createNewCP: cpRoot.getAbsolutePath()=" + cpRoot.getAbsolutePath());
 			LocalFolderImpl vfsWrapper = new LocalFolderImpl(cpRoot);
 			ContentPackage cp = load(vfsWrapper, ores);
 
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java
index fbffb2db92415de2879429b91c8a45de726eb1a6..3db84d3a09c67b17bec5f0c78b3e6a6c54d6a87c 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTISurveyHandler.java
@@ -36,9 +36,11 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
+import org.olat.fileresource.FileResourceManager;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.ims.qti.QTIRuntimeController;
 import org.olat.ims.qti.editor.QTIEditorMainController;
@@ -102,6 +104,11 @@ public class QTISurveyHandler extends QTIHandler {
 		return super.importResource(initialAuthor, displayname, description, new SurveyFileResource(), file, filename);
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return SurveyFileResource.TYPE_NAME;
diff --git a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java
index 358f795232f0d4e1c6c03d37b64ce2d9abd9c1b1..247818a4117a508514a37994740f2cc48587e675 100644
--- a/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java
+++ b/src/main/java/org/olat/ims/qti/repository/handlers/QTITestHandler.java
@@ -36,9 +36,11 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
+import org.olat.fileresource.FileResourceManager;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.ims.qti.QTIRuntimeController;
 import org.olat.ims.qti.editor.QTIEditorMainController;
@@ -102,6 +104,11 @@ public class QTITestHandler extends QTIHandler {
 		return super.importResource(initialAuthor, displayname, description, new TestFileResource(), file, filename);
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return TestFileResource.TYPE_NAME;
diff --git a/src/main/java/org/olat/repository/handlers/FileHandler.java b/src/main/java/org/olat/repository/handlers/FileHandler.java
index e36108471a7e8b231de27e06843616032097f203..0b22fe8f133c9a69e7fb062b18775a7f1a91afe0 100644
--- a/src/main/java/org/olat/repository/handlers/FileHandler.java
+++ b/src/main/java/org/olat/repository/handlers/FileHandler.java
@@ -55,11 +55,6 @@ public abstract class FileHandler implements RepositoryHandler {
 		//
 	}
 
-	@Override
-	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
-		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
-	}
-	
 	@Override
 	public VFSContainer getMediaContainer(RepositoryEntry repoEntry) {
 		return FileResourceManager.getInstance()
diff --git a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
index 16fce20e36ce74d145f271fad9aa94d380c4ab10..da69365f02ac1cf0d2523107bdb934e6ba95a2d4 100644
--- a/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/ImsCPHandler.java
@@ -41,6 +41,7 @@ import org.olat.core.gui.control.generic.iframe.DeliveryOptions;
 import org.olat.core.gui.control.generic.layout.MainLayout3ColumnsController;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
@@ -54,6 +55,7 @@ import org.olat.core.util.vfs.QuotaManager;
 import org.olat.core.util.vfs.callbacks.FullAccessWithQuotaCallback;
 import org.olat.core.util.vfs.callbacks.VFSSecurityCallback;
 import org.olat.fileresource.FileResourceManager;
+import org.olat.fileresource.ZippedDirectoryMediaResource;
 import org.olat.fileresource.types.FileResource;
 import org.olat.fileresource.types.ImsCPFileResource;
 import org.olat.fileresource.types.ResourceEvaluation;
@@ -65,6 +67,7 @@ import org.olat.ims.cp.ui.CPRuntimeController;
 import org.olat.modules.cp.CPDisplayController;
 import org.olat.modules.cp.CPOfflineReadableManager;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.repository.ui.RepositoryEntryRuntimeController.RuntimeControllerCreator;
@@ -155,6 +158,14 @@ public class ImsCPHandler extends FileHandler {
 		return target;
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		File unzippedDir = FileResourceManager.getInstance().unzipFileResource(res);
+		String displayName = CoreSpringFactory.getImpl(RepositoryManager.class)
+				.lookupDisplayNameByOLATResourceableId(res.getResourceableId());
+		return new ZippedDirectoryMediaResource(displayName, unzippedDir);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return ImsCPFileResource.TYPE_NAME;
diff --git a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
index 7cc65dd5c37701b77e29fdbad621ad8c77d9b8f1..ac6ac06256ab33649afb75936e1da65e3ef78212 100644
--- a/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
+++ b/src/main/java/org/olat/repository/handlers/SCORMCPHandler.java
@@ -36,6 +36,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
@@ -43,6 +44,7 @@ import org.olat.core.logging.activity.ThreadLocalUserActivityLogger;
 import org.olat.core.util.FileUtils;
 import org.olat.core.util.coordinate.LockResult;
 import org.olat.fileresource.FileResourceManager;
+import org.olat.fileresource.ZippedDirectoryMediaResource;
 import org.olat.fileresource.types.FileResource;
 import org.olat.fileresource.types.ResourceEvaluation;
 import org.olat.fileresource.types.ScormCPFileResource;
@@ -50,6 +52,7 @@ import org.olat.modules.scorm.ScormMainManager;
 import org.olat.modules.scorm.ScormPackageConfig;
 import org.olat.modules.scorm.ScormRuntimeController;
 import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryManager;
 import org.olat.repository.RepositoryService;
 import org.olat.repository.model.RepositoryEntrySecurity;
 import org.olat.repository.ui.RepositoryEntryRuntimeController.RuntimeControllerCreator;
@@ -127,6 +130,14 @@ public class SCORMCPHandler extends FileHandler {
 		}
 		return target;
 	}
+	
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		File unzippedDir = FileResourceManager.getInstance().unzipFileResource(res);
+		String displayName = CoreSpringFactory.getImpl(RepositoryManager.class)
+				.lookupDisplayNameByOLATResourceableId(res.getResourceableId());
+		return new ZippedDirectoryMediaResource(displayName, unzippedDir);
+	}
 
 	@Override
 	public String getSupportedType() {
diff --git a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
index 6b14372bc221f022dec8b845a7ca6febdd41907b..0ad4cdc410c91877a50c81c38fb32f58f8af81ec 100644
--- a/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
+++ b/src/main/java/org/olat/repository/handlers/WebDocumentHandler.java
@@ -39,6 +39,7 @@ import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.gui.control.generic.wizard.StepsMainRunController;
+import org.olat.core.gui.media.MediaResource;
 import org.olat.core.id.Identity;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
@@ -186,6 +187,11 @@ public class WebDocumentHandler extends FileHandler {
 		return target;
 	}
 
+	@Override
+	public MediaResource getAsMediaResource(OLATResourceable res, boolean backwardsCompatible) {
+		return FileResourceManager.getInstance().getAsDownloadeableMediaResource(res);
+	}
+
 	@Override
 	public String getSupportedType() {
 		return supportedType;