libmtp.c

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

C
2,016
字号
/** * Helper function to extract a unicode property off a device. * This is the standard way of retrieveing unicode device * properties as described by the PTP spec. * @param device a pointer to the device to get the property from. * @param unicstring a pointer to a pointer that will hold the *        property after this call is completed. * @param property the property to retrieve. * @return 0 on success, any other value means failure. */static int get_device_unicode_property(LIBMTP_mtpdevice_t *device,				       char **unicstring, uint16_t property){  PTPPropertyValue propval;  PTPParams *params = (PTPParams *) device->params;  uint16_t *tmp;  int i;  if (!ptp_property_issupported(params, property)) {    return -1;  }  // Unicode strings are 16bit unsigned integer arrays.  if (ptp_getdevicepropvalue(params,			     property,			     &propval,			     PTP_DTC_AUINT16) != PTP_RC_OK) {    return -1;  }  // Extract the actual array.  // printf("Array of %d elements\n", propval.a.count);  tmp = malloc((propval.a.count + 1)*sizeof(uint16_t));  for (i = 0; i < propval.a.count; i++) {    tmp[i] = propval.a.v[i].u16;    // printf("%04x ", tmp[i]);  }  tmp[propval.a.count] = 0x0000U;  free(propval.a.v);  *unicstring = utf16_to_utf8(device, tmp);  free(tmp);  return 0;}/** * This function returns the secure time as an XML document string from * the device. * @param device a pointer to the device to get the secure time for. * @param sectime the secure time string as an XML document or NULL if the call *         failed or the secure time property is not supported. This string *         must be <code>free()</code>:ed by the caller after use. * @return 0 on success, any other value means failure. */int LIBMTP_Get_Secure_Time(LIBMTP_mtpdevice_t *device, char ** const sectime){  return get_device_unicode_property(device, sectime, PTP_DPC_MTP_SecureTime);}/** * This function returns the device (public key) certificate as an * XML document string from the device. * @param device a pointer to the device to get the device certificate for. * @param devcert the device certificate as an XML string or NULL if the call *        failed or the device certificate property is not supported. This *        string must be <code>free()</code>:ed by the caller after use. * @return 0 on success, any other value means failure. */int LIBMTP_Get_Device_Certificate(LIBMTP_mtpdevice_t *device, char ** const devcert){  return get_device_unicode_property(device, devcert, PTP_DPC_MTP_DeviceCertificate);}/** * This function retrieves a list of supported file types, i.e. the file * types that this device claims it supports, e.g. audio file types that * the device can play etc. This list is mitigated to * inlcude the file types that libmtp can handle, i.e. it will not list * filetypes that libmtp will handle internally like playlists and folders. * @param device a pointer to the device to get the filetype capabilities for. * @param filetypes a pointer to a pointer that will hold the list of *        supported filetypes if the call was successful. This list must *        be <code>free()</code>:ed by the caller after use. * @param length a pointer to a variable that will hold the length of the *        list of supported filetypes if the call was successful. * @return 0 on success, any other value means failure. * @see LIBMTP_Get_Filetype_Description() */int LIBMTP_Get_Supported_Filetypes(LIBMTP_mtpdevice_t *device, uint16_t ** const filetypes,				  uint16_t * const length){  PTPParams *params = (PTPParams *) device->params;  uint16_t *localtypes;  uint16_t localtypelen;  uint32_t i;  // This is more memory than needed if there are unknown types, but what the heck.  localtypes = (uint16_t *) malloc(params->deviceinfo.ImageFormats_len * sizeof(uint16_t));  localtypelen = 0;  for (i=0;i<params->deviceinfo.ImageFormats_len;i++) {    uint16_t localtype = map_ptp_type_to_libmtp_type(params->deviceinfo.ImageFormats[i]);    if (localtype != LIBMTP_FILETYPE_UNKNOWN) {      localtypes[localtypelen] = localtype;      localtypelen++;    }  }  *filetypes = localtypes;  *length = localtypelen;  return 0;}/** * This creates a new file metadata structure and allocates memory * for it. Notice that if you add strings to this structure they * will be freed by the corresponding <code>LIBMTP_destroy_file_t</code> * operation later, so be careful of using strdup() when assigning * strings, e.g.: * * <pre> * LIBMTP_file_t *file = LIBMTP_new_file_t(); * file->filename = strdup(namestr); * .... * LIBMTP_destroy_file_t(file); * </pre> * * @return a pointer to the newly allocated metadata structure. * @see LIBMTP_destroy_file_t() */LIBMTP_file_t *LIBMTP_new_file_t(void){  LIBMTP_file_t *new = (LIBMTP_file_t *) malloc(sizeof(LIBMTP_file_t));  if (new == NULL) {    return NULL;  }  new->filename = NULL;  new->filesize = 0;  new->filetype = LIBMTP_FILETYPE_UNKNOWN;  new->next = NULL;  return new;}/** * This destroys a file metadata structure and deallocates the memory * used by it, including any strings. Never use a file metadata * structure again after calling this function on it. * @param file the file metadata to destroy. * @see LIBMTP_new_file_t() */void LIBMTP_destroy_file_t(LIBMTP_file_t *file){  if (file == NULL) {    return;  }  if (file->filename != NULL)    free(file->filename);  free(file);  return;}/*** THIS FUNCTION IS DEPRECATED. PLEASE UPDATE YOUR CODE IN ORDER * NOT TO USE IT. * @see LIBMTP_Get_Filelisting_With_Callback() */LIBMTP_file_t *LIBMTP_Get_Filelisting(LIBMTP_mtpdevice_t *device){  printf("WARNING: LIBMTP_Get_Filelisting() is deprecated.\n");  printf("WARNING: please update your code to use LIBMTP_Get_Filelisting_With_Callback()\n");  return LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);}/** * This returns a long list of all files available * on the current MTP device. Typical usage: * * <pre> * LIBMTP_file_t *filelist; * * filelist = LIBMTP_Get_Filelisting_With_Callback(device, callback, data); * while (filelist != NULL) { *   LIBMTP_file_t *tmp; * *   // Do something on each element in the list here... *   tmp = filelist; *   filelist = filelist->next; *   LIBMTP_destroy_file_t(tmp); * } * </pre> * * @param device a pointer to the device to get the file listing for. * @param callback a function to be called during the tracklisting retrieveal *               for displaying progress bars etc, or NULL if you don't want *               any callbacks. * @param data a user-defined pointer that is passed along to *             the <code>progress</code> function in order to *             pass along some user defined data to the progress *             updates. If not used, set this to NULL. * @return a list of files that can be followed using the <code>next</code> *         field of the <code>LIBMTP_file_t</code> data structure. *         Each of the metadata tags must be freed after use, and may *         contain only partial metadata information, i.e. one or several *         fields may be NULL or 0. * @see LIBMTP_Get_Filemetadata() */LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,                                                    LIBMTP_progressfunc_t const callback,                                                    void const * const data){  uint32_t i = 0;  LIBMTP_file_t *retfiles = NULL;  LIBMTP_file_t *curfile = NULL;  PTPParams *params = (PTPParams *) device->params;  // Get all the handles if we haven't already done that  if (params->handles.Handler == NULL) {    flush_handles(device);  }  for (i = 0; i < params->handles.n; i++) {    if (callback != NULL)      callback(i, params->handles.n, data);    LIBMTP_file_t *file;    PTPObjectInfo oi;    if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {      if (oi.ObjectFormat == PTP_OFC_Association) {	// MTP use thesis object format for folders which means	// these "files" will turn up on a folder listing instead.	continue;      }      // Allocate a new file type      file = LIBMTP_new_file_t();      file->parent_id = oi.ParentObject;      // Set the filetype      file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);      // Original file-specific properties      file->filesize = oi.ObjectCompressedSize;      if (oi.Filename != NULL) {	file->filename = strdup(oi.Filename);      }      // This is some sort of unique ID so we can keep track of the track.      file->item_id = params->handles.Handler[i];      // Add track to a list that will be returned afterwards.      if (retfiles == NULL) {	retfiles = file;	curfile = file;      } else {	curfile->next = file;	curfile = file;      }      // Call listing callback      // double progressPercent = (double)i*(double)100.0 / (double)params->handles.n;    } else {      printf("LIBMTP panic: Found a bad handle, trying to ignore it.\n");    }  } // Handle counting loop  return retfiles;}/** * This function retrieves the metadata for a single file off * the device. * * Do not call this function repeatedly! The file handles are linearly * searched O(n) and the call may involve (slow) USB traffic, so use * <code>LIBMTP_Get_Filelisting()</code> and cache the file, preferably * as an efficient data structure such as a hash list. * * @param device a pointer to the device to get the file metadata from. * @param fileid the object ID of the file that you want the metadata for. * @return a metadata entry on success or NULL on failure. * @see LIBMTP_Get_Filelisting() */LIBMTP_file_t *LIBMTP_Get_Filemetadata(LIBMTP_mtpdevice_t *device, uint32_t const fileid){  uint32_t i = 0;  PTPParams *params = (PTPParams *) device->params;  // Get all the handles if we haven't already done that  if (params->handles.Handler == NULL) {    flush_handles(device);  }  for (i = 0; i < params->handles.n; i++) {    LIBMTP_file_t *file;    PTPObjectInfo oi;    // Is this the file we're looking for?    if (params->handles.Handler[i] != fileid) {      continue;    }    if (ptp_getobjectinfo(params, params->handles.Handler[i], &oi) == PTP_RC_OK) {      if (oi.ObjectFormat == PTP_OFC_Association) {	// MTP use thesis object format for folders which means	// these "files" will turn up on a folder listing instead.	return NULL;      }      // Allocate a new file type      file = LIBMTP_new_file_t();      file->parent_id = oi.ParentObject;      // Set the filetype      file->filetype = map_ptp_type_to_libmtp_type(oi.ObjectFormat);      // Original file-specific properties      file->filesize = oi.ObjectCompressedSize;      if (oi.Filename != NULL) {	file->filename = strdup(oi.Filename);      }      // This is some sort of unique ID so we can keep track of the track.      file->item_id = params->handles.Handler[i];      return file;    } else {      return NULL;    }  }  return NULL;}/** * This creates a new track metadata structure and allocates memory * for it. Notice that if you add strings to this structure they * will be freed by the corresponding <code>LIBMTP_destroy_track_t</code> * operation later, so be careful of using strdup() when assigning * strings, e.g.: * * <pre> * LIBMTP_track_t *track = LIBMTP_new_track_t(); * track->title = strdup(titlestr); * .... * LIBMTP_destroy_track_t(track); * </pre> * * @return a pointer to the newly allocated metadata structure. * @see LIBMTP_destroy_track_t() */LIBMTP_track_t *LIBMTP_new_track_t(void){  LIBMTP_track_t *new = (LIBMTP_track_t *) malloc(sizeof(LIBMTP_track_t));  if (new == NULL) {    return NULL;  }  new->title = NULL;  new->artist = NULL;  new->album = NULL;  new->genre = NULL;  new->date = NULL;  new->filename = NULL;  new->duration = 0;  new->tracknumber = 0;  new->filesize = 0;  new->filetype = LIBMTP_FILETYPE_UNKNOWN;  new->samplerate = 0;  new->nochannels = 0;  new->wavecodec = 0;  new->bitrate = 0;  new->bitratetype = 0;  new->rating = 0;  new->usecount = 0;  new->next = NULL;  return new;}/** * This destroys a track metadata structure and deallocates the memory * used by it, including any strings. Never use a track metadata * structure again after calling this function on it. * @param track the track metadata to destroy. * @see LIBMTP_new_track_t() */void LIBMTP_destroy_track_t(LIBMTP_track_t *track){  if (track == NULL) {    return;  }  if (track->title != NULL)    free(track->title);  if (track->artist != NULL)    free(track->artist);  if (track->album != NULL)

⌨️ 快捷键说明

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