Created
September 7, 2010 11:52
-
-
Save m92o/568214 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ipa2epub.scala | |
// usage: scala ipa2epub.scala src.ipa [dst.epub] | |
// TODO: error handling | |
import java.io.{ File, FileInputStream, FileOutputStream, BufferedInputStream } | |
import java.util.zip.{ ZipFile, ZipEntry, ZipOutputStream, CRC32 } | |
import scala.util.matching.Regex | |
val TopDir = "Payload" | |
def die(message: String) { | |
println(message) | |
exit(1) | |
} | |
def unzip(path: String): Option[String] = { | |
var result: Option[String] = None | |
val regex = new Regex("^" + TopDir + "/.+\\.app/book/") | |
val zip = new ZipFile(path) | |
val files = zip.entries | |
while (files.hasMoreElements) { | |
val file = files.nextElement | |
val name = file.getName | |
val base = regex.findPrefixOf(name) | |
if (base != None) { | |
if (file.isDirectory) | |
new File(name).mkdirs | |
else { | |
val in = new BufferedInputStream(zip.getInputStream(file)) | |
val out = new FileOutputStream(name) | |
val buf = new Array[Byte](1024) | |
var len = in.read(buf) | |
while (len != -1) { | |
out.write(buf, 0, len) | |
len = in.read(buf) | |
} | |
in.close | |
out.close | |
} | |
result = base; | |
} | |
} | |
zip.close | |
result | |
} | |
def zip(path: String, base: String): Option[String] = { | |
var result: Option[String] = None | |
val file = new File(path) | |
val out = new ZipOutputStream(new FileOutputStream(file)) | |
if (archive(out, base, new File(base + "mimetype"), false)) | |
if (archive(out, base, new File(base + "META-INF"), true)) | |
if (archive(out, base, new File(base + "OEBPS"), true)) | |
result = Some(file.getPath) | |
out.close | |
result | |
} | |
def archive(out: ZipOutputStream, base: String, path: File, deflate: Boolean): Boolean = { | |
val result = path.exists | |
if (result) { | |
if (path.isDirectory) | |
path.listFiles.foreach(file => archive(out, base, file, deflate)) | |
else { | |
val len = path.length.toInt | |
val buf = new Array[Byte](len) | |
val in = new BufferedInputStream(new FileInputStream(path)) | |
in.read(buf, 0, len) | |
in.close | |
val file = new ZipEntry(("^" + base).r.replaceFirstIn(path.getPath, "")) | |
if (deflate == false) { | |
// MUST: setCrc before putNextEntry | |
val crc = new CRC32() | |
crc.update(buf) | |
file.setMethod(ZipEntry.STORED) | |
file.setSize(len) | |
file.setCrc(crc.getValue) | |
} | |
out.putNextEntry(file) | |
out.write(buf, 0, len) | |
out.closeEntry | |
} | |
} | |
result | |
} | |
def clean(path: File) { | |
if (path.isDirectory) | |
path.listFiles.foreach(clean) | |
path.delete | |
} | |
// main | |
val src = if (args.length > 0) args(0) else null | |
if (src == null || new File(src).exists == false) die("usage: scala ipa2epub.scala src.ipa [dst.epub]") | |
val dst = if (args.length > 1) args(1) else "\\w+$".r.replaceFirstIn(new File(src).getName, "epub") | |
val base = unzip(src) | |
if (base == None) die("No book found in the archive") | |
val top = new File(TopDir) | |
if (zip(dst, base.get) == None) die("No contents found in the archive") | |
clean(top) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment