Add MTP plugin using routines adapted from banshee, not sure if this works or not

This commit is contained in:
Michael Becker 2019-09-17 01:42:30 -04:00
parent 8d70789cfb
commit 92606e1a0f
16 changed files with 2448 additions and 0 deletions

View File

@ -0,0 +1,33 @@
//
// Methods.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Runtime.InteropServices;
namespace UniversalEditor.Accessors.MTP.Internal.Linux
{
public class Methods
{
public const string LIBRARY_FILENAME = "gio";
[DllImport(LIBRARY_FILENAME)]
public static extern IntPtr g_file_new_for_uri(string uri);
}
}

View File

@ -0,0 +1,149 @@
/***************************************************************************
* AbstractTrackList.cs
*
* Copyright (C) 2008 Novell
* Copyright (C) 2010 Alan McGovern
* Authors:
* Gabriel Burt (gburt@novell.com)
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Mtp
{
public abstract class AbstractTrackList
{
private bool saved;
private List<uint> track_ids;
private MtpDevice device;
public abstract uint Count { get; protected set; }
public abstract string Name { get; set; }
protected abstract IntPtr TracksPtr { get; set; }
protected abstract int Create();
protected abstract int Update();
public bool Saved { get { return saved; } }
protected MtpDevice Device { get { return device; } }
public IList<uint> TrackIds
{
get { return track_ids; }
}
protected AbstractTrackList(MtpDevice device)
{
if (device == null)
{
throw new ArgumentNullException("device");
}
this.device = device;
if (track_ids == null)
{
track_ids = new List<uint>();
}
}
internal AbstractTrackList(MtpDevice device, IntPtr tracks, uint count) : this(device)
{
this.saved = true;
this.track_ids = new List<uint>();
if (tracks != IntPtr.Zero)
{
for (int i = 0; i < (int)count; i++)
track_ids.Add((uint)Marshal.ReadInt32(tracks, sizeof(int) * i));
}
}
public void AddTrack(Track track)
{
AddTrack(track.FileId);
}
public void AddTrack(uint track_id)
{
track_ids.Add(track_id);
Count++;
}
public void RemoveTrack(Track track)
{
RemoveTrack(track.FileId);
}
public void RemoveTrack(uint track_id)
{
track_ids.Remove(track_id);
Count--;
}
public void ClearTracks()
{
track_ids.Clear();
Count = 0;
}
public virtual void Save()
{
Count = (uint)track_ids.Count;
if (TracksPtr != IntPtr.Zero)
throw new InvalidOperationException("TracksPtr must be NULL when Save is called");
try
{
if (Count > 0)
{
TracksPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(uint)) * (int)Count);
for (int i = 0; i < track_ids.Count; i++)
Marshal.WriteInt32(TracksPtr, i * sizeof(int), (int)track_ids[i]);
}
if (saved)
{
saved = Update() == 0;
}
else
{
saved = Create() == 0;
}
}
finally
{
if (TracksPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(TracksPtr);
TracksPtr = IntPtr.Zero;
}
}
}
}
}

View File

@ -0,0 +1,234 @@
/***************************************************************************
* Album.cs
*
* Copyright (C) 2008 Novell
* Authors:
* Gabriel Burt (gburt@novell.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Mtp
{
public class Album : AbstractTrackList
{
internal static List<Album> GetAlbums(MtpDevice device)
{
List<Album> albums = new List<Album>();
IntPtr ptr = LIBMTP_Get_Album_List(device.Handle);
while (ptr != IntPtr.Zero)
{
// Destroy the struct *after* we use it to ensure we don't access freed memory
// for the 'tracks' variable
AlbumStruct d = (AlbumStruct)Marshal.PtrToStructure(ptr, typeof(AlbumStruct));
albums.Add(new Album(device, d));
LIBMTP_destroy_album_t(ptr);
ptr = d.next;
}
return albums;
}
private AlbumStruct album;
public uint AlbumId
{
get { return Saved ? album.album_id : 0; }
}
public override string Name
{
get { return album.name; }
set { album.name = value; }
}
public string Artist
{
get { return album.artist; }
set { album.artist = value; }
}
public string Genre
{
get { return album.genre; }
set { album.genre = value; }
}
public string Composer
{
get
{
return album.composer;
}
set
{
album.composer = value;
}
}
public override uint Count
{
get { return album.no_tracks; }
protected set { album.no_tracks = value; }
}
protected override IntPtr TracksPtr
{
get { return album.tracks; }
set { album.tracks = value; }
}
public Album(MtpDevice device, string name, string artist, string genre, string composer) : base(device)
{
Name = name;
Artist = artist;
Genre = genre;
Composer = composer;
Count = 0;
}
internal Album(MtpDevice device, AlbumStruct album) : base(device, album.tracks, album.no_tracks)
{
// Once we've loaded the tracks, set the TracksPtr to NULL as it
// will be freed when the Album constructor is finished.
this.album = album;
TracksPtr = IntPtr.Zero;
}
public override void Save()
{
Save(null, 0, 0);
}
public void Save(byte[] cover_art, uint width, uint height)
{
base.Save();
if (Saved)
{
if (cover_art == null)
{
return;
}
FileSampleData cover = new FileSampleData();
cover.data = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(byte)) * cover_art.Length);
Marshal.Copy(cover_art, 0, cover.data, cover_art.Length);
cover.size = (ulong)cover_art.Length;
cover.width = width;
cover.height = height;
cover.filetype = FileType.JPEG;
if (FileSample.LIBMTP_Send_Representative_Sample(Device.Handle, AlbumId, ref cover) != 0)
{
//Console.WriteLine ("Failed to send representative sample file for album {0} (id {1})", Name, AlbumId);
}
Marshal.FreeHGlobal(cover.data);
}
}
protected override int Create()
{
return LIBMTP_Create_New_Album(Device.Handle, ref album);
}
protected override int Update()
{
return LIBMTP_Update_Album(Device.Handle, ref album);
}
public void Remove()
{
MtpDevice.LIBMTP_Delete_Object(Device.Handle, AlbumId);
}
public override string ToString()
{
return String.Format("Album < Id: {4}, '{0}' by '{1}', genre '{2}', tracks {3} >", Name, Artist, Genre, Count, AlbumId);
}
public static Album GetById(MtpDevice device, uint id)
{
IntPtr ptr = Album.LIBMTP_Get_Album(device.Handle, id);
if (ptr == IntPtr.Zero)
{
return null;
}
else
{
// Destroy the struct after we use it to prevent accessing freed memory
// in the 'tracks' variable
AlbumStruct album = (AlbumStruct)Marshal.PtrToStructure(ptr, typeof(AlbumStruct));
var ret = new Album(device, album);
LIBMTP_destroy_album_t(ptr);
return ret;
}
}
//[DllImport (MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//internal static extern IntPtr LIBMTP_new_album_t (); // LIBMTP_album_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
static extern void LIBMTP_destroy_album_t(IntPtr album);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr LIBMTP_Get_Album_List(MtpDeviceHandle handle); // LIBMTP_album_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr LIBMTP_Get_Album(MtpDeviceHandle handle, uint albumId); // LIBMTP_album_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
internal static extern int LIBMTP_Create_New_Album(MtpDeviceHandle handle, ref AlbumStruct album);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
static extern int LIBMTP_Update_Album(MtpDeviceHandle handle, ref AlbumStruct album);
}
[StructLayout(LayoutKind.Sequential)]
internal struct AlbumStruct
{
public uint album_id;
public uint parent_id;
public uint storage_id;
[MarshalAs(UnmanagedType.LPStr)]
public string name;
[MarshalAs(UnmanagedType.LPStr)]
public string artist;
[MarshalAs(UnmanagedType.LPStr)]
public string composer;
[MarshalAs(UnmanagedType.LPStr)]
public string genre;
public IntPtr tracks;
public uint no_tracks;
public IntPtr next;
}
}

View File

@ -0,0 +1,85 @@
/***************************************************************************
* Error.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
namespace Mtp
{
public class LibMtpException : Exception
{
public LibMtpException(ErrorCode error) : this(error, error.ToString(), null)
{
}
public LibMtpException(ErrorCode error, string message) : this(error, message, null)
{
}
public LibMtpException(ErrorCode error, string message, Exception innerException)
: base(message, innerException)
{
}
internal static void CheckErrorStack(MtpDeviceHandle handle)
{
IntPtr ptr = MtpDevice.GetErrorStack(handle);
if (ptr == IntPtr.Zero)
return;
LibMtpException ex = null;
while (ptr != IntPtr.Zero)
{
Error e = (Error)Marshal.PtrToStructure(ptr, typeof(Error));
ex = new LibMtpException(e.errornumber, e.error_text, ex);
ptr = e.next;
}
// Once we throw the exception, clear the error stack
MtpDevice.ClearErrorStack(handle);
throw ex;
}
}
public struct Error
{
public ErrorCode errornumber;
[MarshalAs(UnmanagedType.LPStr)] public string error_text;
public IntPtr next; // LIBMTP_error_t*
public static void CheckError(ErrorCode errorCode)
{
if (errorCode != ErrorCode.None)
{
throw new LibMtpException(errorCode, errorCode.ToString());
}
}
}
}

View File

@ -0,0 +1,57 @@
/***************************************************************************
* MtpDevice.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Mtp
{
public enum ErrorCode
{
/*LIBMTP_ERROR_NONE,
LIBMTP_ERROR_GENERAL,
LIBMTP_ERROR_PTP_LAYER,
LIBMTP_ERROR_USB_LAYER,
LIBMTP_ERROR_MEMORY_ALLOCATION,
LIBMTP_ERROR_NO_DEVICE_ATTACHED,
LIBMTP_ERROR_STORAGE_FULL,
LIBMTP_ERROR_CONNECTING,
LIBMTP_ERROR_CANCELLED*/
None,
General,
PtpLayer,
UsbLayer,
MemoryAllocation,
NoDeviceAttached,
StorageFull,
Connecting,
Cancelled
}
}

