blob: 1667f66bb62b3b6f375bfd40715237eb823206d9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*//*
* CacheReader.java
*
* Created on February 16, 2004, 8:11 PM
*/
package org.netbeans.imagecache;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.nio.LongBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.Arrays;
/**
*
* @author Tim Boudreau
*/
public class CacheReader {
static final String filename = CacheWriter.filename;
static final int METAENTRY_LENGTH = CacheWriter.METAENTRY_LENGTH;
static final int ID_OFFSET = CacheWriter.ID_OFFSET;
private File cachefile;
private File metafile;
private ByteBuffer cachebuffer = null;
private ByteBuffer metabuffer = null;
/** Creates a new instance of CacheReader */
public CacheReader(File cacheDir) throws IOException {
this (new File(cacheDir + File.separator + filename + ".cache"),
new File(cacheDir + File.separator + filename + ".metadata"));
}
public CacheReader(File cachefile, File metafile) throws IOException {
if (!cachefile.exists() || !metafile.exists()) {
throw new IOException ("Cache does not exist: " + cachefile + "," + metafile);
}
this.cachefile = cachefile;
this.metafile = metafile;
}
public String[] getIDs() throws IOException {
ArrayList a = new ArrayList();
ByteBuffer b = getMetaBuffer().asReadOnlyBuffer();
int max = b.limit() / METAENTRY_LENGTH;
for (int i=0; i < max; i++) {
int len = b.asIntBuffer().get();
b.mark();
b.position(b.position() + ID_OFFSET);
byte[] bytes = new byte[len];
b.get(bytes);
a.add(new String(bytes));
b.reset();
if (i != max-1) {
b.position(b.position() + METAENTRY_LENGTH);
}
}
String[] result = new String[a.size()];
result = (String[]) a.toArray(result);
return result;
}
public Image find (String id) throws IOException {
ByteBuffer buf = findMetadataFor (toByteArray(id));
if (buf == null) {
return null;
}
IntBuffer ibuf = buf.asIntBuffer();
int[] intEntries = new int[3];
ibuf.get(intEntries);
assert id.length() == intEntries[0];
int width = intEntries[1];
int height = intEntries[2];
long[] longEntries = new long[2];
buf.position(buf.position() + 12);
LongBuffer lbuf = buf.asLongBuffer();
lbuf.get(longEntries);
//The cast to int is safe, the writer will never write a cache file
//bigger than Integer.MAX_VALUE
int start = (int) longEntries[0];
int end = (int) longEntries[1];
ByteBuffer cache = getBuffer().asReadOnlyBuffer();
cache.position(start);
System.err.println("Cache position is " + cache.position());
IntBuffer databuffer = cache.asIntBuffer();
System.err.println("IntBuffer position is " + databuffer.position());
return createImageFrom (databuffer, width, height);
}
/*
private Image createImageFrom (IntBuffer data, int width, int height) {
//Cheap'n'cheesy for now - should really create a custom DataSource which
//reads the buffer for its pixel data
BufferedImage bi = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);
for (int x=0; x < width; x++) {
for (int y=0; y < height; y++) {
try {
bi.setRGB (x, y, data.get());
} catch (Exception e) {
System.err.println("Exception getting " + x + "," + y + " pos:" + data.position());
}
}
}
return bi;
}
*/
private Image createImageFrom (IntBuffer data, int width, int height) {
CRaster raster = new CRaster (data, width, height);
return new CImage (ColorModel.getRGBdefault(), raster, false, null);
}
/** Locates metadata related to the passed id (converted into a byte
* array). Returns either a bytebuffer with the position set to the
* start of the metadata or null. */
private ByteBuffer findMetadataFor (byte[] id) throws IOException {
System.err.println("FindMetadataFor " + new String(id));
long result = -1;
//Get a buffer clone so we don't have threading problems - never
//use the master buffer
ByteBuffer buf = getMetaBuffer().asReadOnlyBuffer();
IntBuffer ibuf = buf.asIntBuffer();
do {
//First, see if the ID (image filename) length matches the ID
//we received - if it doesn't, no need to examine the record
int thisIdLength = ibuf.get();
System.err.println("pos:" + ibuf.position() + " idLen: " + thisIdLength + " looking for len: " + id.length);
if (thisIdLength == id.length) {
//Mark the start of this metadata record and position to
//the start of the ID entry
System.err.println("Length match. Putting mark at " + (buf.position()) + " and moving to " + (buf.position() + ID_OFFSET) + " to check data");
buf.mark().position (buf.position() + ID_OFFSET);
byte[] chars = new byte[id.length];
//Fetch the ID into the array, and reset the buffer position
//for either returning or skipping to the next record
buf.get(chars).reset();
System.err.println(" id from metadata: " + new String(chars));
//Compare it with the id we were passed
if (Arrays.equals(chars, id)) {
System.err.println(" MATCHED - position: " + buf.position());
return buf;
}
}
//Skip ahead to the next record
buf.position(buf.position() + METAENTRY_LENGTH);
ibuf.position(buf.position() / 4);
System.err.println("Buffer pos: " + buf.position() + " ibuf: " + ibuf.position());
} while (buf.position() <= buf.limit() - METAENTRY_LENGTH);
return null;
}
private static byte[] toByteArray(String s) {
char[] c = s.toCharArray();
byte[] result = new byte[c.length];
for (int i=0; i < c.length; i++) {
result[i] = (byte) c[i];
}
return result;
}
protected ByteBuffer createBuffer(File file) throws IOException {
return new FileInputStream (file).getChannel().map(
FileChannel.MapMode.READ_ONLY, 0, file.length());
}
private ByteBuffer getBuffer() throws IOException {
if (cachebuffer == null) {
cachebuffer = createBuffer(cachefile);
}
cachebuffer.position(0);
return cachebuffer;
}
private ByteBuffer getMetaBuffer() throws IOException {
if (metabuffer == null) {
metabuffer = createBuffer(metafile);
}
return metabuffer;
}
}