libmtp.c

来自「Media transfer protocol implementation o」· C语言 代码 · 共 2,016 行 · 第 1/5 页

C
2,016
字号
/** * \file libmtp.c * This file provides an interface "glue" to the underlying * PTP implementation from libgphoto2. It uses some local * code to convert from/to UTF-8 (stored in unicode.c/.h) * and some small utility functions, mainly for debugging * (stored in util.c/.h). * * The three PTP files (ptp.c, ptp.h and ptp-pack.c) are * plain copied from the libhphoto2 codebase. * * The files libusb-glue.c/.h are just what they say: an * interface to libusb for the actual, physical USB traffic. */#include "libmtp.h"#include "unicode.h"#include "ptp.h"#include "libusb-glue.h"#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#ifdef _MSC_VER // For MSVC++#define USE_WINDOWS_IO_H#include <io.h>#endif/* Enable enhanced MTP commands */#define ENABLE_MTP_ENHANCED/* * On MacOS (Darwin) and *BSD we're not using glibc, but libiconv. * glibc knows that UCS-2 is to be in the local machine endianness, * whereas libiconv does not. So we construct this macro to get * things right. Reportedly, glibc 2.1.3 has a bug so that UCS-2 * is always bigendian though, we would need to work around that * too... */#ifndef __GLIBC__#define UCS_2_INTERNAL "UCS-2-INTERNAL"#else#if (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 )#error "Too old glibc. This versions iconv() implementation cannot be trusted."#endif#define UCS_2_INTERNAL "UCS-2"#endif/* * This is a mapping between libmtp internal MTP filetypes and * the libgphoto2/PTP equivalent defines. We need this because * otherwise the libmtp.h device has to be dependent on ptp.h * to be installed too, and we don't want that. *///typedef struct filemap_struct filemap_t;typedef struct filemap_struct {  char *description; /**< Text description for the file type */  LIBMTP_filetype_t id; /**< LIBMTP internal type for the file type */  uint16_t ptp_id; /**< PTP ID for the filetype */  struct filemap_struct *next;} filemap_t;// Global variables// This holds the global filetype mapping tablestatic filemap_t *filemap = NULL;/* * Forward declarations of local (static) functions. */static int register_filetype(char const * const description, LIBMTP_filetype_t const id,			     uint16_t const ptp_id);static void init_filemap();static void flush_handles(LIBMTP_mtpdevice_t *device);static int check_if_file_fits(LIBMTP_mtpdevice_t *device, uint64_t const filesize);static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype);static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype);static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,				       char **unicstring, uint16_t property);static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,				    uint16_t const attribute_id);static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,				    uint16_t const attribute_id, uint32_t const value_default);static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,				    uint16_t const attribute_id, uint16_t const value_default);static uint8_t get_u8_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,				  uint16_t const attribute_id, uint8_t const value_default);static int set_object_string(LIBMTP_mtpdevice_t *device, uint32_t const object_id,			     uint16_t const attribute_id, char const * const string);static int set_object_u32(LIBMTP_mtpdevice_t *device, uint32_t const object_id,			  uint16_t const attribute_id, uint32_t const value);static int set_object_u16(LIBMTP_mtpdevice_t *device, uint32_t const object_id,			  uint16_t const attribute_id, uint16_t const value);static int set_object_u8(LIBMTP_mtpdevice_t *device, uint32_t const object_id,			 uint16_t const attribute_id, uint8_t const value);static void get_track_metadata(LIBMTP_mtpdevice_t *device, uint16_t objectformat,			       LIBMTP_track_t *track);static int create_new_abstract_list(LIBMTP_mtpdevice_t *device,				    char const * const name,				    uint32_t const parenthandle,				    uint16_t const objectformat,				    char const * const suffix,				    uint32_t * const newid,				    uint32_t const * const tracks,				    uint32_t const no_tracks);static MTPPropList *New_MTP_Prop_Entry();static void Destroy_MTP_Prop_Entry(MTPPropList *prop);/** * Create a new file mapping entry * @return a newly allocated filemapping entry. */static filemap_t *new_filemap_entry(){  filemap_t *filemap;  filemap = (filemap_t *)malloc(sizeof(filemap_t));  if( filemap != NULL ) {    filemap->description = NULL;    filemap->id = LIBMTP_FILETYPE_UNKNOWN;    filemap->ptp_id = PTP_OFC_Undefined;    filemap->next = NULL;  }  return filemap;}/** * Register an MTP or PTP filetype for data retrieval * * @param description Text description of filetype * @param id libmtp internal filetype id * @param ptp_id PTP filetype id * @return 0 for success any other value means error.*/static int register_filetype(char const * const description, LIBMTP_filetype_t const id,			     uint16_t const ptp_id){  filemap_t *new = NULL, *current;  // Has this LIBMTP filetype been registered before ?  current = filemap;  while (current != NULL) {    if(current->id == id) {      break;    }    current = current->next;  }  // Create the entry  if(current == NULL) {    new = new_filemap_entry();    if(new == NULL) {      return 1;    }    new->id = id;    if(description != NULL) {      new->description = strdup(description);    }    new->ptp_id = ptp_id;    // Add the entry to the list    if(filemap == NULL) {      filemap = new;    } else {      current = filemap;      while (current->next != NULL ) current=current->next;      current->next = new;    }    // Update the existing entry  } else {    if (current->description != NULL) {      free(current->description);    }    current->description = NULL;    if(description != NULL) {      current->description = strdup(description);    }    current->ptp_id = ptp_id;  }  return 0;}static void init_filemap(){  register_filetype("RIFF WAVE file", LIBMTP_FILETYPE_WAV, PTP_OFC_WAV);  register_filetype("ISO MPEG Audio Layer 3", LIBMTP_FILETYPE_MP3, PTP_OFC_MP3);  register_filetype("Microsoft Windows Media Audio", LIBMTP_FILETYPE_WMA, PTP_OFC_MTP_WMA);  register_filetype("Ogg container format", LIBMTP_FILETYPE_OGG, PTP_OFC_MTP_OGG);  register_filetype("Audible.com Audio Codec", LIBMTP_FILETYPE_AUDIBLE, PTP_OFC_MTP_AudibleCodec);  register_filetype("Advanced Acoustic Coding", LIBMTP_FILETYPE_MP4, PTP_OFC_MTP_MP4);  register_filetype("Undefined audio file", LIBMTP_FILETYPE_UNDEF_AUDIO, PTP_OFC_MTP_UndefinedAudio);  register_filetype("Microsoft Windows Media Video", LIBMTP_FILETYPE_WMV, PTP_OFC_MTP_WMV);  register_filetype("Audio Video Interleave", LIBMTP_FILETYPE_AVI, PTP_OFC_AVI);  register_filetype("MPEG video stream", LIBMTP_FILETYPE_MPEG, PTP_OFC_MPEG);  register_filetype("Microsoft Advanced Systems Format", LIBMTP_FILETYPE_ASF, PTP_OFC_ASF);  register_filetype("Apple Quicktime container format", LIBMTP_FILETYPE_QT, PTP_OFC_QT);  register_filetype("Undefined video file", LIBMTP_FILETYPE_UNDEF_VIDEO, PTP_OFC_MTP_UndefinedVideo);  register_filetype("JPEG file", LIBMTP_FILETYPE_JPEG, PTP_OFC_EXIF_JPEG);  register_filetype("JFIF file", LIBMTP_FILETYPE_JFIF, PTP_OFC_JFIF);  register_filetype("TIFF bitmap file", LIBMTP_FILETYPE_TIFF, PTP_OFC_TIFF);  register_filetype("BMP bitmap file", LIBMTP_FILETYPE_BMP, PTP_OFC_BMP);  register_filetype("GIF bitmap file", LIBMTP_FILETYPE_GIF, PTP_OFC_GIF);  register_filetype("PICT bitmap file", LIBMTP_FILETYPE_PICT, PTP_OFC_PICT);  register_filetype("Portable Network Graphics", LIBMTP_FILETYPE_PNG, PTP_OFC_PNG);  register_filetype("Microsoft Windows Image Format", LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT, PTP_OFC_MTP_WindowsImageFormat);  register_filetype("VCalendar version 1", LIBMTP_FILETYPE_VCALENDAR1, PTP_OFC_MTP_vCalendar1);  register_filetype("VCalendar version 2", LIBMTP_FILETYPE_VCALENDAR2, PTP_OFC_MTP_vCalendar2);  register_filetype("VCard version 2", LIBMTP_FILETYPE_VCARD2, PTP_OFC_MTP_vCard2);  register_filetype("VCard version 3", LIBMTP_FILETYPE_VCARD3, PTP_OFC_MTP_vCard3);  register_filetype("Undefined Windows executable file", LIBMTP_FILETYPE_WINEXEC, PTP_OFC_MTP_UndefinedWindowsExecutable);  register_filetype("Text file", LIBMTP_FILETYPE_TEXT, PTP_OFC_Text);  register_filetype("HTML file", LIBMTP_FILETYPE_HTML, PTP_OFC_HTML);  register_filetype("Undefined filetype", LIBMTP_FILETYPE_UNKNOWN, PTP_OFC_Undefined);}/** * Returns the PTP filetype that maps to a certain libmtp internal file type. * @param intype the MTP library interface type * @return the PTP (libgphoto2) interface type */static uint16_t map_libmtp_type_to_ptp_type(LIBMTP_filetype_t intype){  filemap_t *current;  current = filemap;  while (current != NULL) {    if(current->id == intype) {      return current->ptp_id;    }    current = current->next;  }  // printf("map_libmtp_type_to_ptp_type: unknown filetype.\n");  return PTP_OFC_Undefined;}/** * Returns the PTP internal filetype that maps to a certain libmtp * interface file type. * @param intype the PTP (libgphoto2) interface type * @return the MTP library interface type */static LIBMTP_filetype_t map_ptp_type_to_libmtp_type(uint16_t intype){  filemap_t *current;  current = filemap;  while (current != NULL) {    if(current->ptp_id == intype) {      return current->id;    }    current = current->next;  }  // printf("map_ptp_type_to_libmtp_type: unknown filetype.\n");  return LIBMTP_FILETYPE_UNKNOWN;}/** * Initialize the library. You are only supposed to call this * one, before using the library for the first time in a program. * Never re-initialize libmtp! * * The only thing this does at the moment is to initialise the * filetype mapping table. */void LIBMTP_Init(void){  init_filemap();  return;}/** * This helper function returns a textual description for a libmtp * file type to be used in dialog boxes etc. * @param intype the libmtp internal filetype to get a description for. * @return a string representing the filetype, this must <b>NOT</b> *         be free():ed by the caller! */char const * LIBMTP_Get_Filetype_Description(LIBMTP_filetype_t intype){  filemap_t *current;  current = filemap;  while (current != NULL) {    if(current->id == intype) {      return current->description;    }    current = current->next;  }  return "Unknown filetype";}/** * Retrieves a string from an object * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @return valid string or NULL on failure. The returned string *         must bee <code>free()</code>:ed by the caller after *         use. */static char *get_string_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,				    uint16_t const attribute_id){  PTPPropertyValue propval;  char *retstring = NULL;  PTPParams *params = (PTPParams *) device->params;  uint16_t ret;  if ( device == NULL || object_id == 0) {    return NULL;  }  ret = ptp_mtp_getobjectpropvalue(params, object_id, attribute_id, &propval, PTP_DTC_STR);  if (ret == PTP_RC_OK) {    if (propval.str != NULL) {      retstring = (char *) strdup(propval.str);      free(propval.str);    }  }  return retstring;}/** * Retrieves an unsigned 32-bit integer from an object attribute * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @param value_default Default value to return on failure * @return the value */static uint32_t get_u32_from_object(LIBMTP_mtpdevice_t *device,uint32_t const object_id,				    uint16_t const attribute_id, uint32_t const value_default){  PTPPropertyValue propval;  uint32_t retval = value_default;  PTPParams *params = (PTPParams *) device->params;  uint16_t ret;  if ( device == NULL ) {    return value_default;  }  ret = ptp_mtp_getobjectpropvalue(params, object_id,                                   attribute_id,                                   &propval,                                   PTP_DTC_UINT32);  if (ret == PTP_RC_OK) {    retval = propval.u32;  }  return retval;}/** * Retrieves an unsigned 16-bit integer from an object attribute * * @param device a pointer to an MTP device. * @param object_id Object reference * @param attribute_id PTP attribute ID * @param value_default Default value to return on failure * @return a value */static uint16_t get_u16_from_object(LIBMTP_mtpdevice_t *device, uint32_t const object_id,				    uint16_t const attribute_id, uint16_t const value_default){  PTPPropertyValue propval;  uint16_t retval = value_default;  PTPParams *params = (PTPParams *) device->params;  uint16_t ret;  if ( device == NULL ) {    return value_default;  }  ret = ptp_mtp_getobjectpropvalue(params, object_id,                                   attribute_id,                                   &propval,                                   PTP_DTC_UINT16);  if (ret == PTP_RC_OK) {    retval = propval.u16;  }  return retval;}/** * Retrieves an unsigned 8-bit integer from an object attribute * * @param device a pointer to an MTP device. * @param object_id Object reference

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?