View File

@ -0,0 +1,90 @@
/***************************************************************************
* File.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
namespace Mtp
{
public class File
{
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_new_file_t(); // LIBMTP_file_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_destroy_file_t(ref File file); // LIBMTP_file_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern string LIBMTP_Get_Filetype_Description(FileType type); // char const *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Filelisting(MtpDeviceHandle handle); // LIBMTP_file_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Filelisting_With_Callback(MtpDeviceHandle handle, ProgressFunction function, IntPtr data); // LIBMTP_file_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Filemetadata(MtpDeviceHandle handle, uint fileid); // LIBMTP_file_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Get_File_To_File(MtpDeviceHandle handle, uint fileId, string path, ProgressFunction function, IntPtr data);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_destroy_filesampledata_t(ref FileSampleData data); // LIBMTP_filesampledata_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Get_Representative_Sample_Format(MtpDeviceHandle handle, FileType type, IntPtr data_array);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Send_Representative_Sample(MtpDeviceHandle handle, uint id, ref FileSampleData sample);
}
[StructLayout(LayoutKind.Sequential)]
internal struct FileStruct
{
public int item_id;
public int parent_id;
public int storage_id;
[MarshalAs(UnmanagedType.LPStr)] public string filename;
public long filesize;
public FileType filetype;
public IntPtr next; // LIBMTP_file_t*
public File NextFile
{
get
{
if (next == IntPtr.Zero)
return null;
return (File)Marshal.PtrToStructure(next, typeof(File));
}
}
}
}

View File

@ -0,0 +1,57 @@
/***************************************************************************
* FileSampleData.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
namespace Mtp
{
internal static class FileSample
{
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern void LIBMTP_destroy_filesampledata_t(ref FileSampleData data); // LIBMTP_filesampledata_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern int LIBMTP_Get_Representative_Sample_Format(MtpDeviceHandle handle, FileType type, IntPtr data_array);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern int LIBMTP_Send_Representative_Sample(MtpDeviceHandle handle, uint id, ref FileSampleData sample);
}
[StructLayout(LayoutKind.Sequential)]
internal struct FileSampleData
{
public uint width;
public uint height;
public uint duration;
public FileType filetype;
public ulong size;
public IntPtr data;
}
}

View File

@ -0,0 +1,82 @@
/***************************************************************************
* Enums.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
namespace Mtp
{
public enum FileType
{
FOLDER,
WAV,
MP3,
WMA,
OGG,
AUDIBLE,
MP4,
UNDEF_AUDIO,
WMV,
AVI,
MPEG,
ASF,
QT,
UNDEF_VIDEO,
JPEG,
JFIF,
TIFF,
BMP,
GIF,
PICT,
PNG,
VCALENDAR1,
VCALENDAR2,
VCARD2,
VCARD3,
WINDOWSIMAGEFORMAT,
WINEXEC,
TEXT,
HTML,
FIRMWARE,
AAC,
MEDIACARD,
FLAC,
MP2,
M4A,
DOC,
XML,
XLS,
PPT,
MHT,
JP2,
JPX,
ALBUM,
PLAYLIST,
UNKNOWN
}
}

View File

@ -0,0 +1,313 @@
/***************************************************************************
* Folder.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Mtp
{
public class Folder
{
private MtpDevice device;
private uint folderId;
private uint parentId;
private string name;
internal uint FolderId
{
get { return folderId; }
}
public string Name
{
get { return name; }
}
internal uint ParentId
{
get { return parentId; }
}
internal Folder(uint folderId, uint parentId, string name, MtpDevice device)
{
this.device = device;
this.folderId = folderId;
this.parentId = parentId;
this.name = name;
}
internal Folder(FolderStruct folder, MtpDevice device)
: this(folder.folder_id, folder.parent_id, folder.name, device)
{
}
public Folder AddChild(string name)
{
if (string.IsNullOrEmpty(name))
throw new ArgumentNullException("name");
// First create the folder on the device and check for error
uint id = CreateFolder(device.Handle, name, FolderId);
FolderStruct f = new FolderStruct();
f.folder_id = id;
f.parent_id = FolderId;
f.name = name;
return new Folder(f, device);
}
public List<Folder> GetChildren()
{
IntPtr root = GetFolderList(device.Handle);
IntPtr ptr = Find(root, folderId);
FolderStruct f = (FolderStruct)Marshal.PtrToStructure(ptr, typeof(FolderStruct));
ptr = f.child;
List<Folder> folders = new List<Folder>();
while (ptr != IntPtr.Zero)
{
FolderStruct folder = (FolderStruct)Marshal.PtrToStructure(ptr, typeof(FolderStruct));
folders.Add(new Folder(folder, device));
ptr = folder.sibling;
}
LIBMTP_destroy_folder_t(root);
return folders;
}
private Folder CreateParentFolder()
{
return Find(device, parentId);
}
public bool HasAncestor(Folder ancestor)
{
if (ancestor == null)
{
throw new ArgumentNullException("ancestor");
}
if (device != ancestor.device)
{
throw new ArgumentException("Folders are on different devices");
}
bool hasAncestor = false;
if (parentId != 0)
{
if (parentId == ancestor.FolderId)
{
hasAncestor = true;
}
else
{
Folder parent = CreateParentFolder();
hasAncestor = parent.HasAncestor(ancestor);
}
}
return hasAncestor;
}
public void Remove()
{
MtpDevice.DeleteObject(device.Handle, FolderId);
}
public override string ToString()
{
return String.Format("{0} (id {1}, parent id {2})", Name, FolderId, ParentId);
}
internal static List<Folder> GetRootFolders(MtpDevice device)
{
List<Folder> folders = new List<Folder>();
IntPtr root = GetFolderList(device.Handle);
try
{
for (IntPtr ptr = root; ptr != IntPtr.Zero;)
{
FolderStruct folder = (FolderStruct)Marshal.PtrToStructure(ptr, typeof(FolderStruct));
folders.Add(new Folder(folder, device));
ptr = folder.sibling;
}
}
finally
{
// Recursively destroy the folder tree
LIBMTP_destroy_folder_t(root);
}
return folders;
}
internal static uint CreateFolder(MtpDeviceHandle handle, string name, uint parentId)
{
uint result = LIBMTP_Create_Folder(handle, name, parentId, 0);
if (result == 0)
{
LibMtpException.CheckErrorStack(handle);
throw new LibMtpException(ErrorCode.General, "Could not create folder on the device");
}
return result;
}
internal static void DestroyFolder(IntPtr folder)
{
LIBMTP_destroy_folder_t(folder);
}
internal static IntPtr Find(IntPtr folderList, uint folderId)
{
return LIBMTP_Find_Folder(folderList, folderId);
}
internal static Folder Find(MtpDevice device, uint folderId)
{
if (device == null)
{
throw new ArgumentNullException("device");
}
Folder folder = null;
IntPtr root = GetFolderList(device.Handle);
try
{
IntPtr ptr = Find(root, folderId);
if (ptr != IntPtr.Zero)
{
FolderStruct folderStruct = (FolderStruct)Marshal.PtrToStructure(ptr, typeof(FolderStruct));
folder = new Folder(folderStruct, device);
}
}
finally
{
DestroyFolder(root);
}
return folder;
}
internal static IntPtr GetFolderList(MtpDeviceHandle handle)
{
return LIBMTP_Get_Folder_List(handle);
}
// Folder Management
//[DllImport (MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern IntPtr LIBMTP_new_folder_t (); // LIBMTP_folder_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_destroy_folder_t(IntPtr folder);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Folder_List(MtpDeviceHandle handle); // LIBMTP_folder_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Find_Folder(IntPtr folderList, uint folderId); // LIBMTP_folder_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern uint LIBMTP_Create_Folder(MtpDeviceHandle handle, string name, uint parentId, uint storageId);
}
[StructLayout(LayoutKind.Sequential)]
internal struct FolderStruct
{
public uint folder_id;
public uint parent_id;
public uint storage_id;
[MarshalAs(UnmanagedType.LPStr)] public string name;
public IntPtr sibling; // LIBMTP_folder_t*
public IntPtr child; // LIBMTP_folder_t*
/*
public object NextSibling
{
get
{
if(sibling == IntPtr.Zero)
return null;
return (FolderStruct)Marshal.PtrToStructure(sibling, typeof(Folder));
}
}
public object NextChild
{
get
{
if(child == IntPtr.Zero)
return null;
return (FolderStruct)Marshal.PtrToStructure(child, typeof(Folder));
}
}
public Folder? Sibling
{
get
{
if (sibling == IntPtr.Zero)
return null;
return (Folder)Marshal.PtrToStructure(sibling, typeof(Folder));
}
}
public Folder? Child
{
get
{
if (child == IntPtr.Zero)
return null;
return (Folder)Marshal.PtrToStructure(child, typeof(Folder));
}
}*/
/*public IEnumerable<Folder> Children()
{
Folder? current = Child;
while(current.HasValue)
{
yield return current.Value;
current = current.Value.Child;
}
}*/
/*public IEnumerable<Folder> Siblings()
{
Folder? current = Sibling;
while(current.HasValue)
{
yield return current.Value;
current = current.Value.Sibling;
}
}*/
}
}

