#include <fcntl.h>
#include <sys/mman.h>
+#if !EXIV2_TEST_VERSION(0,17,90)
#include <exiv2/tiffparser.hpp>
#include <exiv2/tiffcomposite.hpp>
#include <exiv2/tiffvisitor.hpp>
#include <exiv2/rafimage.hpp>
#endif
#include <exiv2/futils.hpp>
-
+#else
+#include <exiv2/preview.hpp>
+#endif
extern "C" {
if (!item) return 0;
((Exiv2::Metadatum *)item)->setValue(std::string(str));
return 1;
- }
+ }
catch (Exiv2::AnyError& e) {
return 0;
}
exif->cp_length =cp_length;
}
-unsigned char *exif_get_color_profile(ExifData *exif, guint *data_len)
+guchar *exif_get_color_profile(ExifData *exif, guint *data_len)
{
if (exif->cp_data)
{
return NULL;
}
+#if EXIV2_TEST_VERSION(0,17,90)
+guchar *exif_get_preview(ExifData *exif, guint *data_len)
+{
+ if (!exif) return NULL;
+ try {
+
+ Exiv2::PreviewImageList list(*exif->image);
+ list.read();
+
+ Exiv2::PreviewImageList::iterator pos = list.begin();
+ if (pos != list.end())
+ {
+ Exiv2::DataBuf buf = pos->copy();
+ std::pair<Exiv2::byte*, long> p = buf.release();
+
+ *data_len = p.second;
+ return p.first;
+ }
+ return NULL;
+ }
+ catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ return NULL;
+ }
+}
+
+void exif_free_preview(guchar *buf)
+{
+ delete[] (Exiv2::byte*)buf;
+}
+#endif
}
+#if !EXIV2_TEST_VERSION(0,17,90)
/* This is a dirty hack to support raw file preview, bassed on
tiffparse.cpp from Exiv2 examples */
class RawFile {
public:
- RawFile(int fd);
+ RawFile(Exiv2::BasicIo &io);
~RawFile();
const Exiv2::Value *find(uint16_t tag, uint16_t group);
private:
int type;
Exiv2::TiffComponent::AutoPtr rootDir;
- Exiv2::byte *map_data;
+ Exiv2::BasicIo &io_;
+ const Exiv2::byte *map_data;
size_t map_len;
unsigned long offset;
};
+typedef struct _UnmapData UnmapData;
+struct _UnmapData
+{
+ guchar *ptr;
+ guchar *map_data;
+ size_t map_len;
+};
+
+static GList *exif_unmap_list = 0;
+
+extern "C" guchar *exif_get_preview(ExifData *exif, guint *data_len)
+{
+ int success;
+ unsigned long offset;
+
+ if (!exif) return NULL;
+ const char* path = exif->image->io().path().c_str();
+
+ /* given image pathname, first do simple (and fast) file extension test */
+ if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return 0;
+
+ try {
+ struct stat st;
+ guchar *map_data;
+ size_t map_len;
+ UnmapData *ud;
+ int fd;
+
+ RawFile rf(exif->image->io());
+ offset = rf.preview_offset();
+ DEBUG_1("%s: offset %lu", path, offset);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ {
+ return 0;
+ }
+
+ if (fstat(fd, &st) == -1)
+ {
+ close(fd);
+ return 0;
+ }
+ map_len = st.st_size;
+ map_data = (guchar *) mmap(0, map_len, PROT_READ, MAP_PRIVATE, fd, 0);
+ close(fd);
+ if (map_data == MAP_FAILED)
+ {
+ return 0;
+ }
+ *data_len = map_len - offset;
+ ud = g_new(UnmapData, 1);
+ ud->ptr = map_data + offset;
+ ud->map_data = map_data;
+ ud->map_len = map_len;
+
+ exif_unmap_list = g_list_prepend(exif_unmap_list, ud);
+ return ud->ptr;
+
+ }
+ catch (Exiv2::AnyError& e) {
+ std::cout << "Caught Exiv2 exception '" << e << "'\n";
+ }
+ return NULL;
+
+}
+
+void exif_free_preview(guchar *buf)
+{
+ GList *work = exif_unmap_list;
+
+ while (work)
+ {
+ UnmapData *ud = (UnmapData *)work->data;
+ if (ud->ptr == buf)
+ {
+ munmap(ud->map_data, ud->map_len);
+ exif_unmap_list = g_list_remove_link(exif_unmap_list, work);
+ g_free(ud);
+ return;
+ }
+ }
+ g_assert_not_reached();
+}
+
using namespace Exiv2;
-RawFile::RawFile(int fd) : map_data(NULL), map_len(0), offset(0)
+RawFile::RawFile(BasicIo &io) : io_(io), map_data(NULL), map_len(0), offset(0)
{
+/*
struct stat st;
if (fstat(fd, &st) == -1)
{
{
throw Error(14);
}
+*/
+ if (io.open() != 0) {
+ throw Error(9, io.path(), strError());
+ }
+
+ map_data = io.mmap();
+ map_len = io.size();
+
+
type = Exiv2::ImageFactory::getType(map_data, map_len);
#if EXIV2_TEST_VERSION(0,16,0)
RawFile::~RawFile(void)
{
- if (map_data && munmap(map_data, map_len) == -1)
- {
- log_printf("Failed to unmap file \n");
- }
+ io_.munmap();
+ io_.close();
}
const Value * RawFile::find(uint16_t tag, uint16_t group)
}
-extern "C" gint format_raw_img_exif_offsets_fd(int fd, const gchar *path,
- unsigned char *header_data, const guint header_len,
- guint *image_offset, guint *exif_offset)
-{
- int success;
- unsigned long offset;
-
- /* given image pathname, first do simple (and fast) file extension test */
- if (!filter_file_class(path, FORMAT_CLASS_RAWIMAGE)) return 0;
-
- try {
- RawFile rf(fd);
- offset = rf.preview_offset();
- DEBUG_1("%s: offset %lu", path, offset);
- }
- catch (Exiv2::AnyError& e) {
- std::cout << "Caught Exiv2 exception '" << e << "'\n";
- return 0;
- }
-
- if (image_offset && offset > 0)
- {
- *image_offset = offset;
- if ((unsigned long) lseek(fd, *image_offset, SEEK_SET) != *image_offset)
- {
- log_printf("Failed to seek to embedded image\n");
-
- *image_offset = 0;
- if (*exif_offset) *exif_offset = 0;
- success = FALSE;
- }
- }
-
- return offset > 0;
-}
+#endif
#endif
#include "ui_fileops.h"
#include <fcntl.h>
+#include <sys/mman.h>
static const gchar *image_loader_path(ImageLoader *il)
il->loader = NULL;
}
- if (il->load_fd != -1)
+ if (il->mapped_file)
{
- close(il->load_fd);
- il->load_fd = -1;
+ if (il->preview)
+ {
+ exif_free_preview(il->mapped_file);
+ }
+ else
+ {
+ munmap(il->mapped_file, il->bytes_total);
+ }
+ il->mapped_file = NULL;
}
il->done = TRUE;
c = il->idle_read_loop_count ? il->idle_read_loop_count : 1;
while (c > 0)
{
- b = read(il->load_fd, il->read_buffer, il->read_buffer_size);
+ b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
if (b == 0)
{
return FALSE;
}
- if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL)))
+ if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL)))
{
image_loader_error(il);
return FALSE;
static gint image_loader_begin(ImageLoader *il)
{
gint b;
- guint offset = 0;
if (!il->loader || il->pixbuf) return FALSE;
- b = read(il->load_fd, il->read_buffer, il->read_buffer_size);
-
- if (b > 0 &&
- format_raw_img_exif_offsets_fd(il->load_fd, image_loader_path(il), il->read_buffer, b, &offset, NULL))
- {
- DEBUG_1("Raw file %s contains embedded image", image_loader_path(il));
-
- b = read(il->load_fd, il->read_buffer, il->read_buffer_size);
- }
+ b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
if (b < 1)
{
return FALSE;
}
- if (!gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL))
+ if (!gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL))
{
image_loader_stop(il);
return FALSE;
}
- il->bytes_read += b + offset;
+ il->bytes_read += b;
/* read until size is known */
while (il->loader && !gdk_pixbuf_loader_get_pixbuf(il->loader) && b > 0)
{
- b = read(il->load_fd, il->read_buffer, il->read_buffer_size);
- if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->read_buffer, b, NULL)))
+ b = MIN(il->read_buffer_size, il->bytes_total - il->bytes_read);
+ if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, il->mapped_file + il->bytes_read, b, NULL)))
{
image_loader_stop(il);
return FALSE;
struct stat st;
gchar *pathl;
- if (!il || il->load_fd != -1 || il->loader) return FALSE;
+ if (!il || il->loader || il->mapped_file) return FALSE;
- pathl = path_from_utf8(image_loader_path(il));
- il->load_fd = open(pathl, O_RDONLY | O_NONBLOCK);
- g_free(pathl);
- if (il->load_fd == -1) return FALSE;
+ il->mapped_file = NULL;
- if (fstat(il->load_fd, &st) == 0)
+ if (il->fd)
{
- il->bytes_total = st.st_size;
+ ExifData *exif = exif_read_fd(il->fd);
+
+ il->mapped_file = exif_get_preview(exif, &il->bytes_total);
+
+ if (il->mapped_file)
+ {
+ il->preview = TRUE;
+ DEBUG_1("Raw file %s contains embedded image", image_loader_path(il));
+ }
+ exif_free_fd(il->fd, exif);
}
+
+ if (!il->mapped_file)
+ {
+ /* normal file */
+ gint load_fd;
+
+ pathl = path_from_utf8(image_loader_path(il));
+ load_fd = open(pathl, O_RDONLY | O_NONBLOCK);
+ g_free(pathl);
+ if (load_fd == -1) return FALSE;
+
+ if (fstat(load_fd, &st) == 0)
+ {
+ il->bytes_total = st.st_size;
+ }
+ else
+ {
+ close(load_fd);
+ return FALSE;
+ }
+
+ il->mapped_file = mmap(0, il->bytes_total, PROT_READ|PROT_WRITE, MAP_PRIVATE, load_fd, 0);
+ close(load_fd);
+ if (il->mapped_file == MAP_FAILED)
+ {
+ il->mapped_file = 0;
+ return FALSE;
+ }
+ il->preview = FALSE;
+ }
+
+
il->loader = gdk_pixbuf_loader_new();
g_signal_connect(G_OBJECT(il->loader), "area_updated",
G_CALLBACK(image_loader_area_updated_cb), il);
il->idle_priority = G_PRIORITY_DEFAULT_IDLE;
il->done = FALSE;
il->loader = NULL;
- il->load_fd = -1;
il->bytes_read = 0;
il->bytes_total = 0;
il->idle_read_loop_count = options->image.idle_read_loop_count;
il->read_buffer_size = options->image.read_buffer_size;
- il->read_buffer = g_new(guchar, il->read_buffer_size);
+ il->mapped_file = NULL;
il->requested_width = 0;
il->requested_height = 0;
if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf);
if (il->fd) file_data_unref(il->fd);
if (il->path) g_free(il->path);
- if (il->read_buffer) g_free(il->read_buffer);
DEBUG_1("freeing image loader %p bytes_read=%d", il, il->bytes_read);
g_free(il);
}