/* This code is part of Freenet. It is distributed under the GNU General
* Public License, version 2 (or at your option any later version). See
* http://www.gnu.org/ for further details of the GPL. */
package freenet.support;
import java.util.HashMap;
import java.util.Map;
import freenet.client.ArchiveManager.ARCHIVE_TYPE;
import freenet.support.api.ManifestElement;
/**
* Helper class to estaminate the container size,
* @author saces
*
*/
public final class ContainerSizeEstimator {
public static final ARCHIVE_TYPE DEFAULT_ARCHIVE_TYPE = ARCHIVE_TYPE.TAR;
public final static class ContainerSize {
private long _sizeFiles;
private long _sizeFilesNoLimit;
private long _sizeSubTrees;
private long _sizeSubTreesNoLimit;
private ContainerSize() {
_sizeFiles = 0;
_sizeFilesNoLimit = 0;
_sizeSubTrees = 0;
_sizeSubTreesNoLimit = 0;
}
public long getSizeTotal() {
return _sizeFiles+_sizeSubTrees;
}
public long getSizeTotalNoLimit() {
return _sizeFilesNoLimit+_sizeSubTreesNoLimit;
}
public long getSizeFiles() {
return _sizeFiles;
}
public long getSizeFilesNoLimit() {
return _sizeFilesNoLimit;
}
public long getSizeSubTrees() {
return _sizeSubTrees;
}
public long getSizeSubTreesNoLimit() {
return _sizeSubTreesNoLimit;
}
}
private ContainerSizeEstimator() {}
public static ContainerSize getSubTreeSize(HashMap<String, Object> metadata, long maxItemSize, long maxContainerSize, int maxDeep) {
ContainerSize result = new ContainerSize();
getSubTreeSize(metadata, result, maxItemSize, maxContainerSize, maxDeep);
return result;
}
private static void getSubTreeSize(HashMap<String, Object> metadata, ContainerSize result, long maxItemSize, long maxContainerSize,int maxDeep) {
// files
for(Map.Entry<String,Object> entry:metadata.entrySet()) {
Object o = entry.getValue();
if (o instanceof ManifestElement) {
ManifestElement me = (ManifestElement)o;
long itemsize = me.getSize();
if (itemsize > -1) {
result._sizeFilesNoLimit += getContainerItemSize(me.getSize());
// Add some bytes for .metadata element.
// FIXME 128 picked out of the air! Look up the format.
result._sizeFilesNoLimit += 128 + me.getName().length();
if (itemsize > maxItemSize)
result._sizeFiles += 512; // spare for redirect
else {
result._sizeFiles += getContainerItemSize(me.getSize());
// Add some bytes for .metadata element.
// FIXME 128 picked out of the air! Look up the format.
result._sizeFilesNoLimit += 128 + me.getName().length();
// FIXME The tar file will need the full name????
}
if (result._sizeFiles > maxContainerSize) break;
} else {
// Redirect.
result._sizeFiles += 512;
result._sizeFilesNoLimit += 512;
}
}
}
// sub dirs
if (maxDeep > 0) {
for(Map.Entry<String,Object> entry:metadata.entrySet()) {
Object o = entry.getValue();
if (o instanceof HashMap) {
result._sizeSubTrees += 512;
@SuppressWarnings("unchecked")
HashMap<String, Object> hm = (HashMap<String, Object>) o;
ContainerSize tempResult = new ContainerSize();
getSubTreeSize(hm, tempResult, maxItemSize, (maxContainerSize-result._sizeSubTrees), maxDeep-1);
result._sizeSubTrees += tempResult.getSizeTotal();
result._sizeSubTreesNoLimit += tempResult.getSizeTotalNoLimit();
if (result._sizeSubTrees > maxContainerSize) break;
}
}
}
}
public static long getContainerItemSize(long size) {
return getContainerItemSize(DEFAULT_ARCHIVE_TYPE, size);
}
private static long getContainerItemSize(ARCHIVE_TYPE archiveType, long size) {
if (archiveType == ARCHIVE_TYPE.TAR)
return tarItemSize(size);
throw new UnsupportedOperationException("TODO, only TAR supportet atm.");
}
public static long tarItemSize(long size) {
return 512 + (((size + 511) / 512) * 512);
}
}