void SetExtendedTimeStampTimes(ExtraField_ExtendedTimestamp tstamp, ref DateTime modTime, ref DateTime accTime, ref DateTime createTime)
        {
            if (!tstamp.DataValid)
            {
                return;
            }

            if (tstamp.ModificationTime != DateTime.MinValue)
            {
                modTime = tstamp.ModificationTime;
            }
            if (!tstamp.Local)
            {
                return;
            }

            if (tstamp.AccessTime != DateTime.MinValue)
            {
                accTime = tstamp.AccessTime;
            }
            if (tstamp.CreationTime != DateTime.MinValue)
            {
                createTime = tstamp.CreationTime;
            }
        }
        /// <summary>
        /// Adds the file to the archive. <paramref name="sourcePath"/> is either a relative or absolute
        /// path to the file to add to the archive. If <paramref name="sourcePath"/> is an absolute path,
        /// it will be converted to a relative one by removing the root of the path (<code>/</code> on Unix
        /// and <code>X://</code> on Windows) and stored using the resulting path in the archive. If, however,
        /// the <paramref name="archivePath"/> parameter is present it represents a full in-archive (that is -
        /// without the <code>/</code> or <code>X://</code> part) path of the file including the file name.
        /// </summary>
        /// <returns>The file.</returns>
        /// <param name="sourcePath">Source path.</param>
        /// <param name="archivePath">Path in the archive, including file name.</param>
        /// <param name="permissions">Permissions.</param>
        /// <param name="compressionMethod">Compression method.</param>
        /// <param name="overwriteExisting">Overwrite existing entries in the archive.</param>
        public ZipEntry AddFile(string sourcePath, string archivePath = null,
                                EntryPermissions permissions          = EntryPermissions.Default,
                                CompressionMethod compressionMethod   = CompressionMethod.Default,
                                bool overwriteExisting = true)
        {
            if (String.IsNullOrEmpty(sourcePath))
            {
                throw new ArgumentException("Must not be null or empty", nameof(sourcePath));
            }

            bool isDir = PlatformServices.Instance.IsDirectory(this, sourcePath);

            if (permissions == EntryPermissions.Default)
            {
                permissions = PlatformServices.Instance.GetFilesystemPermissions(this, sourcePath);
                if (permissions == EntryPermissions.Default)
                {
                    permissions = isDir ? DefaultDirectoryPermissions : DefaultFilePermissions;
                }
            }

            if (PlatformServices.Instance.IsRegularFile(this, sourcePath))
            {
                return(AddStream(new FileStream(sourcePath, FileMode.Open, FileAccess.Read), archivePath ?? sourcePath, permissions, compressionMethod, overwriteExisting,
                                 modificationTime: File.GetLastWriteTimeUtc(sourcePath)));
            }

            string destPath = EnsureArchivePath(archivePath ?? sourcePath, isDir);
            long   index    = PlatformServices.Instance.StoreSpecialFile(this, sourcePath, archivePath, out compressionMethod);

            if (index < 0)
            {
                throw GetErrorException();
            }
            if (Native.zip_set_file_compression(archive, (ulong)index, isDir ? CompressionMethod.Store : compressionMethod, 0) < 0)
            {
                throw GetErrorException();
            }
            PlatformServices.Instance.SetEntryPermissions(this, sourcePath, (ulong)index, permissions);
            ZipEntry                     entry     = ReadEntry((ulong)index);
            IList <ExtraField>           fields    = new List <ExtraField> ();
            ExtraField_ExtendedTimestamp timestamp = new ExtraField_ExtendedTimestamp(entry, 0,
                                                                                      createTime: File.GetCreationTimeUtc(sourcePath),
                                                                                      accessTime: File.GetLastAccessTimeUtc(sourcePath),
                                                                                      modificationTime: File.GetLastWriteTimeUtc(sourcePath));

            fields.Add(timestamp);
            if (!PlatformServices.Instance.WriteExtraFields(this, entry, fields))
            {
                throw GetErrorException();
            }
            return(entry);
        }
        /// <summary>
        /// Adds the stream to the archive.
        /// </summary>
        /// <returns>A new ZipEntry for the stream</returns>
        /// <param name="stream">The stream to add to the archive.</param>
        /// <param name="archivePath">The fullpath for the entry in the archive</param>
        /// <param name="permissions">The permissions which the stream should have when extracted (Unix Only)</param>
        /// <param name="compressionMethod">The compression method to use</param>
        /// <param name="overwriteExisting">If true an existing entry will be overwritten. If false and an existing entry exists and error will be raised</param>
        public ZipEntry AddStream(Stream stream, string archivePath, EntryPermissions permissions = EntryPermissions.Default, CompressionMethod compressionMethod = CompressionMethod.Default, bool overwriteExisting = true, DateTime?modificationTime = null)
        {
            if (stream == null)
            {
                throw new ArgumentNullException(nameof(stream));
            }
            sources.Add(stream);
            string destPath = EnsureArchivePath(archivePath);
            var    handle   = GCHandle.Alloc(stream, GCHandleType.Normal);
            IntPtr h        = GCHandle.ToIntPtr(handle);
            IntPtr source   = Native.zip_source_function(archive, callback, h);
            long   index    = Native.zip_file_add(archive, destPath, source, overwriteExisting ? OperationFlags.Overwrite : OperationFlags.None);

            if (index < 0)
            {
                throw GetErrorException();
            }
            if (Native.zip_set_file_compression(archive, (ulong)index, compressionMethod, 0) < 0)
            {
                throw GetErrorException();
            }
            if (permissions == EntryPermissions.Default)
            {
                permissions = DefaultFilePermissions;
            }
            PlatformServices.Instance.SetEntryPermissions(this, (ulong)index, permissions, false);
            ZipEntry                     entry     = ReadEntry((ulong)index);
            IList <ExtraField>           fields    = new List <ExtraField> ();
            ExtraField_ExtendedTimestamp timestamp = new ExtraField_ExtendedTimestamp(entry, 0, modificationTime: modificationTime ?? DateTime.UtcNow);

            fields.Add(timestamp);
            if (!PlatformServices.Instance.WriteExtraFields(this, entry, fields))
            {
                throw GetErrorException();
            }
            return(entry);
        }