/*
* Copyright (C) 2011 Alex Kuiper
*
* This file is part of PageTurner
*
* PageTurner is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* PageTurner is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PageTurner. If not, see <http://www.gnu.org/licenses/>.*
*/
package net.nightwhistler.pageturner.epub;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* This is mostly a performance utility:
*
* We don't want to load all the images from an
* EPUB at once, but lazy-loading several images
* and opening the file for each is too slow.
*
* The image loader allows a class to register call-backs
* so several images can be loaded in a single go.
*
* @author Alex Kuiper
*
*/
public class ResourceLoader {
private String fileName;
private static final Logger LOG = LoggerFactory.getLogger("ResourceLoader");
public ResourceLoader(String fileName) {
this.fileName = fileName;
}
public static interface ResourceCallback {
void onLoadResource( String href, InputStream stream );
}
private class Holder {
String href;
ResourceCallback callback;
}
private List<Holder> callbacks = new ArrayList<>();
public void clear() {
this.callbacks.clear();
}
public void load() throws IOException {
ZipFile zipFile = null;
try {
zipFile = new ZipFile(this.fileName);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while( entries.hasMoreElements() ) {
ZipEntry zipEntry = entries.nextElement();
if(zipEntry.isDirectory()) {
continue;
}
String href = zipEntry.getName();
List<ResourceCallback> filteredCallbacks = findCallbacksFor(href);
if ( ! filteredCallbacks.isEmpty() ) {
for ( ResourceCallback callBack: filteredCallbacks ) {
callBack.onLoadResource(href, zipFile.getInputStream(zipEntry) );
}
}
}
} finally {
if ( zipFile != null ) {
zipFile.close();
}
this.callbacks.clear();
}
}
private List<ResourceCallback> findCallbacksFor( String href ) {
List<ResourceCallback> result = new ArrayList<>();
for ( Holder holder: this.callbacks ) {
if ( href.endsWith(holder.href ) ) {
result.add(holder.callback);
}
}
return result;
}
public void registerCallback( String forHref, ResourceCallback callback )
throws AssertionError{
Holder holder = new Holder();
// Default Charset for android is UTF-8
// http://developer.android.com/reference/java/nio/charset/Charset.html#defaultCharset()
String charsetName = Charset.defaultCharset().name();
if (!Charset.isSupported(charsetName)) {
LOG.warn("{} is not a supported Charset. Will fall back to UTF-8", charsetName);
charsetName = "UTF-8";
}
try {
holder.href = URLDecoder.decode(forHref, charsetName);
holder.callback = callback;
callbacks.add(holder);
} catch (UnsupportedEncodingException e) {
// I don't think this will ever be reached
throw new AssertionError(e);
}
}
}