diff --git a/src/main/java/de/bps/onyx/plugin/OnyxModule.java b/src/main/java/de/bps/onyx/plugin/OnyxModule.java
index 2d1a182fbafad9fc05c968b3a39d662b251f6897..2a1fb3eb116582724dcdf357249495bbcecf5b3f 100644
--- a/src/main/java/de/bps/onyx/plugin/OnyxModule.java
+++ b/src/main/java/de/bps/onyx/plugin/OnyxModule.java
@@ -27,6 +27,7 @@ import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
@@ -229,6 +230,8 @@ public class OnyxModule extends AbstractOLATModule implements ConfigOnOff {
 			} else {
 				eval.setValid(false);
 			}
+		} catch(NoSuchFileException nsfe) {
+			eval.setValid(false);
 		} catch (IOException e) {
 			log.error("", e);
 			eval.setValid(false);
diff --git a/src/main/java/org/olat/fileresource/types/FileResource.java b/src/main/java/org/olat/fileresource/types/FileResource.java
index 6b59723891211d116a3767bbff677a828b6dee1c..53e095e482817335887f78201877822d074a9e4a 100644
--- a/src/main/java/org/olat/fileresource/types/FileResource.java
+++ b/src/main/java/org/olat/fileresource/types/FileResource.java
@@ -112,13 +112,24 @@ public class FileResource implements OLATResourceable {
 		} else if(filename != null && filename.toLowerCase().endsWith(".zip")) {
 			//perhaps find root folder and return it
 			fPath = FileSystems.newFileSystem(file.toPath(), null).getPath("/");
+			RootSearcher rootSearcher = searchRootDirectory(fPath);
+			if(rootSearcher.foundRoot()) {
+				Path rootPath = rootSearcher.getRoot();
+				fPath = fPath.resolve(rootPath);
+			}
 		} else {
 			fPath = file.toPath();
 		}
-
 		return fPath;
 	}
 	
+	protected static  RootSearcher searchRootDirectory(Path fPath)
+	throws IOException {
+		RootSearcher rootSearcher = new RootSearcher();
+		Files.walkFileTree(fPath, rootSearcher);
+		return rootSearcher;
+	}
+	
 	public static boolean copyResource(File file, String filename, File targetDirectory) {
 		return copyResource(file, filename, targetDirectory, new YesMatcher());
 	}
@@ -131,13 +142,45 @@ public class FileResource implements OLATResourceable {
 			}
 			
 			Path destDir = targetDirectory.toPath();
-			Files.walkFileTree(path, new CopyVisitor(destDir, filter));
+			Files.walkFileTree(path, new CopyVisitor(path, destDir, filter));
 			return true;
 		} catch (IOException e) {
 			log.error("", e);
 			return false;
 		}
 	}
+
+	public static class RootSearcher extends SimpleFileVisitor<Path> {
+		
+		private Path root;
+		private boolean rootFound = false;
+		
+		public Path getRoot() {
+			return root;
+		}
+		
+		public boolean foundRoot() {
+			return root != null && rootFound;
+		}
+
+		@Override
+		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+		throws IOException {
+			Path tokenZero = file.getName(0);
+			if("__MACOSX".equals(tokenZero.toString()) || Files.isHidden(file)) {
+				//ignore
+			} else if(root == null) {
+				if(Files.isRegularFile(file) && file.getNameCount() > 1) {
+					root = tokenZero;
+					rootFound = true;
+				}
+			} else if(!root.equals(tokenZero)) {
+				rootFound = false;
+		        return FileVisitResult.TERMINATE;
+			}
+	        return FileVisitResult.CONTINUE;
+		}
+	}
 	
 	public static class YesMatcher implements PathMatcher {
 		@Override
@@ -147,11 +190,13 @@ public class FileResource implements OLATResourceable {
 	}
 	
 	public static class CopyVisitor extends SimpleFileVisitor<Path> {
-		
+
+		private final Path source;
 		private final Path destDir;
 		private final PathMatcher filter;
 		
-		public CopyVisitor(Path destDir, PathMatcher filter) {
+		public CopyVisitor(Path source, Path destDir, PathMatcher filter) {
+			this.source = source;
 			this.destDir = destDir;
 			this.filter = filter;
 		}
@@ -159,7 +204,8 @@ public class FileResource implements OLATResourceable {
 		@Override
 		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
 	    throws IOException {
-	        final Path destFile = Paths.get(destDir.toString(), file.toString());
+			Path relativeFile = source.relativize(file);
+	        final Path destFile = Paths.get(destDir.toString(), relativeFile.toString());
 	        if(filter.matches(file)) {
 	        	Files.copy(file, destFile, StandardCopyOption.REPLACE_EXISTING);
 	        }
@@ -169,7 +215,8 @@ public class FileResource implements OLATResourceable {
 		@Override
 		public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
 		throws IOException {
-	        final Path dirToCreate = Paths.get(destDir.toString(), dir.toString());
+			Path relativeDir = source.relativize(dir);
+	        final Path dirToCreate = Paths.get(destDir.toString(), relativeDir.toString());
 	        if(Files.notExists(dirToCreate)){
 	        	Files.createDirectory(dirToCreate);
 	        }
diff --git a/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java b/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java
index 531616c9a55a3dffd044f141ae2f2b154d52dbfd..80a2c3749f790b4f69ab4d161be651647f06c1a7 100644
--- a/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java
+++ b/src/main/java/org/olat/fileresource/types/ImsCPFileResource.java
@@ -62,30 +62,14 @@ public class ImsCPFileResource extends FileResource {
 	public ImsCPFileResource() {
 		super(TYPE_NAME);
 	}
-	
-	/**
-	 * Check for title and at least one resource.
-	 * @param unzippedDir
-	 * @return True if is of type.
-	 */
-	public static boolean validate(File unzippedDir) {
-		File fManifest = new File(unzippedDir, IMS_MANIFEST);
-		Document doc = IMSLoader.loadIMSDocument(fManifest);
-		//do not throw exception already here, as it might be only a generic zip file
-		if (doc == null) {
-			return false;
-		} else {
-			return validateImsManifest(doc);
-		}
-	}
-	
+
 	public static ResourceEvaluation evaluate(File file, String filename) {
 		ResourceEvaluation eval = new ResourceEvaluation();
 		try {
 			ImsManifestFileFilter visitor = new ImsManifestFileFilter();
 			Path fPath = PathUtils.visit(file, filename, visitor);
 			if(visitor.isValid()) {
-				Path manifestPath = fPath.resolve(IMS_MANIFEST);
+				Path manifestPath = fPath.resolve(visitor.getManifestPath());
 				Document doc = IMSLoader.loadIMSDocument(manifestPath);
 				if(validateImsManifest(doc)) {
 					eval.setValid(true);
@@ -170,6 +154,7 @@ public class ImsCPFileResource extends FileResource {
 	
 	private static class ImsManifestFileFilter extends SimpleFileVisitor<Path> {
 		private boolean manifestFile;
+		private Path manifestPath;
 
 		@Override
 		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
@@ -178,6 +163,7 @@ public class ImsCPFileResource extends FileResource {
 			String filename = file.getFileName().toString();
 			if(IMS_MANIFEST.equals(filename)) {
 				manifestFile = true;
+				manifestPath = file;
 			}
 			return manifestFile ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE;
 		}
@@ -185,5 +171,9 @@ public class ImsCPFileResource extends FileResource {
 		public boolean isValid() {
 			return manifestFile;
 		}
+		
+		public Path getManifestPath() {
+			return manifestPath;
+		}
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java b/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java
index 08bff1f5260c6096e0ea1049432597ec83ee5d37..bb7ee23ccaac1e568d3f399465c2729e119b191f 100644
--- a/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java
+++ b/src/main/java/org/olat/fileresource/types/ScormCPFileResource.java
@@ -28,6 +28,7 @@ package org.olat.fileresource.types;
 import java.io.File;
 import java.io.IOException;
 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;
@@ -67,24 +68,23 @@ public class ScormCPFileResource extends FileResource {
 		super(TYPE_NAME);
 	}
 	
-	/**
-	 * Check for title and at least one resource.
-	 * @param unzippedDir
-	 * @return True if is of type.
-	 */
-	public static boolean validate(File unzippedDir) {
-		File fManifest = new File(unzippedDir, "imsmanifest.xml");
-		Document doc = IMSLoader.loadIMSDocument(fManifest);
-		return validateImsManifest(doc);
-	}
-	
 	public static ResourceEvaluation evaluate(File file, String filename) {
 		ResourceEvaluation eval = new ResourceEvaluation();
 		try {
 			ImsManifestFileFilter visitor = new ImsManifestFileFilter();
 			Path fPath = PathUtils.visit(file, filename, visitor);
 			if(visitor.isValid()) {
-				Path manifestPath = fPath.resolve(IMS_MANIFEST);
+				Path realManifestPath = visitor.getManifestPath();
+				Path manifestPath = fPath.resolve(realManifestPath);
+				
+				RootSearcher rootSearcher = new RootSearcher();
+				Files.walkFileTree(fPath, rootSearcher);
+				if(rootSearcher.foundRoot()) {
+					manifestPath = rootSearcher.getRoot().resolve(IMS_MANIFEST);
+				} else {
+					manifestPath = fPath.resolve(IMS_MANIFEST);
+				}
+				
 				Document doc = IMSLoader.loadIMSDocument(manifestPath);
 				if(validateImsManifest(doc)) {
 					eval.setValid(true);
@@ -214,6 +214,7 @@ public class ScormCPFileResource extends FileResource {
 	
 	private static class ImsManifestFileFilter extends SimpleFileVisitor<Path> {
 		private boolean manifestFile;
+		private Path manifestPath;
 
 		@Override
 		public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
@@ -222,6 +223,7 @@ public class ScormCPFileResource extends FileResource {
 			String filename = file.getFileName().toString();
 			if(IMS_MANIFEST.equals(filename)) {
 				manifestFile = true;
+				manifestPath = file;
 			}
 			return manifestFile ? FileVisitResult.TERMINATE : FileVisitResult.CONTINUE;
 		}
@@ -229,5 +231,9 @@ public class ScormCPFileResource extends FileResource {
 		public boolean isValid() {
 			return manifestFile;
 		}
+
+		public Path getManifestPath() {
+			return manifestPath;
+		}
 	}
 }
diff --git a/src/test/java/org/olat/fileresource/FileResourceTest.java b/src/test/java/org/olat/fileresource/FileResourceTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..977724ea019581b4a52f9b8e226ca50cd805d15f
--- /dev/null
+++ b/src/test/java/org/olat/fileresource/FileResourceTest.java
@@ -0,0 +1,76 @@
+/**
+ * <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.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Path;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.olat.fileresource.types.FileResource;
+import org.olat.fileresource.types.ResourceEvaluation;
+import org.olat.fileresource.types.ScormCPFileResource;
+
+/**
+ * 
+ * Initial date: 25.07.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class FileResourceTest {
+	
+	@Test
+	public void scormPackage() throws URISyntaxException {
+		URL fileUrl = FileResourceTest.class.getResource("very_simple_scorm.zip");
+		File file = new File(fileUrl.toURI());
+		ResourceEvaluation eval = ScormCPFileResource.evaluate(file, file.getName());
+		Assert.assertTrue(eval.isValid());
+	}
+	
+	@Test
+	public void scormPackage_withinDirectory() throws URISyntaxException {
+		URL fileUrl = FileResourceTest.class.getResource("very_simple_scorm_in_directory.zip");
+		File file = new File(fileUrl.toURI());
+		ResourceEvaluation eval = ScormCPFileResource.evaluate(file, file.getName());
+		Assert.assertTrue(eval.isValid());
+	}
+	
+	@Test
+	public void scormPackage_invalid() throws URISyntaxException {
+		URL fileUrl = FileResourceTest.class.getResource("invalid_scorm.zip");
+		File file = new File(fileUrl.toURI());
+		ResourceEvaluation eval = ScormCPFileResource.evaluate(file, file.getName());
+		Assert.assertFalse(eval.isValid());
+	}
+	
+	@Test
+	public void qtiPackage() throws URISyntaxException, IOException {
+		URL fileUrl = FileResourceTest.class.getResource("qti.zip");
+		File file = new File(fileUrl.toURI());
+		Path path = FileResource.getResource(file, file.getName());
+		//must be root
+		Assert.assertEquals(0, path.getNameCount());
+	}
+
+}
diff --git a/src/test/java/org/olat/fileresource/invalid_scorm.zip b/src/test/java/org/olat/fileresource/invalid_scorm.zip
new file mode 100644
index 0000000000000000000000000000000000000000..944a1ef73d590fa77149d56c204a6f5fbe9c0987
Binary files /dev/null and b/src/test/java/org/olat/fileresource/invalid_scorm.zip differ
diff --git a/src/test/java/org/olat/fileresource/qti.zip b/src/test/java/org/olat/fileresource/qti.zip
new file mode 100644
index 0000000000000000000000000000000000000000..3709bbcc2ce21c7ce0ab1c9d9dc341af5bda0055
Binary files /dev/null and b/src/test/java/org/olat/fileresource/qti.zip differ
diff --git a/src/test/java/org/olat/fileresource/very_simple_scorm.zip b/src/test/java/org/olat/fileresource/very_simple_scorm.zip
new file mode 100644
index 0000000000000000000000000000000000000000..5703afdeed8f4f6cb69131e886ddffdaafc87983
Binary files /dev/null and b/src/test/java/org/olat/fileresource/very_simple_scorm.zip differ
diff --git a/src/test/java/org/olat/fileresource/very_simple_scorm_in_directory.zip b/src/test/java/org/olat/fileresource/very_simple_scorm_in_directory.zip
new file mode 100644
index 0000000000000000000000000000000000000000..c1757253ff1d8d4839231ab07f1ede80259c6c45
Binary files /dev/null and b/src/test/java/org/olat/fileresource/very_simple_scorm_in_directory.zip differ
diff --git a/src/test/java/org/olat/modules/coach/CoachingDAOTest.java b/src/test/java/org/olat/modules/coach/CoachingDAOTest.java
index 11c747222d3e0616a441fce0a95fd45bb366df1e..ae8b7376a095b012ba6b2f3bb4fbdba0ca6dfa5e 100644
--- a/src/test/java/org/olat/modules/coach/CoachingDAOTest.java
+++ b/src/test/java/org/olat/modules/coach/CoachingDAOTest.java
@@ -1,3 +1,22 @@
+/**
+ * <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.modules.coach;
 
 import java.io.File;
@@ -21,6 +40,12 @@ import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
 
+/**
+ * 
+ * Initial date: 24.07.2014<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
 public class CoachingDAOTest extends OlatTestCase {
 	
 	@Autowired
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index 8ea0619c5ec5fff2ada072f53390434196b7d4c5..4de668b9a2a1b49c6f8647e38d8792becfc4868b 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -93,6 +93,7 @@ import org.junit.runners.Suite;
 	org.olat.group.test.BusinessGroupRelationDAOTest.class,//ok
 	org.olat.group.test.BusinessGroupConcurrentTest.class,//ok
 	org.olat.group.test.ContactDAOTest.class,//ok
+	org.olat.fileresource.FileResourceTest.class,//ok
 	org.olat.resource.lock.pessimistic.PLockTest.class,//ok
 	org.olat.resource.references.ReferenceManagerTest.class,//ok
 	org.olat.resource.OLATResourceManagerTest.class,//ok
@@ -127,6 +128,7 @@ import org.junit.runners.Suite;
 	org.olat.modules.wiki.WikiUnitTest.class,//ok
 	org.olat.modules.wiki.versioning.diff.CookbookDiffTest.class,//ok
 	org.olat.modules.wiki.gui.components.wikiToHtml.FilterUtilTest.class,
+	org.olat.modules.coach.CoachingDAOTest.class,//ok
 	org.olat.modules.coach.CoachingServiceTest.class,//ok
 	org.olat.properties.PropertyTest.class,//ok
 	org.olat.search.service.document.file.FileDocumentFactoryTest.class,