Skip to content

Commit

Permalink
Refactoring extraction as plain files and as zip
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelschoen committed Mar 30, 2018
1 parent bcb2de0 commit bd359ea
Show file tree
Hide file tree
Showing 34 changed files with 209 additions and 2,815 deletions.
32 changes: 30 additions & 2 deletions README.md
Expand Up @@ -31,12 +31,32 @@ VirtualDirectory root = stDisk.getRootContents();
root.getContents().forEach(f -> System.out.println("Entry: " + f.getName() + ", is file: " + f.isFile()));
```

Then extract the contents with
Then extract the contents into the local filesystem with

```
handler.extractImage(stDisk, new File("/tmp/"));
stDisk.exportToDirectory(new File("/tmp", "unpacked"));
```

Or export then into a .zip archive with

```
stDisk.exportAsZip(new File("/tmp", stDisk.getName() + ".zip"));
```

or send the zip to any output stream with

```
stDisk.exportAsZip(new FileOutputStream("/tmp/stuff.zip"));
```

Get the contents of a single "VirtualFile" file entry with "getContents()":

```
VirtualFile entry = ...
byte[] fileContents = entry.getContents().array();
```


## Credits

* https://github.com/waldheinz/fat32-lib - Great library for processing FAT images (DOS and Atari ST).
Expand Down Expand Up @@ -81,3 +101,11 @@ Then run the extractor tool with this command:
```
$ java -jar build\libs\retro-io-1.0-SNAPSHOT-all.jar
````

### Install to local Maven repository

To build the library and install it in your local Maven repository, run

```
$ gradle publishToMavenLocal
```
11 changes: 11 additions & 0 deletions build.gradle
Expand Up @@ -39,6 +39,17 @@ jar {
}
}

publishing {
publications {
mavenJava(MavenPublication) {
from components.java
}
}
repositories {
mavenLocal()
}
}

