~ubuntu-branches/ubuntu/jaunty/beagle/jaunty-security

« back to all changes in this revision

Viewing changes to Util/F-Spot/Imaging/Exif.cs

  • Committer: Bazaar Package Importer
  • Author(s): Stefan Ebner
  • Date: 2008-05-04 00:31:32 UTC
  • mfrom: (1.1.21 upstream)
  • Revision ID: james.westby@ubuntu.com-20080504003132-2tkm5o8moo5952ri
Tags: 0.3.7-2ubuntu1
 * Merge from Debian unstable. (LP: #225746) Remaining Ubuntu changes:
  - debian/control:
    + Rename ice{weasel,dove}-beagle to {mozilla,thunderbird}-beagle and
      and update the dependencies accordingly.
    + Change Maintainer to Ubuntu Mono Team.
  - debian/rules:
    + Install the mozilla-beagle and thunderbird-beagle extensions.
  - ice{dove,weasel}.dirs:
    + Renamed to {mozilla,thunderbird}-beagle.dirs.
    + Fixed paths to point to usr/lib/{firefox,thunderbird}

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// Exif.cs : LibExif wrapper for FSpot
 
3
//
 
4
// Author:
 
5
//   Larry Ewing     (lewing@novell.com)
 
6
//   Ravi Pratap     (ravi@ximian.com)
 
7
//   Miguel de Icaza (miguel@ximian.com)
 
8
//
 
9
// (C) 2002, 2004, 2005 Novell, Inc.
 
10
//
 
11
 
 
12
using System;
 
13
using System.Collections;
 
14
using System.Runtime.InteropServices;
 
15
 
 
16
using Mono.Unix;
 
17
 
 
18
namespace Exif {
 
19
        public enum Tag {
 
20
                InteroperabilityIndex           = 0x0001,
 
21
                InteroperabilityVersion         = 0x0002,
 
22
                ImageWidth                      = 0x0100,
 
23
                ImageHeight                     = 0x0101,
 
24
                BitsPersample                   = 0x0102,
 
25
                Compression                     = 0x0103,
 
26
                PhotometricInterpretation       = 0x0106,
 
27
                FillOrder                       = 0x010a,
 
28
                DocumentName                    = 0x010d,
 
29
                ImageDescription                = 0x010e,
 
30
                Make                            = 0x010f,
 
31
                Model                           = 0x0110,
 
32
                StripOffsets                    = 0x0111,
 
33
                Orientation                     = 0x0112,
 
34
                SamplesPerPixel                 = 0x0115,
 
35
                RowsPerStrip                    = 0x0116,
 
36
                StripByteCounts                 = 0x0117,
 
37
                XResolution                     = 0x011a,
 
38
                YResolution                     = 0x011b,
 
39
                PlanarConfiguration             = 0x011c,
 
40
                ResolutionUnit                  = 0x0128,
 
41
                TransferFunction                = 0x012d,
 
42
                Software                        = 0x0131,
 
43
                DateTime                        = 0x0132,
 
44
                Artist                          = 0x013b,
 
45
                WhitePoint                      = 0x013e,
 
46
                PrimaryChromaticities           = 0x013f,
 
47
                TransferRange                   = 0x0156,
 
48
                JPEGProc                        = 0x0200,
 
49
                JPEGInterchangeFormat           = 0x0201,
 
50
                JPEGInterchangeFormatLength     = 0x0202,
 
51
                YCBCRCoefficients               = 0x0211,
 
52
                YCBCRSubSampling                = 0x0212,
 
53
                YCBCRPositioning                = 0x0213,
 
54
                ReferenceBlackWhite             = 0x0214,
 
55
                RelatedImageFileFormat          = 0x1000,
 
56
                RelatedImageWidth               = 0x1001,
 
57
                RelatedImageHeight              = 0x1002,
 
58
                CFARepeatPatternDim             = 0x828d,
 
59
                CFAPattern                      = 0x828e,
 
60
                BatteryLevel                    = 0x828f,
 
61
                Copyright                       = 0x8298,
 
62
                ExposureTime                    = 0x829a,
 
63
                FNumber                         = 0x829d,
 
64
                IPTCNAA                         = 0x83bb,
 
65
                ExifIfdPointer                  = 0x8769,
 
66
                InterColorProfile               = 0x8773,
 
67
                ExposureProgram                 = 0x8822,
 
68
                SpectralSensitivity             = 0x8824,
 
69
                GPSInfoIfdPointer               = 0x8825,
 
70
                ISOSpeedRatings                 = 0x8827,
 
71
                OECF                            = 0x8828,
 
72
                ExifVersion                     = 0x9000,
 
73
                DateTimeOriginal                = 0x9003,
 
74
                DateTimeDigitized               = 0x9004,
 
75
                ComponentsConfiguration         = 0x9101,
 
76
                CompressedBitsPerPixel          = 0x9102,
 
77
                ShutterSpeedValue               = 0x9201,
 
78
                ApertureValue                   = 0x9202,
 
79
                BrightnessValue                 = 0x9203,
 
80
                ExposureBiasValue               = 0x9204,
 
81
                MaxApertureValue                = 0x9205,
 
82
                SubjectDistance                 = 0x9206,
 
83
                MeteringMode                    = 0x9207,
 
84
                LightSource                     = 0x9208,
 
85
                Flash                           = 0x9209,
 
86
                FocalLength                     = 0x920a,
 
87
                SubjectArea                     = 0x9214,
 
88
                MakerNote                       = 0x927c,
 
89
                UserComment                     = 0x9286,
 
90
                SubSecTime                      = 0x9290,
 
91
                SubSecTimeOriginal              = 0x9291,
 
92
                SubSecTimeDigitized             = 0x9292,
 
93
                FlashPixVersion                 = 0xa000,
 
94
                ColorSpace                      = 0xa001,
 
95
                PixelXDimension                 = 0xa002,
 
96
                PixelYDimension                 = 0xa003,
 
97
                RelatedSoundFile                = 0xa004,
 
98
                InteroperabilityIfdPointer      = 0xa005,
 
99
                FlashEnergy                     = 0xa20b,
 
100
                SpatialFrequencyResponse        = 0xa20c,
 
101
                FocalPlaneXResolution           = 0xa20e,
 
102
                FocalPlaneYResolution           = 0xa20f,
 
103
                FocalPlaneResolutionUnit        = 0xa210,
 
104
                SubjectLocation                 = 0xa214,
 
105
                ExposureIndex                   = 0xa215,
 
106
                SensingMethod                   = 0xa217,
 
107
                FileSource                      = 0xa300,
 
108
                SceneType                       = 0xa301,
 
109
                NewCFAPattern                   = 0xa302,
 
110
                CustomRendered                  = 0xa401,
 
111
                ExposureMode                    = 0xa402,
 
112
                WhiteBalance                    = 0xa403,
 
113
                DigitalZoomRatio                = 0xa404,
 
114
                FocalLengthIn35mmFilm           = 0xa405,
 
115
                SceneCaptureType                = 0xa406,
 
116
                GainControl                     = 0xa407,
 
117
                Contrast                        = 0xa408,
 
118
                Saturation                      = 0xa409,
 
119
                Sharpness                       = 0xa40a,
 
120
                DeviceSettingDescription        = 0xa40b,
 
121
                SubjectDistanceRange            = 0xa40c,
 
122
                ImageUniqueId                   = 0xa420,
 
123
 
 
124
                // The Following IDs are not described the EXIF spec
 
125
 
 
126
                // The XMP spec declares that XMP data should live 0x2bc when
 
127
                // embedded in tiff images.
 
128
                XMP                             = 0x02bc,
 
129
                
 
130
                // Print Image Matching data
 
131
                PimIfdPointer              = 0xc4a5
 
132
        }
 
133
        
 
134
        public enum ByteOrder {
 
135
                Motorola,
 
136
                Intel
 
137
        }
 
138
        
 
139
        public enum ExifFormat {
 
140
                Byte      = 1,
 
141
                Ascii     = 2,
 
142
                Short     = 3,
 
143
                Long      = 4,
 
144
                Rational  = 5,
 
145
                Undefined = 7,
 
146
                Slong     = 9,
 
147
                SRational = 10
 
148
        }
 
149
        
 
150
        public enum Ifd {
 
151
                Zero = 0,
 
152
                One,
 
153
                Exif,
 
154
                Gps,
 
155
                InterOperability,
 
156
                Count
 
157
        }
 
158
        
 
159
        public class ExifUtil {
 
160
                
 
161
                [DllImport ("libexif.dll")]
 
162
                static extern IntPtr exif_tag_get_name (Tag tag);
 
163
                
 
164
                [DllImport ("libexif.dll")]
 
165
                static extern IntPtr exif_tag_get_title (Tag tag);
 
166
                
 
167
                [DllImport ("libexif.dll")]
 
168
                static extern IntPtr exif_tag_get_description (Tag tag);
 
169
                
 
170
                [DllImport ("libexif.dll")]
 
171
                static extern IntPtr exif_byte_order_get_name (ByteOrder order);
 
172
                
 
173
                [DllImport ("libexif.dll")]
 
174
                static extern IntPtr exif_format_get_name (ExifFormat format);
 
175
                
 
176
                [DllImport ("libexif.dll")]
 
177
                static extern char exif_format_get_size (ExifFormat format);
 
178
                
 
179
                [DllImport ("libexif.dll")]
 
180
                static extern IntPtr exif_ifd_get_name (Ifd ifd);
 
181
                
 
182
                public static string GetTagName (Tag tag)
 
183
                {
 
184
                        
 
185
                        IntPtr raw_ret = exif_tag_get_name (tag);
 
186
                        return Marshal.PtrToStringAnsi (raw_ret);
 
187
                }
 
188
                
 
189
                public static string GetTagTitle (Tag tag)
 
190
                {
 
191
                        IntPtr raw_ret = exif_tag_get_title (tag);
 
192
                        return Marshal.PtrToStringAnsi (raw_ret);
 
193
                }
 
194
                
 
195
                public static string GetTagDescription (Tag tag)
 
196
                {
 
197
                        IntPtr raw_ret = exif_tag_get_description (tag);
 
198
                        return Marshal.PtrToStringAnsi (raw_ret);
 
199
                }
 
200
                
 
201
                public static string GetByteOrderName (ByteOrder order)
 
202
                {
 
203
                        IntPtr raw_ret = exif_byte_order_get_name (order);
 
204
                        return Marshal.PtrToStringAnsi (raw_ret);
 
205
                }
 
206
                
 
207
                public static string GetFormatName (ExifFormat format)
 
208
                {
 
209
                        IntPtr raw_ret = exif_format_get_name (format);
 
210
                        return Marshal.PtrToStringAnsi (raw_ret);
 
211
                }
 
212
                
 
213
                public static char GetFormatSize (ExifFormat format)
 
214
                {
 
215
                        return exif_format_get_size (format);
 
216
                }
 
217
                
 
218
                public static string GetIfdName (Ifd ifd)
 
219
                {                       
 
220
                        IntPtr raw_ret = exif_ifd_get_name (ifd);
 
221
                        return Marshal.PtrToStringAnsi (raw_ret);
 
222
                }
 
223
                
 
224
                public static string GetIfdNameExtended (Ifd ifd)
 
225
                {
 
226
                        switch (ifd) {
 
227
                        case Ifd.Zero:
 
228
                                return Catalog.GetString ("Image Directory");
 
229
                        case Ifd.One:
 
230
                                return Catalog.GetString ("Thumbnail Directory");
 
231
                        case Ifd.Exif:
 
232
                                return Catalog.GetString ("Exif Directory");
 
233
                        case Ifd.Gps:
 
234
                                return Catalog.GetString ("GPS Directory");
 
235
                        case Ifd.InterOperability:
 
236
                                return Catalog.GetString ("InterOperability Directory");
 
237
                        default:
 
238
                                return Catalog.GetString ("Unknown Directory");
 
239
                        }
 
240
                }
 
241
                
 
242
                public static DateTime DateTimeFromString(string dt)
 
243
                {
 
244
                        // Exif DateTime strings are formatted as
 
245
                        //      "YYYY:MM:DD HH:MM:SS"
 
246
                        
 
247
                        string delimiters = " :";
 
248
                        string[] dt_data = dt.Split ( delimiters.ToCharArray(), 6 );
 
249
                        DateTime result;
 
250
                        try {
 
251
                        // Assume local time
 
252
                        result = new DateTime (Int32.Parse(dt_data[0]), Int32.Parse(dt_data[1]), Int32.Parse(dt_data[2]),
 
253
                                               Int32.Parse(dt_data[3]), Int32.Parse(dt_data[4]), Int32.Parse(dt_data[5]), DateTimeKind.Local);
 
254
                        } catch (FormatException) {
 
255
                                result = DateTime.MinValue;
 
256
                        }
 
257
                        
 
258
                        return result;
 
259
                }       
 
260
                
 
261
        }               
 
262
 
 
263
        public abstract class ExifObject : IDisposable {
 
264
                protected HandleRef handle;
 
265
                
 
266
                public HandleRef Handle {
 
267
                        get {
 
268
                                return handle;
 
269
                        }
 
270
                }
 
271
                
 
272
                public ExifObject () {}
 
273
 
 
274
                public ExifObject (IntPtr ptr)
 
275
                {
 
276
                        handle = new HandleRef (this, ptr);
 
277
                }
 
278
                
 
279
                protected abstract void Cleanup ();
 
280
                
 
281
                public void Dispose () {
 
282
                        Cleanup ();
 
283
                        System.GC.SuppressFinalize (this);
 
284
                }
 
285
                
 
286
                ~ExifObject ()
 
287
                {
 
288
                        Cleanup ();
 
289
                }
 
290
        }
 
291
        
 
292
        [StructLayout(LayoutKind.Sequential)]
 
293
        internal unsafe struct _ExifContent {
 
294
                public IntPtr entries;
 
295
                public uint count; 
 
296
                public IntPtr parent;
 
297
                
 
298
                public IntPtr priv;
 
299
        }
 
300
        
 
301
        public class ExifContent : ExifObject {
 
302
                ExifData parent;
 
303
                public ExifData Parent {
 
304
                        get {
 
305
                                return parent;
 
306
                        }
 
307
                }
 
308
 
 
309
                System.Collections.ArrayList entries;
 
310
                
 
311
                internal ExifContent (ExifData parent, IntPtr handle) : base (handle)
 
312
                {
 
313
                        this.parent = parent;
 
314
                        exif_content_ref (this.handle);
 
315
                }
 
316
                
 
317
                [DllImport ("libexif.dll")]
 
318
                static extern void exif_content_ref (HandleRef handle);
 
319
                
 
320
                [DllImport ("libexif.dll")]
 
321
                static extern void exif_content_unref (HandleRef handle);
 
322
                
 
323
                protected override void Cleanup ()
 
324
                {
 
325
                        exif_content_unref (handle);
 
326
                }
 
327
                
 
328
                [DllImport ("libexif.dll")]
 
329
                internal static extern void exif_content_remove_entry (HandleRef content, HandleRef entry);
 
330
                
 
331
                [DllImport ("libexif.dll")]
 
332
                internal static extern void exif_content_add_entry (HandleRef content, HandleRef entry);
 
333
                
 
334
                public ExifEntry Lookup (Tag tag)
 
335
                {
 
336
                        Assemble ();
 
337
                        
 
338
                        foreach (ExifEntry entry in entries) {
 
339
                                if (entry.Tag == tag) {
 
340
                                        return entry;
 
341
                                }
 
342
                        }               
 
343
                        
 
344
                        return null;
 
345
                }
 
346
 
 
347
                public bool Contains (ExifEntry entry)
 
348
                {
 
349
                        Assemble ();
 
350
 
 
351
                        return entries.Contains (entry);
 
352
                }
 
353
 
 
354
                public ExifEntry GetEntry (Tag tag)
 
355
                {
 
356
                        Assemble ();
 
357
                        
 
358
                        ExifEntry entry = Lookup (tag);
 
359
                        if (entry == null)
 
360
                                entry = new ExifEntry (this, tag);
 
361
 
 
362
                        return entry;
 
363
                }
 
364
 
 
365
                public void Add (ExifEntry entry)
 
366
                {
 
367
                        Assemble ();
 
368
 
 
369
                        entries.Add (entry);
 
370
                        // This call can recurse into this function but it protects
 
371
                        // itself by checking if it the content already contains the entry
 
372
                        entry.SetParent (this);
 
373
                        exif_content_add_entry (this.handle, entry.Handle);     
 
374
                }
 
375
 
 
376
                public void Remove (ExifEntry entry)
 
377
                {
 
378
                        Assemble ();
 
379
                        
 
380
                        entries.Remove (entry);
 
381
                        // This call can recurse into this function but it protects
 
382
                        // itself by checking if it the content already contains the entry
 
383
                        entry.SetParent (null);
 
384
                        exif_content_remove_entry (this.handle, entry.Handle);
 
385
                }
 
386
                
 
387
                public ExifEntry [] GetEntries () 
 
388
                {
 
389
                        Assemble ();
 
390
 
 
391
                        return (ExifEntry [])entries.ToArray (typeof (ExifEntry));
 
392
                }
 
393
                
 
394
                [DllImport ("libexif.dll")]
 
395
                internal static unsafe extern IntPtr exif_content_foreach_entry (HandleRef content,
 
396
                                                                                 ExifContentForeachEntryFunc func,
 
397
                                                                                 IntPtr data);
 
398
                
 
399
                internal delegate void ExifContentForeachEntryFunc (IntPtr entry_ptr, IntPtr data);
 
400
                
 
401
                void AssembleEntry (IntPtr entry, IntPtr data)
 
402
                {
 
403
                        entries.Add (new ExifEntry (this, entry));
 
404
                }
 
405
                
 
406
                ExifContentForeachEntryFunc func;
 
407
                
 
408
                public void  Assemble ()
 
409
                {
 
410
                        if (entries == null) {
 
411
                                        entries = new System.Collections.ArrayList ();
 
412
                                        
 
413
                                        func = new ExifContentForeachEntryFunc (AssembleEntry);
 
414
                                        exif_content_foreach_entry (this.Handle, func, IntPtr.Zero);
 
415
                        }
 
416
                }
 
417
        }
 
418
        
 
419
        
 
420
        [StructLayout(LayoutKind.Sequential)]
 
421
        internal struct _ExifEntry {
 
422
                public Tag tag;
 
423
                public int format;
 
424
                public uint components;
 
425
                public IntPtr data;
 
426
                public uint  size;
 
427
                
 
428
                public IntPtr parent;
 
429
                
 
430
                public IntPtr priv;
 
431
        }
 
432
        
 
433
        
 
434
        public class ExifEntry : ExifObject {
 
435
                ExifContent parent;
 
436
                public ExifContent Parent {
 
437
                        get {
 
438
                                unsafe {
 
439
                                        if (_handle->parent != parent.Handle.Handle)
 
440
                                                throw new Exception ("Invalid Object State");
 
441
                                        
 
442
                                        return parent;
 
443
                                }
 
444
                        }
 
445
                }
 
446
                // Don't use this unless you know exactly what you are doing
 
447
                internal void SetParent (ExifContent adoptor) {
 
448
                        // NOTE this api is ugly but the check prevent the parent state 
 
449
                        // from getting confused.  See ExifContent Add and Remove for the 
 
450
                        // other half.
 
451
                        if (parent != null && parent.Contains (this))
 
452
                                parent.Remove (this);
 
453
 
 
454
                        if (adoptor != null && !adoptor.Contains (this))
 
455
                                adoptor.Add (this);
 
456
                        
 
457
                        parent = adoptor;
 
458
                }
 
459
 
 
460
                internal ExifEntry (ExifContent parent, IntPtr native) : base (native)
 
461
                {
 
462
                        this.handle = new HandleRef (this, native);
 
463
                        this.parent = parent;
 
464
                        exif_entry_ref (this.handle);
 
465
                }
 
466
 
 
467
                [DllImport ("libexif.dll")]
 
468
                internal static extern IntPtr exif_entry_new ();
 
469
 
 
470
                [DllImport ("libexif.dll")]
 
471
                internal static extern void exif_entry_initialize (HandleRef handle, Tag tag);
 
472
 
 
473
                public ExifEntry (ExifContent parent, Tag tag)
 
474
                {
 
475
                        handle = new HandleRef (this, exif_entry_new ());
 
476
                        parent.Add (this);
 
477
                        this.Reset (tag);
 
478
                }
 
479
                
 
480
                public void Reset (Tag tag)
 
481
                {
 
482
                        unsafe {
 
483
                                // Free any exsting data so that _initialize will actually set the data
 
484
                                if (_handle->data != IntPtr.Zero)
 
485
                                        ExifData.free (_handle->data);
 
486
                                _handle->data = IntPtr.Zero;
 
487
                        }
 
488
 
 
489
                        exif_entry_initialize (handle, tag);
 
490
 
 
491
                        //FIXME the month string in time fields in libexif ix currently broken so we do our own. 
 
492
                        if (tag == Tag.DateTime
 
493
                            || tag == Tag.DateTimeOriginal
 
494
                            || tag == Tag.DateTimeDigitized)
 
495
                                this.SetData (System.DateTime.Now);
 
496
 
 
497
                }
 
498
 
 
499
 
 
500
                public void Reset ()
 
501
                {
 
502
                        Reset (Tag);
 
503
                }
 
504
 
 
505
                protected override void Cleanup ()
 
506
                {
 
507
                        exif_entry_unref (this.handle);
 
508
                }
 
509
                
 
510
                private unsafe _ExifEntry *_handle {
 
511
                        get {
 
512
                                        return (_ExifEntry *)handle.Handle;
 
513
                        }
 
514
                }
 
515
                
 
516
                public Tag Tag {
 
517
                        get {
 
518
                                unsafe {
 
519
                                        return _handle->tag;
 
520
                                }
 
521
                        }
 
522
                }
 
523
                
 
524
                public ExifFormat Format {
 
525
                        get {
 
526
                                unsafe {
 
527
                                        return (ExifFormat) _handle->format;
 
528
                                }
 
529
                        }
 
530
                }
 
531
                
 
532
                public byte [] Data {
 
533
                        get {
 
534
                                unsafe {
 
535
                                        byte [] data = new byte [_handle->size]; 
 
536
                                        
 
537
                                        if (data.Length > 0)
 
538
                                                Marshal.Copy (_handle->data, data, 0, (int)_handle->size);
 
539
                                        
 
540
                                        return data;
 
541
                                }
 
542
                        }
 
543
                }
 
544
                
 
545
                public void SetData (byte [] data, int size)
 
546
                {
 
547
                        unsafe {
 
548
                                if (data == null || data.Length == 0)
 
549
                                        throw new System.Exception ("Invalid Length");
 
550
                                
 
551
                                if (_handle->data != IntPtr.Zero)
 
552
                                        ExifData.free (_handle->data);
 
553
                                
 
554
                                _handle->data = ExifData.malloc ((uint)data.Length);
 
555
                                Marshal.Copy (data, 0, _handle->data, data.Length);
 
556
 
 
557
                                _handle->size = (uint) data.Length;
 
558
                                // This needs to be set per type as well but
 
559
                                // we do it here as well
 
560
                                _handle->components = (uint) (data.Length / size);
 
561
                        }
 
562
                }
 
563
                
 
564
                public void SetData (byte []data)
 
565
                {
 
566
                        SetData (data, 1);
 
567
                }
 
568
 
 
569
                public void SetData (uint s)
 
570
                {
 
571
                        this.SetData (FSpot.BitConverter.GetBytes (s, this.ByteOrder == ByteOrder.Intel), 4);
 
572
                }
 
573
 
 
574
                public void SetData (ushort s)
 
575
                {
 
576
                        this.SetData (FSpot.BitConverter.GetBytes (s, this.ByteOrder == ByteOrder.Intel), 2);
 
577
                }           
 
578
 
 
579
                public void SetData (string value)
 
580
                {
 
581
                        int len = System.Text.Encoding.UTF8.GetByteCount (value);
 
582
                        byte [] tmp = new byte [len + 1];
 
583
                        System.Text.Encoding.UTF8.GetBytes (value, 0, value.Length, tmp, 0);
 
584
                        tmp[len] = 0;
 
585
                        //System.Console.WriteLine ("value = {0} len = {1}", value, len);
 
586
                        SetData (tmp, 1);
 
587
                }
 
588
 
 
589
                public void SetData (System.DateTime time)
 
590
                {
 
591
                        SetData (time.ToString ("yyyy:MM:dd HH:mm:ss"));
 
592
                }
 
593
                
 
594
                private unsafe void PutBytes (byte *dest, byte *src, int count)
 
595
                {
 
596
                        int i = 0;
 
597
                        if (System.BitConverter.IsLittleEndian == (this.ByteOrder == ByteOrder.Intel)) {
 
598
                                for (i = 0; i < count; i++) {
 
599
                                        //System.Console.WriteLine ("Copying normal byte [{0}]= {1}", i, src[i]);
 
600
                                        dest [i] = src [i];
 
601
                                }
 
602
                        } else {
 
603
                                for (i = 0; i < count; i++) {
 
604
                                        //System.Console.WriteLine ("Copying swapped byte [{0}]= {1}", i, src[i]);
 
605
                                        dest [i] = src [count - i -1];  
 
606
                                }
 
607
                        }
 
608
                }
 
609
                
 
610
                private unsafe uint ToUInt (byte *src)
 
611
                {
 
612
                        uint value;
 
613
                        PutBytes ((byte *)&value, (byte *)src, 4);
 
614
                        return value;
 
615
                }
 
616
                
 
617
                private unsafe ushort ToUShort (byte *src)
 
618
                {
 
619
                        ushort value;
 
620
                        PutBytes ((byte *)&value, (byte *)src, 2);
 
621
                        return value;
 
622
                }
 
623
                
 
624
                public uint [] GetDataUInt () {
 
625
                        unsafe {
 
626
                                uint [] result = new uint [_handle->components];
 
627
                                uint *src = (uint *)_handle->data;
 
628
                                //System.Console.WriteLine ("copying {0} components", result.Length); 
 
629
                                for (int i = 0; i < result.Length; i++) {
 
630
                                        result [i] = ToUInt ((byte *)src);
 
631
                                        //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]);
 
632
                                        src += i;
 
633
                                }
 
634
                                
 
635
                                return result;
 
636
                        }
 
637
                }                       
 
638
 
 
639
                public ushort [] GetDataUShort () {
 
640
                        unsafe {
 
641
                                ushort [] result = new ushort [_handle->components];
 
642
                                ushort *src = (ushort *)_handle->data;
 
643
                                //System.Console.WriteLine ("copying {0} components", result.Length); 
 
644
                                for (int i = 0; i < result.Length; i++) {
 
645
                                        result [i] = ToUShort ((byte *)src);
 
646
                                        //System.Console.WriteLine ("value[{0}] = {1}", i, result [i]);
 
647
                                        src += i;
 
648
                                }
 
649
                                
 
650
                                return result;
 
651
                        }
 
652
                }
 
653
 
 
654
 
 
655
                public int [] GetDataInt () {
 
656
                        return null;
 
657
                }
 
658
 
 
659
                public ByteOrder ByteOrder
 
660
                {
 
661
                        get {
 
662
                                return parent.Parent.GetByteOrder ();
 
663
                        }
 
664
                }
 
665
 
 
666
                public string Description 
 
667
                {
 
668
                        get {
 
669
                                return ExifUtil.GetTagDescription (Tag);
 
670
                        }
 
671
                }
 
672
                
 
673
                public string Name
 
674
                {
 
675
                        get {
 
676
                                return ExifUtil.GetTagName (Tag);
 
677
                        }
 
678
                }
 
679
                
 
680
                public string Title
 
681
                {
 
682
                        get {
 
683
                                return ExifUtil.GetTagTitle (Tag);
 
684
                        }
 
685
                }
 
686
                
 
687
                static int fallback = 0;
 
688
                
 
689
                // FIXME this version is only valid in libexif 0.5
 
690
                [DllImport ("libexif.dll")]
 
691
                internal static extern IntPtr exif_entry_get_value (HandleRef handle);
 
692
                [DllImport ("libexif.dll")]
 
693
                internal static extern IntPtr exif_entry_get_value_brief (HandleRef handle);
 
694
                
 
695
                // FIXME this version is only valid in libexif 0.6
 
696
                [DllImport ("libexif.dll")]
 
697
                internal static extern IntPtr exif_entry_get_value (HandleRef handle, byte  [] value, int maxlen);
 
698
                
 
699
                public string Value
 
700
                {
 
701
                        get {
 
702
                                if (fallback == 0) {
 
703
                                        try {
 
704
                                                exif_entry_get_value_brief (this.Handle);
 
705
                                                fallback = 1;
 
706
                                        } catch (EntryPointNotFoundException) {
 
707
                                                fallback = -1;
 
708
                                        }
 
709
                                }
 
710
                                
 
711
                                if (fallback > 0) 
 
712
                                        return Marshal.PtrToStringAnsi (exif_entry_get_value (this.Handle));
 
713
                                else {
 
714
                                        byte [] value = new byte [1024];
 
715
                                        exif_entry_get_value (this.Handle, value, value.Length);
 
716
 
 
717
                                        int i;
 
718
                                        for (i = 0; i <  value.Length; i++) {
 
719
                                                if (value [i] == 0) 
 
720
                                                        break;
 
721
                                        }
 
722
                                        int len = System.Math.Max (i, 0);
 
723
                                        if (len == 0)
 
724
                                                return null;
 
725
                                        
 
726
                                        return System.Text.Encoding.UTF8.GetString (value, 0, len);
 
727
                                }
 
728
                        }
 
729
                }
 
730
                
 
731
                [DllImport ("libexif.dll")]
 
732
                internal static extern void exif_entry_ref (HandleRef handle);
 
733
                
 
734
                [DllImport ("libexif.dll")]
 
735
                internal static extern void exif_entry_unref (HandleRef handle);
 
736
        }
 
737
        
 
738
        [StructLayout(LayoutKind.Sequential)]
 
739
        internal struct _ExifData {
 
740
                internal IntPtr ifd0;
 
741
                internal IntPtr ifd1;
 
742
                internal IntPtr ifd_exif;
 
743
                internal IntPtr ifd_gps;
 
744
                internal IntPtr ifd_interop;
 
745
 
 
746
                internal IntPtr  data;
 
747
                internal int     size;
 
748
                
 
749
                internal IntPtr priv;
 
750
        }
 
751
        
 
752
        public class ExifData : ExifObject {
 
753
                System.Collections.ArrayList ifds;
 
754
                
 
755
                [DllImport ("libexif.dll")]
 
756
                internal static extern IntPtr exif_data_new ();
 
757
                
 
758
                public ExifData ()
 
759
                {
 
760
                        handle = new HandleRef (this, exif_data_new ());
 
761
                }
 
762
                
 
763
                [DllImport ("libexif.dll")]
 
764
                internal static extern IntPtr exif_data_new_from_file (string path);
 
765
                        
 
766
                public ExifData (string filename)
 
767
                {
 
768
                        handle = new HandleRef (this, exif_data_new_from_file (filename));
 
769
                }
 
770
                
 
771
                [DllImport ("libexif.dll")]
 
772
                internal static extern IntPtr exif_data_new_from_data (byte [] data, uint size);
 
773
 
 
774
                public ExifData (byte [] data)
 
775
                {
 
776
                        handle = new HandleRef (this, exif_data_new_from_data (data, (uint) data.Length));
 
777
                }
 
778
 
 
779
                public ExifData (byte [] data, uint size)
 
780
                {
 
781
                        handle = new HandleRef (this, exif_data_new_from_data (data, size));
 
782
                }
 
783
 
 
784
                [DllImport ("libc")] 
 
785
                internal static extern void free (IntPtr address);
 
786
                
 
787
                [DllImport ("libc")] 
 
788
                internal static extern IntPtr malloc (uint size);
 
789
                
 
790
                [DllImport ("libexif.dll")]
 
791
                private static extern void exif_data_save_data (HandleRef handle, out IntPtr content, out uint size);           
 
792
                public byte [] Save ()
 
793
                {
 
794
                        Byte [] content = null;
 
795
                        uint size;
 
796
                        IntPtr data;
 
797
                        unsafe {
 
798
                                exif_data_save_data (handle, out data, out size);
 
799
                                
 
800
                                content = new byte [size];
 
801
                                Marshal.Copy (data, content, 0, (int)size);
 
802
                                free (data);
 
803
                        }
 
804
                                
 
805
                        //System.Console.WriteLine ("Saved {0} bytes", content.Length);
 
806
                        return content;
 
807
                }
 
808
                
 
809
                [DllImport ("libexif.dll")]
 
810
                internal static extern void exif_data_unref (HandleRef data);
 
811
                
 
812
                [DllImport ("libexif.dll")]
 
813
                internal static extern void exif_data_free (HandleRef data);
 
814
 
 
815
                protected override void Cleanup ()
 
816
                {
 
817
                        exif_data_unref (handle);
 
818
                }
 
819
                
 
820
                [DllImport ("libexif.dll")]
 
821
                internal static extern void exif_data_dump (HandleRef data);
 
822
 
 
823
                public void Dump ()
 
824
                {
 
825
                        exif_data_dump (handle);
 
826
                }
 
827
                
 
828
                public ExifContent GetContents (Ifd ifd)
 
829
                {
 
830
                        Assemble ();
 
831
 
 
832
                        return (ExifContent) ifds [(int)ifd];
 
833
                }
 
834
 
 
835
                public ExifContent [] GetContents ()
 
836
                {
 
837
                        Assemble ();
 
838
 
 
839
                        return (ExifContent []) ifds.ToArray (typeof (ExifContent));
 
840
                }
 
841
 
 
842
                [DllImport("libexif.dll")]
 
843
                internal static extern ByteOrder exif_data_get_byte_order (HandleRef handle);
 
844
                
 
845
                public ByteOrder GetByteOrder ()
 
846
                {
 
847
                        return exif_data_get_byte_order (handle);
 
848
                }
 
849
                
 
850
                internal delegate void ExifDataForeachContentFunc (IntPtr content, IntPtr data);
 
851
                
 
852
                [DllImport ("libexif.dll")]
 
853
                internal unsafe static extern void exif_data_foreach_content(HandleRef handle, ExifDataForeachContentFunc func, IntPtr data);
 
854
                
 
855
                unsafe void AssembleIfds (IntPtr content, IntPtr data)
 
856
                {
 
857
                        ifds.Add (new ExifContent (this, content));
 
858
                }
 
859
                
 
860
                public ExifEntry LookupFirst (Tag tag)
 
861
                {
 
862
                        Assemble ();
 
863
                        foreach (ExifContent content in ifds) {
 
864
                                if (content == null)
 
865
                                        continue;
 
866
                                
 
867
                                ExifEntry entry = content.Lookup (tag);
 
868
                                if (entry != null)
 
869
                                        return entry;
 
870
                        }
 
871
                        return null;
 
872
                }
 
873
 
 
874
                public string LookupFirstValue (Tag tag)
 
875
                {
 
876
                        ExifEntry entry = LookupFirst (tag);
 
877
                        if (entry != null) {
 
878
                                return entry.Value;
 
879
                        }
 
880
                        return null;
 
881
                }
 
882
 
 
883
                public void Assemble ()
 
884
                {
 
885
                        if (ifds == null) {
 
886
                                ifds = new System.Collections.ArrayList ();
 
887
 
 
888
                                if (handle.Handle != IntPtr.Zero)
 
889
                                        exif_data_foreach_content (handle, new ExifDataForeachContentFunc (AssembleIfds), IntPtr.Zero);
 
890
                        }
 
891
                }
 
892
                
 
893
                byte [] empty = new byte [0];
 
894
                public byte [] Data {
 
895
                        get {
 
896
                                unsafe {
 
897
                                        _ExifData * obj = (_ExifData *) Handle.Handle;
 
898
                                        byte [] result;
 
899
                                        
 
900
                                        if (obj == null || obj->data == (IntPtr) 0)
 
901
                                                result = empty;
 
902
                                        else {
 
903
                                                result = new byte [obj->size];
 
904
                                                Marshal.Copy (obj->data, result, 0, obj->size);
 
905
                                                
 
906
                                        }
 
907
                                        return result;
 
908
                                }
 
909
                        }
 
910
                        set {
 
911
                                unsafe {
 
912
                                        _ExifData * obj = (_ExifData *) Handle.Handle;
 
913
                                        if (value.Length > 65533)
 
914
                                                throw new System.Exception ("Thumbnail too large");
 
915
                                        
 
916
                                        if (obj->data != IntPtr.Zero)
 
917
                                                free (obj->data);
 
918
                                        
 
919
                                        obj->data = malloc ((uint)value.Length);
 
920
                                        Marshal.Copy (value, 0, obj->data, value.Length);
 
921
                                }
 
922
                        }
 
923
                }
 
924
        }
 
925
}