View File

@ -0,0 +1,642 @@
/***************************************************************************
* MtpDevice.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Mtp
{
public delegate int ProgressFunction(ulong sent, ulong total, IntPtr data);
public class MtpDevice : IDisposable
{
internal static IntPtr Offset(IntPtr ptr, int offset)
{
if (IntPtr.Size == 8)
{
return (IntPtr)(ptr.ToInt64() + offset);
}
else
{
return (IntPtr)(ptr.ToInt32() + offset);
}
}
internal MtpDeviceHandle Handle;
private MtpDeviceStruct device;
private string name;
private Folder albumFolder;
private Folder musicFolder;
private Folder organizerFolder;
private Folder pictureFolder;
private Folder playlistFolder;
private Folder podcastFolder;
private Folder textFolder;
private Folder videoFolder;
static MtpDevice()
{
LIBMTP_Init();
}
public int BatteryLevel
{
get
{
ushort level, maxLevel;
GetBatteryLevel(Handle, out maxLevel, out level);
return (int)((level * 100.0) / maxLevel);
}
}
public string SerialNumber
{
get { return GetSerialnumber(Handle); }
}
public string Version
{
get { return GetDeviceversion(Handle); }
}
public string ModelName
{
get; private set;
}
public string Name
{
get { return name; }
set
{
if (SetFriendlyName(Handle, value))
{
name = value;
}
}
}
public Folder AlbumFolder
{
get { return albumFolder; }
}
public Folder MusicFolder
{
get { return musicFolder; }
}
public Folder OrganizerFolder
{
get { return organizerFolder; }
}
public Folder PictureFolder
{
get { return pictureFolder; }
}
public Folder PlaylistFolder
{
get { return playlistFolder; }
}
public Folder PodcastFolder
{
get { return podcastFolder; }
}
public Folder TextFolder
{
get { return textFolder; }
}
public Folder VideoFolder
{
get { return videoFolder; }
}
internal MtpDevice(MtpDeviceHandle handle, MtpDeviceStruct device)
{
this.device = device;
this.Handle = handle;
this.name = GetFriendlyName(Handle);
this.ModelName = GetModelName(Handle);
SetDefaultFolders();
}
internal MtpDevice(IntPtr handle, bool ownsHandle, MtpDeviceStruct device)
: this(new MtpDeviceHandle(handle, ownsHandle), device)
{
}
/// <summary>
/// This function scans the top level directories and stores the relevant ones so they are readily
/// accessible
/// </summary>
private void SetDefaultFolders()
{
List<Folder> folders = GetRootFolders();
foreach (Folder f in folders)
{
if (f.FolderId == this.device.default_album_folder)
albumFolder = f;
else if (f.FolderId == device.default_music_folder)
{
musicFolder = f;
}
else if (f.FolderId == device.default_organizer_folder)
organizerFolder = f;
else if (f.FolderId == device.default_picture_folder)
pictureFolder = f;
else if (f.FolderId == device.default_playlist_folder)
playlistFolder = f;
else if (f.FolderId == device.default_text_folder)
textFolder = f;
else if (f.FolderId == device.default_video_folder)
videoFolder = f;
else if (f.FolderId == device.default_zencast_folder)
podcastFolder = f;
}
// Fix for devices that don't have an explicit playlist folder (see BGO #590342 and #733883)
if (playlistFolder == null && musicFolder != null)
{
playlistFolder = musicFolder;
}
}
public void Dispose()
{
if (!Handle.IsClosed)
Handle.Close();
}
public List<Folder> GetRootFolders()
{
return Folder.GetRootFolders(this);
}
public List<Track> GetAllTracks()
{
return GetAllTracks(null);
}
public List<Track> GetAllTracks(ProgressFunction callback)
{
IntPtr ptr = Track.GetTrackListing(Handle, callback, IntPtr.Zero);
List<Track> tracks = new List<Track>();
while (ptr != IntPtr.Zero)
{
// Destroy the struct after we use it to avoid potential referencing of freed memory.
TrackStruct track = (TrackStruct)Marshal.PtrToStructure(ptr, typeof(TrackStruct));
tracks.Add(new Track(track, this));
Track.DestroyTrack(ptr);
ptr = track.next;
}
return tracks;
}
public List<Playlist> GetPlaylists()
{
return Playlist.GetPlaylists(this);
}
public List<Album> GetAlbums()
{
return Album.GetAlbums(this);
}
public List<DeviceStorage> GetStorage()
{
List<DeviceStorage> storages = new List<DeviceStorage>();
IntPtr ptr = device.storage;
while (ptr != IntPtr.Zero)
{
DeviceStorage storage = (DeviceStorage)Marshal.PtrToStructure(ptr, typeof(DeviceStorage));
storages.Add(storage);
ptr = storage.Next;
}
return storages;
}
public void Remove(Track track)
{
DeleteObject(Handle, track.FileId);
}
public void UploadTrack(string path, Track track, Folder folder)
{
UploadTrack(path, track, folder, null);
}
public void UploadTrack(string path, Track track, Folder folder, ProgressFunction callback)
{
if (string.IsNullOrEmpty(path))
throw new ArgumentNullException("path");
if (track == null)
throw new ArgumentNullException("track");
folder = folder ?? MusicFolder;
if (folder != null)
{
track.trackStruct.parent_id = folder.FolderId;
}
// We send the trackstruct by ref so that when the file_id gets filled in, our copy is updated
Track.SendTrack(Handle, path, ref track.trackStruct, callback, IntPtr.Zero);
// LibMtp.GetStorage (Handle, 0);
}
public FileType[] GetFileTypes()
{
Int16[] ints = GetFileTypes(Handle);
FileType[] file_types = new FileType[ints.Length];
for (int i = 0; i < ints.Length; i++)
{
file_types[i] = (FileType)ints[i];
}
return file_types;
}
public static MtpDevice Connect(RawMtpDevice rawDevice)
{
var raw = rawDevice.RawDevice;
IntPtr device = LIBMTP_Open_Raw_Device(raw);
if (device == IntPtr.Zero)
return null;
return new MtpDevice(new MtpDeviceHandle(device, true), (MtpDeviceStruct)Marshal.PtrToStructure(device, typeof(MtpDeviceStruct)));
}
public static List<RawMtpDevice> Detect()
{
int count = 0;
IntPtr ptr = IntPtr.Zero;
LIBMTP_Detect_Raw_Devices(ref ptr, ref count);
List<RawMtpDevice> devices = new List<RawMtpDevice>();
for (int i = 0; i < count; i++)
{
IntPtr offset = Offset(ptr, i * Marshal.SizeOf(typeof(RawDeviceStruct)));
RawDeviceStruct d = (RawDeviceStruct)Marshal.PtrToStructure(offset, typeof(RawDeviceStruct));
devices.Add(new RawMtpDevice(d));
}
return devices;
}
internal static void ClearErrorStack(MtpDeviceHandle handle)
{
LIBMTP_Clear_Errorstack(handle);
}
internal static void DeleteObject(MtpDeviceHandle handle, uint object_id)
{
if (LIBMTP_Delete_Object(handle, object_id) != 0)
{
LibMtpException.CheckErrorStack(handle);
throw new LibMtpException(ErrorCode.General, "Could not delete the track");
}
}
internal static void GetBatteryLevel(MtpDeviceHandle handle, out ushort maxLevel, out ushort currentLevel)
{
int result = LIBMTP_Get_Batterylevel(handle, out maxLevel, out currentLevel);
if (result != 0)
{
LibMtpException.CheckErrorStack(handle);
throw new LibMtpException(ErrorCode.General, "Could not retrieve battery stats");
}
}
internal static void GetConnectedDevices(out IntPtr list)
{
Error.CheckError(LIBMTP_Get_Connected_Devices(out list));
}
internal static IntPtr GetErrorStack(MtpDeviceHandle handle)
{
return LIBMTP_Get_Errorstack(handle);
}
internal static string GetDeviceversion(MtpDeviceHandle handle)
{
IntPtr ptr = LIBMTP_Get_Deviceversion(handle);
if (ptr == IntPtr.Zero)
return null;
return StringFromIntPtr(ptr);
}
internal static string GetFriendlyName(MtpDeviceHandle handle)
{
IntPtr ptr = LIBMTP_Get_Friendlyname(handle);
if (ptr == IntPtr.Zero)
return null;
return StringFromIntPtr(ptr);
}
internal static bool SetFriendlyName(MtpDeviceHandle handle, string name)
{
bool success = LIBMTP_Set_Friendlyname(handle, name) == 0;
return success;
}
internal static string GetModelName(MtpDeviceHandle handle)
{
IntPtr ptr = LIBMTP_Get_Modelname(handle);
if (ptr == IntPtr.Zero)
return null;
return StringFromIntPtr(ptr);
}
internal static string GetSerialnumber(MtpDeviceHandle handle)
{
IntPtr ptr = LIBMTP_Get_Serialnumber(handle);
if (ptr == IntPtr.Zero)
return null;
return StringFromIntPtr(ptr);
}
internal static void GetStorage(MtpDeviceHandle handle, int sortMode)
{
LIBMTP_Get_Storage(handle, sortMode);
}
internal static Int16[] GetFileTypes(MtpDeviceHandle handle)
{
IntPtr types = IntPtr.Zero;
ushort count = 0;
if (LIBMTP_Get_Supported_Filetypes(handle, ref types, ref count) == 0)
{
Int16[] type_ary = new Int16[count];
Marshal.Copy(types, type_ary, 0, (int)count);
Marshal.FreeHGlobal(types);
return type_ary;
}
return new Int16[0];
}
internal static void ReleaseDevice(IntPtr handle)
{
LIBMTP_Release_Device(handle);
}
private static string StringFromIntPtr(IntPtr ptr)
{
int i = 0;
while (Marshal.ReadByte(ptr, i) != (byte)0) ++i;
byte[] s_buf = new byte[i];
Marshal.Copy(ptr, s_buf, 0, s_buf.Length);
string s = System.Text.Encoding.UTF8.GetString(s_buf);
Marshal.FreeCoTaskMem(ptr);
return s;
}
internal const string LibMtpLibrary = "libmtp.dll";
// Device Management
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_Init();
// Clears out the error stack and frees any allocated memory.
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_Clear_Errorstack(MtpDeviceHandle handle);
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
internal static extern int LIBMTP_Delete_Object(MtpDeviceHandle handle, uint object_id);
// Gets the first connected device:
//[DllImport (LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern IntPtr LIBMTP_Get_First_Device (); // LIBMTP_mtpdevice_t *
// Gets the storage information
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Get_Storage(MtpDeviceHandle handle, int sortMode);
// Formats the supplied storage device attached to the device
//[DllImport (LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern int LIBMTP_Format_Storage (MtpDeviceHandle handle, ref DeviceStorage storage);
// Counts the devices in the list
//[DllImport (LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern uint LIBMTP_Number_Devices_In_List (MtpDeviceHandle handle);
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern ErrorCode LIBMTP_Get_Connected_Devices(out IntPtr list); //LIBMTP_mtpdevice_t **
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern ErrorCode LIBMTP_Detect_Raw_Devices(ref IntPtr list, ref int count); //LIBMTP_raw_device_t
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Open_Raw_Device(RawDeviceStruct rawdevice);
// Deallocates the memory for the device
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_Release_Device(IntPtr device);
//[DllImport (LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern int LIBMTP_Reset_Device (MtpDeviceHandle handle);
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Get_Batterylevel(MtpDeviceHandle handle, out ushort maxLevel, out ushort currentLevel);
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Modelname(MtpDeviceHandle handle); // char *
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Serialnumber(MtpDeviceHandle handle); // char *
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Deviceversion(MtpDeviceHandle handle); // char *
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Friendlyname(MtpDeviceHandle handle); // char *
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Set_Friendlyname(MtpDeviceHandle handle, string name);
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Errorstack(MtpDeviceHandle handle); // LIBMTP_error_t *
[DllImport(LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Get_Supported_Filetypes(MtpDeviceHandle handle, ref IntPtr types, ref ushort count); // uint16_t **const
// void LIBMTP_Release_Device_List (LIBMTP_mtpdevice_t *)
// int LIBMTP_Detect_Descriptor (uint16_t *, uint16_t *);
/*
void LIBMTP_Dump_Device_Info (LIBMTP_mtpdevice_t *)
char * LIBMTP_Get_Syncpartner (LIBMTP_mtpdevice_t *)
int LIBMTP_Set_Syncpartner (LIBMTP_mtpdevice_t *, char const *const)
int LIBMTP_Get_Secure_Time (LIBMTP_mtpdevice_t *, char **const)
int LIBMTP_Get_Device_Certificate (LIBMTP_mtpdevice_t *, char **const)
*/
public static string GetMimeTypeFor(FileType type)
{
switch (type)
{
case FileType.MP3: return "audio/mpeg";
case FileType.OGG: return "audio/ogg";
case FileType.WMA: return "audio/x-ms-wma";
case FileType.WMV: return "video/x-ms-wmv";
case FileType.ASF: return "video/x-ms-asf";
case FileType.AAC: return "audio/x-aac";
case FileType.MP4: return "video/mp4";
case FileType.AVI: return "video/avi";
case FileType.WAV: return "audio/x-wav";
case FileType.MPEG: return "video/mpeg";
case FileType.FLAC: return "audio/flac";
case FileType.QT: return "video/quicktime";
case FileType.M4A: return "audio/mp4";
}
return null;
}
}
[StructLayout(LayoutKind.Sequential)]
internal struct DeviceEntry
{
[MarshalAs(UnmanagedType.LPStr)] public string vendor;
public ushort vendor_id;
[MarshalAs(UnmanagedType.LPStr)] public string product;
public ushort product_id;
public uint device_flags;
}
[StructLayout(LayoutKind.Sequential)]
public struct DeviceStorage
{
public uint Id;
public ushort StorageType;
public ushort FileSystemType;
public ushort AccessCapability;
public ulong MaxCapacity;
public ulong FreeSpaceInBytes;
public ulong FreeSpaceInObjects;
[MarshalAs(UnmanagedType.LPStr)] public string StorageDescription;
[MarshalAs(UnmanagedType.LPStr)] public string VolumeIdentifier;
public IntPtr Next; // LIBMTP_devicestorage_t*
public IntPtr Prev; // LIBMTP_devicestorage_t*
}
internal class MtpDeviceHandle : SafeHandle
{
private MtpDeviceHandle()
: base(IntPtr.Zero, true)
{
}
internal MtpDeviceHandle(IntPtr ptr, bool ownsHandle)
: base(IntPtr.Zero, ownsHandle)
{
SetHandle(ptr);
}
public override bool IsInvalid
{
get { return handle == IntPtr.Zero; }
}
protected override bool ReleaseHandle()
{
MtpDevice.ReleaseDevice(handle);
return true;
}
}
internal struct MtpDeviceStruct
{
public byte object_bitsize;
public IntPtr parameters; // void*
public IntPtr usbinfo; // void*
public IntPtr storage; // LIBMTP_devicestorage_t*
public IntPtr errorstack; // LIBMTP_error_t*
public byte maximum_battery_level;
public uint default_music_folder;
public uint default_playlist_folder;
public uint default_picture_folder;
public uint default_video_folder;
public uint default_organizer_folder;
public uint default_zencast_folder;
public uint default_album_folder;
public uint default_text_folder;
public IntPtr cd; // void*
public IntPtr next; // LIBMTP_mtpdevice_t*
}
[StructLayout(LayoutKind.Sequential)]
internal struct RawDeviceStruct
{
public DeviceEntry device_entry; /**< The device entry for this raw device */
public uint bus_location; /**< Location of the bus, if device available */
public byte devnum; /**< Device number on the bus, if device available */
}
public class RawMtpDevice
{
public uint BusNumber
{
get { return RawDevice.bus_location; }
}
public int DeviceNumber
{
get { return RawDevice.devnum; }
}
internal RawDeviceStruct RawDevice
{
get; private set;
}
internal RawMtpDevice(RawDeviceStruct device)
{
RawDevice = device;
}
}
}

View File

@ -0,0 +1,145 @@
/***************************************************************************
* Playlist.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Mtp
{
public sealed class Playlist : AbstractTrackList
{
internal static List<Playlist> GetPlaylists(MtpDevice device)
{
List<Playlist> playlists = new List<Playlist>();
IntPtr ptr = Playlist.LIBMTP_Get_Playlist_List(device.Handle);
while (ptr != IntPtr.Zero)
{
// Destroy the struct *after* we use it to ensure we don't access freed memory
// for the 'tracks' variable
PlaylistStruct d = (PlaylistStruct)Marshal.PtrToStructure(ptr, typeof(PlaylistStruct));
playlists.Add(new Playlist(device, d));
LIBMTP_destroy_playlist_t(ptr);
ptr = d.next;
}
return playlists;
}
private PlaylistStruct playlist;
public override uint Count
{
get { return playlist.no_tracks; }
protected set { playlist.no_tracks = value; }
}
public override string Name
{
get { return playlist.Name; }
set { playlist.Name = value; }
}
protected override IntPtr TracksPtr
{
get { return playlist.tracks; }
set { playlist.tracks = value; }
}
public Playlist(MtpDevice device, string name) : base(device)
{
this.playlist = new PlaylistStruct();
Name = name;
Count = 0;
}
internal Playlist(MtpDevice device, PlaylistStruct playlist) : base(device, playlist.tracks, playlist.no_tracks)
{
// Once we've loaded the tracks, set the TracksPtr to NULL as it
// will be freed when the Playlist constructor is finished.
this.playlist = playlist;
TracksPtr = IntPtr.Zero;
}
protected override int Create()
{
playlist.parent_id = Device.PlaylistFolder.FolderId;
return LIBMTP_Create_New_Playlist(Device.Handle, ref playlist);
}
protected override int Update()
{
return LIBMTP_Update_Playlist(Device.Handle, ref playlist);
}
public void Remove()
{
MtpDevice.LIBMTP_Delete_Object(Device.Handle, playlist.playlist_id);
}
// Playlist Management
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_destroy_playlist_t(IntPtr playlist);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Playlist_List(MtpDeviceHandle handle); // LIBMTP_playlist_t*
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Create_New_Playlist(MtpDeviceHandle handle, ref PlaylistStruct metadata);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Update_Playlist(MtpDeviceHandle handle, ref PlaylistStruct playlist);
}
[StructLayout(LayoutKind.Sequential)]
internal struct PlaylistStruct
{
public uint playlist_id;
public uint parent_id;
public uint storage_id;
[MarshalAs(UnmanagedType.LPStr)]
public string Name;
public IntPtr tracks; // int*
public uint no_tracks;
public IntPtr next; // LIBMTP_playlist_t*
/*public Playlist? Next
{
get
{
if (next == IntPtr.Zero)
return null;
return (Playlist)Marshal.PtrToStructure(next, typeof(Playlist));
}
}*/
}
}

View File

@ -0,0 +1,344 @@
/***************************************************************************
* Track.cs
*
* Copyright (C) 2006-2007 Alan McGovern
* Authors:
* Alan McGovern (alan.mcgovern@gmail.com)
****************************************************************************/
/* THIS FILE IS LICENSED UNDER THE MIT LICENSE AS OUTLINED IMMEDIATELY BELOW:
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
using System;
using System.Runtime.InteropServices;
namespace Mtp
{
public class Track
{
internal TrackStruct trackStruct;
private MtpDevice device;
public uint FileId
{
get { return trackStruct.item_id; }
}
public string Album
{
get { return trackStruct.album; }
set { trackStruct.album = value; }
}
public string Artist
{
get { return trackStruct.artist; }
set { trackStruct.artist = value; }
}
public uint Bitrate
{
get { return trackStruct.bitrate; }
}
public ushort BitrateType
{
get { return trackStruct.bitratetype; }
}
public string ReleaseDate
{
get { return trackStruct.date; }
set { trackStruct.date = value; }
}
public int Year
{
get { return ReleaseDate == null || ReleaseDate.Length < 4 ? 0 : Int32.Parse(ReleaseDate.Substring(0, 4)); }
set { ReleaseDate = String.Format("{0:0000}0101T0000.00", value); }
}
public uint Duration
{
get { return trackStruct.duration; }
set { trackStruct.duration = value; }
}
public string FileName
{
get { return trackStruct.filename; }
set { trackStruct.filename = value; }
}
public ulong FileSize
{
get { return trackStruct.filesize; }
set { trackStruct.filesize = value; }
}
public FileType FileType
{
get { return trackStruct.filetype; }
set { trackStruct.filetype = value; }
}
public string Genre
{
get { return trackStruct.genre; }
set { trackStruct.genre = value; }
}
public ushort NoChannels
{
get { return trackStruct.nochannels; }
set { trackStruct.nochannels = value; }
}
// 0 to 100
public ushort Rating
{
get { return trackStruct.rating; }
set
{
if (value < 0 || value > 100)
throw new ArgumentOutOfRangeException("Rating", "Rating must be between zero and 100");
trackStruct.rating = value;
}
}
public uint SampleRate
{
get { return trackStruct.samplerate; }
set { trackStruct.samplerate = value; }
}
public string Title
{
get { return trackStruct.title; }
set { trackStruct.title = value; }
}
public ushort TrackNumber
{
get { return trackStruct.tracknumber; }
set { trackStruct.tracknumber = value; }
}
public uint WaveCodec
{
get { return trackStruct.wavecodec; }
}
public uint UseCount
{
get { return trackStruct.usecount; }
set { trackStruct.usecount = value; }
}
public string Composer
{
get { return trackStruct.composer; }
set { trackStruct.composer = value; }
}
public Track(string filename, ulong filesize) : this(filename, filesize, null)
{
}
public Track(string filename, ulong filesize, MtpDevice device) : this(new TrackStruct(), device)
{
this.trackStruct.filename = filename;
this.trackStruct.filesize = filesize;
this.trackStruct.filetype = DetectFileType(this);
}
internal Track(TrackStruct track, MtpDevice device)
{
this.device = device;
this.trackStruct = track;
}
public bool InFolder(Folder folder)
{
return InFolder(folder, false);
}
public bool InFolder(Folder folder, bool recursive)
{
if (folder == null)
{
return false;
}
bool is_parent = trackStruct.parent_id == folder.FolderId;
if (is_parent || !recursive)
{
return is_parent;
}
return Folder.Find(device, trackStruct.parent_id).HasAncestor(folder);
}
public void Download(string path)
{
Download(path, null);
}
public void Download(string path, ProgressFunction callback)
{
if (String.IsNullOrEmpty(path))
throw new ArgumentException("Cannot be null or empty", "path");
GetTrack(device.Handle, trackStruct.item_id, path, callback, IntPtr.Zero);
}
public void UpdateMetadata()
{
UpdateTrackMetadata(device.Handle, ref trackStruct);
}
private static FileType DetectFileType(Track track)
{
string ext = System.IO.Path.GetExtension(track.FileName);
// Strip leading .
if (ext.Length > 0)
ext = ext.Substring(1, ext.Length - 1);
// this is a hack; catch all m4(a|b|v|p)
if (ext != null && ext.ToLower().StartsWith("m4"))
ext = "mp4";
FileType type = (FileType)Enum.Parse(typeof(FileType), ext, true);
//if (type == null)
// return FileType.UNKNOWN;
return type;
}
internal static void DestroyTrack(IntPtr track)
{
LIBMTP_destroy_track_t(track);
}
internal static void GetTrack(MtpDeviceHandle handle, uint trackId, string destPath, ProgressFunction callback, IntPtr data)
{
if (LIBMTP_Get_Track_To_File(handle, trackId, destPath, callback, data) != 0)
{
LibMtpException.CheckErrorStack(handle);
throw new LibMtpException(ErrorCode.General, "Could not download track from the device");
}
}
internal static IntPtr GetTrackListing(MtpDeviceHandle handle, ProgressFunction function, IntPtr data)
{
return LIBMTP_Get_Tracklisting_With_Callback(handle, function, data);
}
internal static void SendTrack(MtpDeviceHandle handle, string path, ref TrackStruct metadata, ProgressFunction callback, IntPtr data)
{
if (LIBMTP_Send_Track_From_File(handle, path, ref metadata, callback, data) != 0)
{
LibMtpException.CheckErrorStack(handle);
throw new LibMtpException(ErrorCode.General, "Could not upload the track");
}
}
internal static void UpdateTrackMetadata(MtpDeviceHandle handle, ref TrackStruct metadata)
{
if (LIBMTP_Update_Track_Metadata(handle, ref metadata) != 0)
throw new LibMtpException(ErrorCode.General);
}
//[DllImport (MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern IntPtr LIBMTP_new_track_t (); // LIBMTP_track_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern void LIBMTP_destroy_track_t(IntPtr track); // LIBMTP_track_t *
//[DllImport (MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern IntPtr LIBMTP_Get_Tracklisting (MtpDeviceHandle handle); //LIBMTP_track_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr LIBMTP_Get_Tracklisting_With_Callback(MtpDeviceHandle handle, ProgressFunction callback, IntPtr data); // LIBMTP_track_t *
//[DllImport (MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern IntPtr LIBMTP_Get_Trackmetadata (MtpDeviceHandle handle, uint trackId); // LIBMTP_track_t *
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Get_Track_To_File(MtpDeviceHandle handle, uint trackId, string path, ProgressFunction callback, IntPtr data);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Send_Track_From_File(MtpDeviceHandle handle, string path, ref TrackStruct track, ProgressFunction callback, IntPtr data);
[DllImport(MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
private static extern int LIBMTP_Update_Track_Metadata(MtpDeviceHandle handle, ref TrackStruct metadata);
//[DllImport (MtpDevice.LibMtpLibrary, CallingConvention = CallingConvention.Cdecl)]
//private static extern int LIBMTP_Track_Exists (MtpDeviceHandle handle, uint trackId);
//int LIBMTP_Get_Track_To_File_Descriptor (MtpDeviceHandle handle, uint trackId, int const, LIBMTP_progressfunc_t const, void const *const)
//int LIBMTP_Send_Track_From_File_Descriptor (MtpDeviceHandle handle, int const, LIBMTP_track_t *const, LIBMTP_progressfunc_t const, void const *const, uint32_t const)
}
[StructLayout(LayoutKind.Sequential)]
internal struct TrackStruct
{
public uint item_id;
public uint parent_id;
public uint storage_id;
[MarshalAs(UnmanagedType.LPStr)] public string title;
[MarshalAs(UnmanagedType.LPStr)] public string artist;
[MarshalAs(UnmanagedType.LPStr)] public string composer;
[MarshalAs(UnmanagedType.LPStr)] public string genre;
[MarshalAs(UnmanagedType.LPStr)] public string album;
[MarshalAs(UnmanagedType.LPStr)] public string date;
[MarshalAs(UnmanagedType.LPStr)] public string filename;
public ushort tracknumber;
public uint duration;
public uint samplerate;
public ushort nochannels;
public uint wavecodec;
public uint bitrate;
public ushort bitratetype;
public ushort rating; // 0 -> 100
public uint usecount;
public ulong filesize;
#if LIBMTP_SIZEOF_TIME_T_64
public ulong modificationdate;
#else
public uint modificationdate;
#endif
public FileType filetype;
public IntPtr next; // Track Null if last
/*
public Track? Next
{
get
{
if (next == IntPtr.Zero)
return null;
return (Track)Marshal.PtrToStructure(next, typeof(Track));
}
}*/
}
}

