Blob Blame History Raw
From 9fd5cc67477200ee12e77b0a87d7b4b18fabd9ad Mon Sep 17 00:00:00 2001
From: David Hewitt <davidmhewitt@gmail.com>
Date: Fri, 1 Oct 2021 15:13:23 +0100
Subject: [PATCH 1/3] Update vapi files

---
 src/Views/ImportPage.vala     |  52 +++++++++--------
 src/camera/GPhoto.vala        |  93 ++++++++++++-----------------
 src/photos/PhotoMetadata.vala |  34 ++++-------
 vapi/libexif.vapi             |  46 +++++++++------
 vapi/libgphoto2.vapi          | 106 +++++++++++++++++-----------------
 5 files changed, 156 insertions(+), 175 deletions(-)

diff --git a/src/Views/ImportPage.vala b/src/Views/ImportPage.vala
index a3a4d2ef..6cd14a89 100644
--- a/src/Views/ImportPage.vala
+++ b/src/Views/ImportPage.vala
@@ -278,8 +278,7 @@ class ImportPreview : CheckerboardItem {
         bool using_placeholder = (pixbuf == null);
         if (pixbuf == null) {
             if (placeholder_preview == null) {
-                placeholder_preview = AppWindow.get_instance ().render_icon ("image-missing",
-                                      Gtk.IconSize.DIALOG, null);
+                placeholder_preview = get_placeholder_pixbuf ();
                 placeholder_preview = scale_pixbuf (placeholder_preview, MAX_SCALE,
                                                     Gdk.InterpType.BILINEAR, true);
             }
@@ -305,6 +304,23 @@ class ImportPreview : CheckerboardItem {
         set_image (pixbuf);
     }
 
+    private Gdk.Pixbuf get_placeholder_pixbuf () {
+        Gdk.Pixbuf? pixbuf = null;
+
+        try {
+            var icon_theme = Gtk.IconTheme.get_default ();
+            pixbuf = icon_theme.load_icon ("image-missing", 48, 0);
+        } catch (Error e) {
+            // Create an empty black pixbuf as a fallback
+            pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, 50, 50);
+            pixbuf.fill (0);
+
+            warning("Could not load icon from theme: %s", e.message);
+        }
+
+        return pixbuf;
+    }
+
     public bool is_already_imported () {
         PhotoImportSource photo_import_source = get_import_source () as PhotoImportSource;
         if (photo_import_source != null) {
@@ -1250,11 +1266,10 @@ public class ImportPage : CheckerboardPage {
 
         Gee.ArrayList<ImportSource> import_list = new Gee.ArrayList<ImportSource> ();
 
-        GPhoto.CameraStorageInformation *sifs = null;
-        int count = 0;
-        refresh_result = camera.get_storageinfo (&sifs, out count, spin_idle_context.context);
+        GPhoto.CameraStorageInformation[] sifs = null;
+        refresh_result = camera.get_storageinfo (out sifs, spin_idle_context.context);
         if (refresh_result == GPhoto.Result.OK) {
-            for (int fsid = 0; fsid < count; fsid++) {
+            for (int fsid = 0; fsid < sifs.length; fsid++) {
                 // Check well-known video and image paths first to prevent accidental
                 // scanning of undesired directories (which can cause user annoyance with
                 // some smartphones or camera-equipped media players)
@@ -1389,18 +1404,15 @@ public class ImportPage : CheckerboardPage {
     // Need to do this because some phones (iPhone, in particular) changes the name of their filesystem
     // between each mount
     public static string? get_fs_basedir (GPhoto.Camera camera, int fsid) {
-        GPhoto.CameraStorageInformation *sifs = null;
-        int count = 0;
-        GPhoto.Result res = camera.get_storageinfo (&sifs, out count, null_context.context);
+        GPhoto.CameraStorageInformation[] sifs = null;
+        GPhoto.Result res = camera.get_storageinfo (out sifs, null_context.context);
         if (res != GPhoto.Result.OK)
             return null;
 
-        if (fsid >= count)
+        if (fsid >= sifs.length)
             return null;
 
-        GPhoto.CameraStorageInformation *ifs = sifs + fsid;
-
-        return (ifs->fields & GPhoto.CameraStorageInfoFields.BASE) != 0 ? ifs->basedir : "/";
+        return (sifs[fsid].fields & GPhoto.CameraStorageInfoFields.BASE) != 0 ? (string)sifs[fsid].basedir : "/";
     }
 
     public static string? get_fulldir (GPhoto.Camera camera, string camera_name, int fsid, string folder) {
@@ -1474,12 +1486,12 @@ public class ImportPage : CheckerboardPage {
                     import_list.add (video_source);
                 } else {
                     // determine file format from type, and then from file extension
-                    PhotoFileFormat file_format = PhotoFileFormat.from_gphoto_type (info.file.type);
+                    PhotoFileFormat file_format = PhotoFileFormat.from_gphoto_type ((string)info.file.type);
                     if (file_format == PhotoFileFormat.UNKNOWN) {
                         file_format = PhotoFileFormat.get_by_basename_extension (filename);
                         if (file_format == PhotoFileFormat.UNKNOWN) {
                             message ("Skipping %s/%s: Not a supported file extension (%s)", fulldir,
-                                     filename, info.file.type);
+                                     filename, (string)info.file.type);
 
                             continue;
                         }
@@ -1627,9 +1639,8 @@ public class ImportPage : CheckerboardPage {
             // this means the preview orientation will be wrong and the MD5 is not generated
             // if the EXIF did not parse properly (see above)
 
-            uint8[] preview_raw = null;
-            size_t preview_raw_length = 0;
             Gdk.Pixbuf preview = null;
+            string? preview_md5 = null;
             try {
                 string preview_fulldir = fulldir;
                 string preview_filename = filename;
@@ -1638,7 +1649,7 @@ public class ImportPage : CheckerboardPage {
                     preview_filename = associated.filename;
                 }
                 preview = GPhoto.load_preview (spin_idle_context.context, camera, preview_fulldir,
-                                               preview_filename, out preview_raw, out preview_raw_length);
+                                               preview_filename, out preview_md5);
             } catch (Error err) {
                 // only issue the warning message if we're not reading a video. GPhoto is capable
                 // of reading video previews about 50% of the time, so we don't want to put a guard
@@ -1650,11 +1661,6 @@ public class ImportPage : CheckerboardPage {
                 }
             }
 
-            // calculate thumbnail fingerprint
-            string? preview_md5 = null;
-            if (preview != null && preview_raw != null && preview_raw_length > 0)
-                preview_md5 = md5_binary (preview_raw, preview_raw_length);
-
 #if TRACE_MD5
             debug ("camera MD5 %s: exif=%s preview=%s", filename, exif_only_md5, preview_md5);
 #endif
diff --git a/src/camera/GPhoto.vala b/src/camera/GPhoto.vala
index c2998eb3..06334e72 100644
--- a/src/camera/GPhoto.vala
+++ b/src/camera/GPhoto.vala
@@ -127,13 +127,24 @@ public bool get_info (Context context, Camera camera, string folder, string file
     return true;
 }
 
+public Bytes? camera_file_to_bytes (Context context, CameraFile file) {
+    // if buffer can be loaded into memory, return a Bytes class with
+    // CameraFile being the owner of the data. This way, the CameraFile is freed
+    // when the Bytes are freed
+    unowned uint8[] buffer = null;
+    var res = file.get_data(out buffer);
+    if (res != Result.OK)
+        return null;
+
+    return Bytes.new_with_owner<GPhoto.CameraFile>(buffer, file);
+}
+
 // Libgphoto will in some instances refuse to get metadata from a camera, but the camera is accessable as a
 // filesystem.  In these cases shotwell can access the file directly. See:
 // http://redmine.yorba.org/issues/2959
 public PhotoMetadata? get_fallback_metadata (Camera camera, Context context, string folder, string filename) {
-    GPhoto.CameraStorageInformation *sifs = null;
-    int count = 0;
-    camera.get_storageinfo (&sifs, out count, context);
+    GPhoto.CameraStorageInformation[] sifs = null;
+    camera.get_storageinfo (out sifs, context);
 
     GPhoto.PortInfo port_info;
     camera.get_port_info (out port_info);
@@ -158,9 +169,10 @@ public PhotoMetadata? get_fallback_metadata (Camera camera, Context context, str
 }
 
 public Gdk.Pixbuf? load_preview (Context context, Camera camera, string folder, string filename,
-                                 out uint8[] raw, out size_t raw_length) throws Error {
-    raw = null;
-    raw_length = 0;
+                                 out string? preview_md5) throws Error {
+    Bytes? raw = null;
+    Bytes? out_bytes = null;
+    preview_md5 = null;
 
     try {
         raw = load_file_into_buffer (context, camera, folder, filename, GPhoto.CameraFileType.PREVIEW);
@@ -170,35 +182,22 @@ public Gdk.Pixbuf? load_preview (Context context, Camera camera, string folder,
             return null;
         if (0 == metadata.get_preview_count ())
             return null;
-        PhotoPreview? preview = metadata.get_preview (metadata.get_preview_count () - 1);
+
+        // Get the smallest preview from meta-data
+        var preview = metadata.get_preview (metadata.get_preview_count () - 1);
         raw = preview.flatten ();
+        preview_md5 = Checksum.compute_for_bytes (ChecksumType.MD5, raw);
     }
 
-    if (raw == null) {
-        raw_length = 0;
-        return null;
-    }
+    out_bytes = raw;
+    preview_md5 = Checksum.compute_for_bytes (ChecksumType.MD5, out_bytes);
 
-    raw_length = raw.length;
-
-    // Try to make sure last two bytes are JPEG footer.
-    // This is necessary because GPhoto sometimes includes a few extra bytes. See
-    // Yorba bug #2905 and the following GPhoto bug:
-    // http://sourceforge.net/tracker/?func=detail&aid=3141521&group_id=8874&atid=108874
-    if (raw_length > 32) {
-        for (size_t i = raw_length - 2; i > raw_length - 32; i--) {
-            if (raw[i] == Jpeg.MARKER_PREFIX && raw[i + 1] == Jpeg.Marker.EOI) {
-                debug ("Adjusted length of thumbnail for: %s", filename);
-                raw_length = i + 2;
-                break;
-            }
-        }
-    }
+    MemoryInputStream mins = new MemoryInputStream.from_bytes (raw);
 
-    MemoryInputStream mins = new MemoryInputStream.from_data (raw, null);
     return new Gdk.Pixbuf.from_stream_at_scale (mins, ImportPreview.MAX_SCALE, ImportPreview.MAX_SCALE, true, null);
 }
 
+
 public Gdk.Pixbuf? load_image (Context context, Camera camera, string folder, string filename)
 throws Error {
     InputStream ins = load_file_into_stream (context, camera, folder, filename, GPhoto.CameraFileType.NORMAL);
@@ -228,7 +227,7 @@ public void save_image (Context context, Camera camera, string folder, string fi
 
 public PhotoMetadata? load_metadata (Context context, Camera camera, string folder, string filename)
 throws Error {
-    uint8[] camera_raw = null;
+    Bytes? camera_raw = null;
     try {
         camera_raw = load_file_into_buffer (context, camera, folder, filename, GPhoto.CameraFileType.EXIF);
     } catch {
@@ -258,17 +257,12 @@ public InputStream load_file_into_stream (Context context, Camera camera, string
         throw new GPhotoError.LIBRARY ("[%d] Error retrieving file object for %s/%s: %s",
         (int) res, folder, filename, res.as_string ());
 
-    // if entire file fits in memory, return a stream from that ... can't merely wrap
-    // MemoryInputStream around the camera_file buffer, as that will be destroyed when the
-    // function returns
-    unowned uint8 *data;
-    ulong data_len;
-    res = camera_file.get_data_and_size (out data, out data_len);
-    if (res == Result.OK) {
-        uint8[] buffer = new uint8[data_len];
-        Memory.copy (buffer, data, buffer.length);
-
-        return new MemoryInputStream.from_data (buffer, on_mins_destroyed);
+    // if entire file fits in memory, return a stream from that ...
+    // The camera_file is set as data on the object to keep it alive while
+    // the MemoryInputStream is alive.
+    var bytes = camera_file_to_bytes (context, camera_file);
+    if (bytes != null) {
+        return new MemoryInputStream.from_bytes (bytes);
     }
 
     // if not stored in memory, try copying it to a temp file and then reading out of that
@@ -281,13 +275,9 @@ public InputStream load_file_into_stream (Context context, Camera camera, string
     return temp.read (null);
 }
 
-private static void on_mins_destroyed (void *data) {
-    free (data);
-}
-
 // Returns a buffer with the requested file, if within reason.  Use load_file for larger files.
-public uint8[]? load_file_into_buffer (Context context, Camera camera, string folder,
-                                       string filename, CameraFileType filetype) throws Error {
+public Bytes? load_file_into_buffer (Context context, Camera camera, string folder,
+                                     string filename, CameraFileType filetype) throws Error {
     GPhoto.CameraFile camera_file;
     GPhoto.Result res = GPhoto.CameraFile.create (out camera_file);
     if (res != Result.OK)
@@ -298,17 +288,6 @@ public uint8[]? load_file_into_buffer (Context context, Camera camera, string fo
         throw new GPhotoError.LIBRARY ("[%d] Error retrieving file object for %s/%s: %s",
         (int) res, folder, filename, res.as_string ());
 
-    // if buffer can be loaded into memory, return a copy of that (can't return buffer itself
-    // as it will be destroyed when the camera_file is unref'd)
-    unowned uint8 *data;
-    ulong data_len;
-    res = camera_file.get_data_and_size (out data, out data_len);
-    if (res != Result.OK)
-        return null;
-
-    uint8[] buffer = new uint8[data_len];
-    Memory.copy (buffer, data, buffer.length);
-
-    return buffer;
+    return camera_file_to_bytes (context, camera_file);
 }
 }
diff --git a/src/photos/PhotoMetadata.vala b/src/photos/PhotoMetadata.vala
index 491e37f2..4f4715fe 100644
--- a/src/photos/PhotoMetadata.vala
+++ b/src/photos/PhotoMetadata.vala
@@ -91,16 +91,15 @@ public abstract class PhotoPreview {
         return extension;
     }
 
-    public abstract uint8[] flatten () throws Error;
+    public abstract Bytes flatten () throws Error;
 
     public virtual Gdk.Pixbuf? get_pixbuf () throws Error {
-        uint8[] flattened = flatten ();
+        var flattened = flatten ();
 
         // Need to create from stream or file for decode ... catch decode error and return null,
         // different from an I/O error causing the problem
         try {
-            return new Gdk.Pixbuf.from_stream (new MemoryInputStream.from_data (flattened, null),
-            null);
+            return new Gdk.Pixbuf.from_stream (new MemoryInputStream.from_bytes (flattened));
         } catch (Error err) {
             warning ("Unable to decode thumbnail for %s: %s", name, err.message);
 
@@ -137,11 +136,11 @@ public class PhotoMetadata : MediaMetadata {
             this.number = number;
         }
 
-        public override uint8[] flatten () throws Error {
+        public override Bytes flatten () throws Error {
             unowned GExiv2.PreviewProperties?[] props = owner.exiv2.get_preview_properties ();
             assert (props != null && props.length > number);
 
-            return owner.exiv2.get_preview_image (props[number]).get_data ();
+            return new Bytes (owner.exiv2.get_preview_image (props[number]).get_data ());
         }
     }
 
@@ -174,31 +173,18 @@ public class PhotoMetadata : MediaMetadata {
         exiv2 = new GExiv2.Metadata ();
         exif = null;
 
-#if GEXIV2_0_11
         exiv2.open_buf (buffer[0:length]);
-#else
-        exiv2.open_buf (buffer, length);
-#endif
-        exif = Exif.Data.new_from_data (buffer, length);
+        exif = Exif.Data.new_from_data (buffer[0:length]);
         source_name = "<memory buffer %d bytes>".printf (length);
     }
 
-    public void read_from_app1_segment (uint8[] buffer, int length = 0) throws Error {
-        if (length <= 0)
-            length = buffer.length;
-
-        assert (buffer.length >= length);
-
+    public void read_from_app1_segment (Bytes buffer) throws Error {
         exiv2 = new GExiv2.Metadata ();
         exif = null;
 
-#if GEXIV2_0_11
-        exiv2.from_app1_segment (buffer[0:length]);
-#else
-        exiv2.from_app1_segment (buffer, length);
-#endif
-        exif = Exif.Data.new_from_data (buffer, length);
-        source_name = "<app1 segment %d bytes>".printf (length);
+        exiv2.from_app1_segment (buffer.get_data ());
+        exif = Exif.Data.new_from_data (buffer.get_data ());
+        source_name = "<app1 segment %zu bytes>".printf (buffer.get_size ());
     }
 
     public static MetadataDomain get_tag_domain (string tag) {
diff --git a/vapi/libexif.vapi b/vapi/libexif.vapi
index 8cd3fc3a..8331e9a0 100644
--- a/vapi/libexif.vapi
+++ b/vapi/libexif.vapi
@@ -1,4 +1,5 @@
 /* Copyright 2009-2013 Yorba Foundation
+ * Copyright 2016 Software Freedom Conservancy Inc.
  *
  * This software is licensed under the GNU LGPL (version 2.1 or later).
  * See the COPYING file in this distribution.
@@ -63,7 +64,11 @@ namespace Exif {
         public static void set_slong(uchar *buffer, ByteOrder byteOrder, int32 val);
     }
 
-    [CCode (cheader_filename="libexif/exif-content.h", has_target=false)]
+    [CCode (
+        cheader_filename="libexif/exif-content.h",
+        has_target=false,
+        cname="ExifContentForeachEntryFunc"
+    )]
     public delegate void ForeachEntryFunc(Entry e, void *user);
 
     [Compact]
@@ -79,7 +84,7 @@ namespace Exif {
         [CCode (cname="exif_data_new")]
         public Data();
         public static Data? new_from_file(string path);
-        public static Data? new_from_data(uint8 *data, size_t count);
+        public static Data? new_from_data([CCode (array_length_pos=1.1)]uint8[] data);
         public void dump();
         public void fix();
         public void foreach_content(ForeachContentFunc cb, void *user = null);
@@ -90,14 +95,18 @@ namespace Exif {
         public void unset_option(DataOption option);
         public void save_data(uchar **buffer, uint *size);
         public void set_data_type(DataType data_type);
-        
+
         // length is Exif.IFD_COUNT
-        public Content[] ifd;
+        public Content ifd[Exif.IFD_COUNT];
         public uchar *data;
         public uint size;
     }
 
-    [CCode (cheader_filename="libexif/exif-data.h", has_target=false)]
+    [CCode (
+        cheader_filename="libexif/exif-data.h",
+        has_target=false,
+        cname="ExifDataForeachContentFunc"
+    )]
     public delegate void ForeachContentFunc(Content c, void *user);
 
     [CCode (
@@ -113,7 +122,7 @@ namespace Exif {
         public unowned string get_name();
         public unowned string get_description();
     }
-    
+
     [CCode (
         cname="ExifDataType",
         cheader_filename="libexif/exif-data-type.h",
@@ -124,7 +133,7 @@ namespace Exif {
         UNCOMPRESSED_PLANAR,
         UNCOMPRESSED_YCC,
         COMPRESSED;
-        
+
         public bool is_valid() {
             switch (this) {
                 case UNCOMPRESSED_CHUNKY:
@@ -132,16 +141,16 @@ namespace Exif {
                 case UNCOMPRESSED_YCC:
                 case COMPRESSED:
                     return true;
-                
+
                 default:
                     return false;
             }
         }
     }
-    
+
     [CCode (cname="EXIF_DATA_TYPE_COUNT")]
     public const int DATA_TYPE_COUNT;
-    
+
     [Compact]
     [CCode (
         cname="ExifEntry",
@@ -160,14 +169,14 @@ namespace Exif {
         public string get_string() {
             char[] buffer = new char[256];
             get_value(buffer, 256);
-            
+
             GLib.StringBuilder builder = new GLib.StringBuilder();
             foreach (char c in buffer)
                 builder.append_c(c);
-            
+
             return builder.str;
         }
-        
+
         public Tag tag;
         public Format format;
         public ulong components;
@@ -215,7 +224,7 @@ namespace Exif {
 
         public unowned string get_name();
     }
-    
+
     [CCode (cname="EXIF_IFD_COUNT")]
     public const int IFD_COUNT;
 
@@ -265,7 +274,7 @@ namespace Exif {
         public unowned string get_title();
         public unowned string get_message();
     }
-    
+
     [Compact]
     [CCode (
         cname="ExifMem",
@@ -280,7 +289,7 @@ namespace Exif {
         public void free(void *ptr);
         public static Mem new_default();
     }
-    
+
     [SimpleType]
     [CCode (
         cname="ExifRational",
@@ -290,7 +299,7 @@ namespace Exif {
         uint32 numerator;
         uint32 denominator;
     }
-    
+
     [CCode (
         cname="ExifSupportLevel",
         cheader_filename="libexif/exif-tag.h",
@@ -302,7 +311,7 @@ namespace Exif {
         MANDATORY,
         OPTIONAL
     }
-    
+
     [CCode (
         cname="ExifTag",
         cheader_filename="libexif/exif-tag.h",
@@ -338,3 +347,4 @@ namespace Exif {
         public SupportLevel get_support_level_in_ifd(Ifd ifd, DataType data_type);
     }
 }
+
diff --git a/vapi/libgphoto2.vapi b/vapi/libgphoto2.vapi
index 282ce742..0852e701 100644
--- a/vapi/libgphoto2.vapi
+++ b/vapi/libgphoto2.vapi
@@ -1,4 +1,5 @@
 /* Copyright 2009-2013 Yorba Foundation
+ * Copyright 2016 Software Freedom Conservancy Inc.
  *
  * This software is licensed under the GNU LGPL (version 2.1 or later).
  * See the COPYING file in this distribution.
@@ -28,7 +29,7 @@ namespace GPhoto {
         public int usb_class;
         public int usb_protocol;
     }
-    
+
     [Compact]
     [CCode (
         cname="CameraAbilitiesList",
@@ -46,7 +47,7 @@ namespace GPhoto {
         public int lookup_model(string model);
         public Result get_abilities(int index, out CameraAbilities abilities);
     }
-    
+
     [Compact]
     [CCode (
         cname="Camera",
@@ -64,8 +65,8 @@ namespace GPhoto {
         public Result set_port_info(PortInfo info);
         public Result get_abilities(out CameraAbilities abilities);
         public Result set_abilities(CameraAbilities abilities);
-        public Result get_storageinfo(CameraStorageInformation **sifs, out int count, Context context);
-        
+        public Result get_storageinfo([CCode (array_length_pos=1.1)]out CameraStorageInformation[] sifs, Context context);
+
         // Folders
         [CCode (cname="gp_camera_folder_list_folders")]
         public Result list_folders(string folder, CameraList list, Context context);
@@ -74,12 +75,12 @@ namespace GPhoto {
         [CCode (cname="gp_camera_folder_delete_all")]
         public Result delete_all_files(string folder, Context context);
         [CCode (cname="gp_camera_folder_put_file")]
-        public Result put_file(string folder, CameraFile file, Context context);
+        public Result put_file(string folder, string filename, CameraFileType type, CameraFile file, Context context);
         [CCode (cname="gp_camera_folder_make_dir")]
         public Result make_dir(string folder, string name, Context context);
         [CCode (cname="gp_camera_folder_remove_dir")]
         public Result remove_dir(string folder, string name, Context context);
-        
+
         // Files
         [CCode (cname="gp_camera_file_get_info")]
         public Result get_file_info(string folder, string file, out CameraFileInfo info, Context context);
@@ -91,7 +92,7 @@ namespace GPhoto {
         [CCode (cname="gp_camera_file_delete")]
         public Result delete_file(string folder, string filename, Context context);
     }
-    
+
     [Compact]
     [CCode (
         cname="CameraFile",
@@ -104,11 +105,14 @@ namespace GPhoto {
     public class CameraFile {
         [CCode (cname="gp_file_new")]
         public static Result create(out CameraFile file);
-        public Result get_data_and_size(out uint8 *data, out ulong data_len);
+        [CCode (cname="gp_file_new_from_fd")]
+        public static Result create_from_fd(out CameraFile file, int fd);
+        [CCode (cname="gp_file_get_data_and_size")]
+        public Result get_data([CCode (array_length_pos=1.1, array_length_type="gulong")]out unowned uint8[] data);
         public Result save(string filename);
         public Result slurp(uint8[] data, out size_t readlen);
     }
-    
+
     [SimpleType]
     [CCode (
         cname="CameraFileInfo",
@@ -120,7 +124,7 @@ namespace GPhoto {
         public CameraFileInfoFile file;
         public CameraFileInfoAudio audio;
     }
-    
+
     [SimpleType]
     [CCode (
         cname="CameraFileInfoAudio",
@@ -128,7 +132,7 @@ namespace GPhoto {
     )]
     public struct CameraFileInfoAudio {
     }
-    
+
     [CCode (
         cname="CameraFileInfoFields",
         cheader_filename="gphoto2/gphoto2-filesys.h",
@@ -138,7 +142,6 @@ namespace GPhoto {
     public enum CameraFileInfoFields {
         NONE,
         TYPE,
-        NAME,
         SIZE,
         WIDTH,
         HEIGHT,
@@ -147,7 +150,7 @@ namespace GPhoto {
         MTIME,
         ALL
     }
-    
+
     [SimpleType]
     [CCode (
         cname="CameraFileInfoFile",
@@ -157,14 +160,13 @@ namespace GPhoto {
         public CameraFileInfoFields fields;
         public CameraFileStatus status;
         public ulong size;
-        public string type;
+        public char type[64];
         public uint width;
         public uint height;
-        public string name;
         public CameraFilePermissions permissions;
         public time_t mtime;
     }
-    
+
     [SimpleType]
     [CCode (
         cname="CameraFileInfoPreview",
@@ -174,14 +176,11 @@ namespace GPhoto {
         public CameraFileInfoFields fields;
         public CameraFileStatus status;
         public ulong size;
-        public string type;
+        public char type[64];
         public uint width;
         public uint height;
-        public string name;
-        public CameraFilePermissions permissions;
-        public time_t mtime;
     }
-    
+
     [CCode (
         cname="CameraFileOperation",
         cheader_filename="gphoto2/gphoto2-abilities-list.h",
@@ -196,7 +195,7 @@ namespace GPhoto {
         AUDIO,
         EXIF
     }
-    
+
     [CCode (
         cname="CameraFilePermissions",
         cheader_filename="gphoto2/gphoto2-filesys.h",
@@ -209,7 +208,7 @@ namespace GPhoto {
         DELETE,
         ALL
     }
-    
+
     [CCode (
         cname="CameraFileStatus",
         cheader_filename="gphoto2/gphoto2-filesys.h",
@@ -219,7 +218,7 @@ namespace GPhoto {
         NOT_DOWNLOADED,
         DOWNLOADED
     }
-    
+
     [CCode (
         cname="CameraFileType",
         cheader_filename="gphoto2/gphoto2-file.h",
@@ -233,7 +232,7 @@ namespace GPhoto {
         EXIF,
         METADATA
     }
-    
+
     [CCode (
         cname="CameraFolderOperation",
         cheader_filename="gphoto2/gphoto2-abilities-list.h",
@@ -247,7 +246,7 @@ namespace GPhoto {
         MAKE_DIR,
         REMOVE_DIR
     }
-    
+
     [Compact]
     [CCode (
         cname="CameraList",
@@ -264,14 +263,14 @@ namespace GPhoto {
         public Result append(string name, string value);
         public Result reset();
         public Result sort();
-        public Result find_by_name(out int? index, string name);
+        public Result find_by_name(out int index, string name);
         public Result get_name(int index, out unowned string name);
         public Result get_value(int index, out unowned string value);
         public Result set_name(int index, string name);
         public Result set_value(int index, string value);
         public Result populate(string format, int count);
     }
-    
+
     [CCode (
         cname="CameraOperation",
         cheader_filename="gphoto2/gphoto2-abilities-list.h",
@@ -286,7 +285,7 @@ namespace GPhoto {
         CAPTURE_PREVIEW,
         CONFIG
     }
-    
+
     [CCode (
         cname="CameraStorageInfoFields",
         cheader_filename="gphoto2/gphoto2-filesys.h",
@@ -304,7 +303,7 @@ namespace GPhoto {
         FREESPACEKBYTES,
         FREESPACEIMAGES
     }
-    
+
     [SimpleType]
     [CCode (
         cname="CameraStorageInformation",
@@ -312,9 +311,9 @@ namespace GPhoto {
     )]
     public struct CameraStorageInformation {
         public CameraStorageInfoFields fields;
-        public string basedir;
-        public string label;
-        public string description;
+        public char basedir[256];
+        public char label[256];
+        public char description[256];
         public int type;
         public int fstype;
         public int access;
@@ -322,7 +321,7 @@ namespace GPhoto {
         public ulong freekbytes;
         public ulong freeimages;
     }
-    
+
     [Compact]
     [CCode (
         ref_function="GPHOTO_REF_CONTEXT",
@@ -334,29 +333,29 @@ namespace GPhoto {
         public Context();
         public void set_idle_func(ContextIdleFunc func);
         public void set_progress_funcs(
-            [CCode (delegate_target_pos=3.1)] ContextProgressStartFunc startFunc, 
-            [CCode (delegate_target_pos=3.1)] ContextProgressUpdateFunc updateFunc, 
+            [CCode (delegate_target_pos=3.1)] ContextProgressStartFunc startFunc,
+            [CCode (delegate_target_pos=3.1)] ContextProgressUpdateFunc updateFunc,
             [CCode (delegate_target_pos=3.1)] ContextProgressStopFunc stopFunc);
         public void set_error_func([CCode (delegate_target_pos=3.1)] ContextErrorFunc errorFunc);
         public void set_status_func([CCode (delegate_target_pos=3.1)] ContextStatusFunc statusFunc);
         public void set_message_func([CCode (delegate_target_pos=3.1)] ContextMessageFunc messageFunc);
     }
-    
+
     public delegate void ContextIdleFunc(Context context);
-    
+
     public delegate void ContextErrorFunc(Context context, string text);
-    
+
     public delegate void ContextStatusFunc(Context context, string text);
-    
+
     public delegate void ContextMessageFunc(Context context, string text);
-    
+
     // TODO: Support for va_args in Vala, esp. for delegates?
     public delegate uint ContextProgressStartFunc(Context context, float target, string text);
-    
+
     public delegate void ContextProgressUpdateFunc(Context context, uint id, float current);
-    
+
     public delegate void ContextProgressStopFunc(Context context, uint id);
-    
+
     [CCode (
         cheader_filename="gphoto2/gphoto2-file.h",
         cprefix="GP_MIME_"
@@ -382,7 +381,7 @@ namespace GPhoto {
         public const string ASF;
         public const string MPEG;
     }
-    
+
     [SimpleType]
     [CCode (
         destroy_function="",
@@ -402,7 +401,7 @@ namespace GPhoto {
         [CCode (cname="gp_port_info_set_library_filename")]
         public int set_library_filename(string lib);
     }
-    
+
     [Compact]
     [CCode (
         free_function="gp_port_info_list_free",
@@ -417,7 +416,7 @@ namespace GPhoto {
         public int lookup_path(string name);
         public Result get_info(int index, out PortInfo info);
     }
-    
+
     [CCode (
         cheader_filename="gphoto2/gphoto2-port-info-list.h",
         cprefix="GP_PORT_"
@@ -430,7 +429,7 @@ namespace GPhoto {
         DISK,
         PTPIP
     }
-    
+
     [CCode (
         cname="int",
         cheader_filename="gphoto2/gphoto2-result.h,gphoto2/gphoto2-port-result.h",
@@ -472,24 +471,25 @@ namespace GPhoto {
         CANCEL,
         CAMERA_ERROR,
         OS_FAILURE;
-        
+
         [CCode (cname="gp_port_result_as_string")]
         public unowned string as_string();
-        
+
         public string to_full_string() {
             return "%s (%d)".printf(as_string(), this);
         }
     }
-    
+
     [CCode (
         cheader_filename="gphoto2/gphoto2-version.h",
-        cprefix="GP_VERSION"
+        cprefix="GP_VERSION_"
     )]
     public enum VersionVerbosity {
         SHORT,
         VERBOSE
     }
-    
+
     public unowned string library_version(VersionVerbosity verbosity);
 }
 
+

From 9736a39acbd077350504b77a95f13ca14453d017 Mon Sep 17 00:00:00 2001
From: David Hewitt <davidmhewitt@gmail.com>
Date: Fri, 1 Oct 2021 15:15:42 +0100
Subject: [PATCH 2/3] Update fallback icon

---
 src/Views/ImportPage.vala | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/src/Views/ImportPage.vala b/src/Views/ImportPage.vala
index 6cd14a89..03f96ac5 100644
--- a/src/Views/ImportPage.vala
+++ b/src/Views/ImportPage.vala
@@ -312,10 +312,8 @@ class ImportPreview : CheckerboardItem {
             pixbuf = icon_theme.load_icon ("image-missing", 48, 0);
         } catch (Error e) {
             // Create an empty black pixbuf as a fallback
-            pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, 50, 50);
+            pixbuf = new Gdk.Pixbuf (Gdk.Colorspace.RGB, false, 8, 48, 48);
             pixbuf.fill (0);
-
-            warning("Could not load icon from theme: %s", e.message);
         }
 
         return pixbuf;

From 39809afe8d2b0f223d2a6aa77a612d6fd85042ce Mon Sep 17 00:00:00 2001
From: David Hewitt <davidmhewitt@gmail.com>
Date: Fri, 1 Oct 2021 15:21:44 +0100
Subject: [PATCH 3/3] Satisfy linter

---
 src/camera/GPhoto.vala | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/camera/GPhoto.vala b/src/camera/GPhoto.vala
index 06334e72..e97db7c3 100644
--- a/src/camera/GPhoto.vala
+++ b/src/camera/GPhoto.vala
@@ -132,11 +132,11 @@ public Bytes? camera_file_to_bytes (Context context, CameraFile file) {
     // CameraFile being the owner of the data. This way, the CameraFile is freed
     // when the Bytes are freed
     unowned uint8[] buffer = null;
-    var res = file.get_data(out buffer);
+    var res = file.get_data (out buffer);
     if (res != Result.OK)
         return null;
 
-    return Bytes.new_with_owner<GPhoto.CameraFile>(buffer, file);
+    return Bytes.new_with_owner<GPhoto.CameraFile> (buffer, file);
 }
 
 // Libgphoto will in some instances refuse to get metadata from a camera, but the camera is accessable as a