dependencies {
testCompile group: 'org.hamcrest', name: 'hamcrest-core', version: '1.3'
testCompile group: 'junit', name: 'junit-dep', version: '4.10'
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/org/retro/common/ExtractorTool.java
Expand Up @@ -191,9 +191,9 @@ protected void extractToFile(boolean toZip){
try {
currentTargetDirectory = chooser.getSelectedFile();
if(toZip) {
handler.extractInZipArchive(currentDisk, currentTargetDirectory);
currentDisk.exportAsZip(currentTargetDirectory);
} else {
handler.extractVirtualDisk(currentDisk, currentTargetDirectory);
currentDisk.exportToDirectory(currentTargetDirectory);
}
} catch(Exception e) {
e.printStackTrace();
Expand Down
21 changes: 0 additions & 21 deletions src/main/java/org/retro/common/ImageHandler.java
@@ -1,7 +1,5 @@
package org.retro.common;

import java.io.File;

/**
* Interface for classes that can read (and potentially write)
* a certain type of retro floppy disk image file.
Expand Down Expand Up @@ -30,23 +28,4 @@ public interface ImageHandler {
* @throws VirtualDiskException If the image file could not be created.
*/
void writeImage(VirtualDisk virtualDisk, java.io.File imageFile) throws VirtualDiskException;

/**
* Extracts the contents of a given virtual disk into a target directory.
*
* @param disk The virtual disk to extract.
* @param targetDirectory The target directory (will be created, with all parents, if necessary).
* @throws VirtualDiskException If the files could not be extracted.
*/
void extractVirtualDisk(VirtualDisk disk, java.io.File targetDirectory) throws VirtualDiskException;

/**
* Extracts the contents of a given virtual disk into a target ZIP archive. The top-level directory
* in the ZIP file usually has the same name as the original floppy disk image, minus its suffix.
*
* @param disk The virtual disk to extract.
* @param target The target ZIP archive (target's directory will be created, with all parents, if necessary).
* @throws VirtualDiskException If the files could not be extracted.
*/
void extractInZipArchive(VirtualDisk disk, File target) throws VirtualDiskException;
}
14 changes: 13 additions & 1 deletion src/main/java/org/retro/common/VirtualDisk.java
@@ -1,10 +1,22 @@
package org.retro.common;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

public interface VirtualDisk {

String getName();

VirtualDirectory getRootContents() throws VirtualDiskException;
VirtualDirectory getRootContents();

ImageType getType();

ImageHandler getHandler();

void exportToDirectory(File targetDirectory) throws IOException;

void exportAsZip(File zipFile) throws IOException;

void exportAsZip(OutputStream target) throws IOException;
}
15 changes: 15 additions & 0 deletions src/main/java/org/retro/common/VirtualFile.java
@@ -1,6 +1,7 @@
package org.retro.common;

import java.nio.ByteBuffer;
import java.util.UUID;

/**
* Represents a single file (or directory).
Expand All @@ -18,13 +19,17 @@ public class VirtualFile implements Comparable<VirtualFile> {
/** The file content (can be empty buffer). */
private ByteBuffer content = ByteBuffer.allocate(0);

/** The unique identifier for this file. */
private String uuid;

/**
* Creates a file.
*
* @param name The name of this file.
*/
public VirtualFile(String name) {
this.name = name;
this.uuid = UUID.randomUUID().toString();
}

/**
Expand All @@ -39,6 +44,16 @@ public VirtualFile(VirtualDirectory parent, String name) {
parent.addFile(this);
}

/**
* UUID that uniquely identifies this file. This is generated randomly
* every time the file is read from a floppy disk image.
*
* @return The UUID of this file.
*/
public String getUuid() {
return this.uuid;
}

/**
* Returns the full path filename of this file, i.e.
* the name of the file preceeded by all parent directories.
Expand Down
97 changes: 4 additions & 93 deletions src/main/java/org/retro/common/impl/AbstractBaseImageHandler.java
@@ -1,15 +1,12 @@
package org.retro.common.impl;

import org.apache.commons.io.IOUtils;
import org.retro.common.*;
import org.retro.common.ImageHandler;
import org.retro.common.VirtualDisk;
import org.retro.common.VirtualDiskException;
import org.retro.common.VirtualFile;

import java.io.*;
import java.net.URI;
import java.nio.file.FileSystem;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* Abstract base class with some common functionality for
Expand All @@ -32,92 +29,6 @@ public void writeImage(VirtualDisk virtualDisk, File imageFile) throws VirtualDi
throw new VirtualDiskException("*not implemented*");
}

/**
* Extracts the contents of the given virtual disk into the
* specified target directory. The target directory is created
* (with all required parent directories) if it does not exist yet.
*
* @param disk The disk that should be extracted.
* @param targetDirectory The target directory to receive the extracted content.
* @throws VirtualDiskException If the extraction failed.
*/
@Override
public void extractVirtualDisk(VirtualDisk disk, java.io.File targetDirectory) throws VirtualDiskException {
targetDirectory.mkdirs();
if(!targetDirectory.exists() || targetDirectory.isFile() || !targetDirectory.canWrite()) {
throw new VirtualDiskException("Failed to create / write to directory: " + targetDirectory.getAbsolutePath());
}
VirtualDirectory root = disk.getRootContents();
extractDirectory(root, targetDirectory);
}

@Override
public void extractInZipArchive(VirtualDisk disk, File targetDirectory) throws VirtualDiskException {
Map<String, String> env = new HashMap<>();
env.put("create", "true");

targetDirectory.mkdirs();
System.out.println("Target directory: " + targetDirectory.getAbsolutePath());
String targetFileName = disk.getName() + ".zip";
System.out.println("Target zip file name: " + targetFileName);
File targetZipFile = new File(targetDirectory, targetFileName);
System.out.println("Target zip file: " + targetZipFile.getAbsolutePath());
try {
String zipUriName = targetZipFile.getCanonicalPath().replace(File.separatorChar, '/');
URI uri = URI.create("jar:file:///" + zipUriName);
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
Path pathInZipfile = zipfs.getPath(disk.getName());
Files.createDirectories(pathInZipfile);
extractToZip(zipfs, disk.getRootContents(), disk.getName());
}
} catch(IOException e) {
throw new VirtualDiskException("Failed to extract file to ZIP: " + targetZipFile.getAbsolutePath()
+ ", reason: " + e, e);
}
}

/**
* Extracts the virtual disk contents into a ZIP archive file.
*
* @param zipfs The ZIP filesystem to extract the contents to.
* @param directory The directory with the files to extract.
* @param zipRootPrefix The root directory in the ZIP; usually the original disk image's filename without suffix.
* @throws IOException If the ZIP file could not be created.
*/
private void extractToZip(FileSystem zipfs, VirtualDirectory directory, String zipRootPrefix) throws IOException {
for (VirtualFile entry : directory.getContents()) {
Path pathInZipfile = zipfs.getPath("/" + zipRootPrefix + entry.getFullName());
if (entry.isFile()) {
Files.copy(new ByteArrayInputStream(entry.getContent().array()), pathInZipfile,
StandardCopyOption.REPLACE_EXISTING);
} else {
Files.createDirectories(pathInZipfile);
extractToZip(zipfs, (VirtualDirectory)entry, zipRootPrefix);
}
}
}

/**
* Extracts the given directory's contents to the target directory.
*
* @param virtualVirtualDirectory The directory that must be extracted.
* @param targetDirectory The target directory for the extracted data.
* @throws VirtualDiskException If the extraction failed.
*/
private void extractDirectory(VirtualDirectory virtualVirtualDirectory, File targetDirectory) throws VirtualDiskException {
Iterator<VirtualFile> files = virtualVirtualDirectory.iterator();
while(files.hasNext()) {
VirtualFile file = files.next();
if(file.isDirectory()) {
File newTargetDirectory = new File(targetDirectory, replaceBadChars(file.getName()));
newTargetDirectory.mkdirs();
extractDirectory((VirtualDirectory)file, newTargetDirectory);
} else {
extractFile(file, targetDirectory);
}
}
}

/**
* Extracts the given file to the target directory.
*
Expand Down

0 comments on commit bd359ea

Please sign in to comment.