View File

@ -0,0 +1,102 @@
//
// MyClass.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UniversalEditor.IO;
namespace UniversalEditor.Accessors.MTP
{
public class MTPAccessor : Accessor
{
private static AccessorReference _ar = null;
protected override void InitializeInternal()
{
base.InitializeInternal();
}
public override long Length { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override void Seek(long offset, SeekOrigin origin)
{
throw new NotImplementedException();
}
protected override void CloseInternal()
{
throw new NotImplementedException();
}
protected override long GetPosition()
{
return 0;
}
protected override AccessorReference MakeReferenceInternal()
{
if (_ar == null)
{
_ar = base.MakeReferenceInternal();
_ar.Title = "Media Transfer Protocol (MTP)";
_ar.Schemas.Add("mtp-disabled");
_ar.ImportOptions.Add(new CustomOptionText("FileName", "File _name"));
}
return _ar;
}
private static IntPtr Offset(IntPtr ptr, int offset)
{
if (IntPtr.Size == 8)
{
return (IntPtr)(ptr.ToInt64() + offset);
}
else
{
return (IntPtr)(ptr.ToInt32() + offset);
}
}
protected override void OpenInternal()
{
/*
List<Mtp.RawMtpDevice> list = Mtp.MtpDevice.Detect();
Mtp.RawMtpDevice rawdev = list[0];
Mtp.MtpDevice dev = Mtp.MtpDevice.Connect(rawdev);
List<Mtp.Folder> listFolders = dev.GetRootFolders();
*/
// int w = Internal.Methods.Get_File_To_File(hRawDevice, 0, OriginalUri.LocalPath, null, IntPtr.Zero);
// IntPtr hFile = Internal.Linux.Methods.g_file_new_for_uri(OriginalUri.OriginalString);
}
protected override int ReadInternal(byte[] buffer, int start, int count)
{
throw new NotImplementedException();
}
protected override int WriteInternal(byte[] buffer, int start, int count)
{
throw new NotImplementedException();
}
}
}

View File

@ -0,0 +1,46 @@
//
// AssemblyInfo.cs
//
// Author:
// Mike Becker <alcexhim@gmail.com>
//
// Copyright (c) 2019 Mike Becker
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System.Reflection;
using System.Runtime.CompilerServices;
// Information about this assembly is defined by the following attributes.
// Change them to the values specific to your project.
[assembly: AssemblyTitle("UniversalEditor.Plugins.MTP")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("Mike Becker")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
[assembly: AssemblyVersion("1.0.*")]
// The following attributes are used to specify the signing key for the assembly,
// if desired. See the Mono documentation for more information about signing.
//[assembly: AssemblyDelaySign(false)]
//[assembly: AssemblyKeyFile("")]

View File

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{EA724755-2670-4520-86AA-657C8A124DB7}</ProjectGuid>
<OutputType>Library</OutputType>
<RootNamespace>UniversalEditor</RootNamespace>
<AssemblyName>UniversalEditor.Plugins.MTP</AssemblyName>
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>..\..\Output\Debug\Plugins</OutputPath>
<DefineConstants>DEBUG;</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<Optimize>true</Optimize>
<OutputPath>..\..\Output\Release\Plugins</OutputPath>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<ConsolePause>false</ConsolePause>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Accessors\MTP\MTPAccessor.cs" />
<Compile Include="Accessors\MTP\LibMTP\File.cs" />
<Compile Include="Accessors\MTP\LibMTP\FileType.cs" />
<Compile Include="Accessors\MTP\LibMTP\AbstractTrackList.cs" />
<Compile Include="Accessors\MTP\LibMTP\Album.cs" />
<Compile Include="Accessors\MTP\LibMTP\ErrorCode.cs" />
<Compile Include="Accessors\MTP\LibMTP\FileSampleData.cs" />
<Compile Include="Accessors\MTP\LibMTP\Folder.cs" />
<Compile Include="Accessors\MTP\LibMTP\MtpDevice.cs" />
<Compile Include="Accessors\MTP\LibMTP\Playlist.cs" />
<Compile Include="Accessors\MTP\LibMTP\Error.cs" />
<Compile Include="Accessors\MTP\LibMTP\Track.cs" />
<Compile Include="Accessors\MTP\Internal\Linux\Methods.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\Libraries\UniversalEditor.Core\UniversalEditor.Core.csproj">
<Project>{2D4737E6-6D95-408A-90DB-8DFF38147E85}</Project>
<Name>UniversalEditor.Core</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Folder Include="Accessors\" />
<Folder Include="Accessors\MTP\" />
<Folder Include="Accessors\MTP\LibMTP\" />
<Folder Include="Accessors\MTP\Internal\" />
<Folder Include="Accessors\MTP\Internal\Linux\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -141,6 +141,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins.Printing", "Plugins
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalEditor.Plugins.Generic.Printing", "Plugins.Printing\UniversalEditor.Plugins.Generic.Printing\UniversalEditor.Plugins.Generic.Printing.csproj", "{A3231B32-A0E4-4B67-9A09-310B25BBB9B6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UniversalEditor.Plugins.MTP", "Plugins\UniversalEditor.Plugins.MTP\UniversalEditor.Plugins.MTP.csproj", "{EA724755-2670-4520-86AA-657C8A124DB7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -405,6 +407,10 @@ Global
{A3231B32-A0E4-4B67-9A09-310B25BBB9B6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3231B32-A0E4-4B67-9A09-310B25BBB9B6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3231B32-A0E4-4B67-9A09-310B25BBB9B6}.Release|Any CPU.Build.0 = Release|Any CPU
{EA724755-2670-4520-86AA-657C8A124DB7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA724755-2670-4520-86AA-657C8A124DB7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA724755-2670-4520-86AA-657C8A124DB7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA724755-2670-4520-86AA-657C8A124DB7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{6F0AB1AF-E1A1-4D19-B19C-05BBB15C94B2} = {05D15661-E684-4EC9-8FBD-C014BA433CC5}
@ -470,6 +476,7 @@ Global
{242A32D8-9A3A-4FE3-902B-AB9C3154723A} = {05D15661-E684-4EC9-8FBD-C014BA433CC5}
{868A6888-EDB9-407E-A710-40F297D4EAB8} = {0399182F-AF56-4E86-B229-EAB38C2EE6AF}
{A3231B32-A0E4-4B67-9A09-310B25BBB9B6} = {FB678C6D-29A0-405B-BA86-E1EC12A96AA9}
{EA724755-2670-4520-86AA-657C8A124DB7} = {2ED32D16-6C06-4450-909A-40D32DA67FB4}
EndGlobalSection
GlobalSection(MonoDevelopProperties) = preSolution
Policies = $0