示例#1
0
void spl_to_playlist_t(LIBMTP_mtpdevice_t* device, PTPObjectInfo *oi,
                       const uint32_t id, LIBMTP_playlist_t * const pl)
{
    // Fill in playlist metadata
    // Use the Filename as the playlist name, dropping the ".spl" extension
    pl->name = malloc(sizeof(char)*(strlen(oi->Filename) -4 +1));
    memcpy(pl->name, oi->Filename, strlen(oi->Filename) -4);
    // Set terminating character
    pl->name[strlen(oi->Filename) - 4] = 0;
    pl->playlist_id = id;
    pl->parent_id = oi->ParentObject;
    pl->storage_id = oi->StorageID;
    pl->tracks = NULL;
    pl->no_tracks = 0;
    
    LIBMTP_PLST_DEBUG("pl->name='%s'\n", pl->name);
    
    // open a temporary file
    char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX";
    int fd = mkstemp(tmpname);
    if(fd < 0) {
        LIBMTP_ERROR("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno));
        return;
    }
    // make sure the file will be deleted afterwards
    if(unlink(tmpname) < 0)
        LIBMTP_ERROR("failed to delete temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno));
    int ret = LIBMTP_Get_File_To_File_Descriptor(device, pl->playlist_id, fd, NULL, NULL);
    if( ret < 0 ) {
        // FIXME     add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist: Could not get .spl playlist file.");
        close(fd);
        LIBMTP_INFO("FIXME closed\n");
    }
    
    text_t* p = read_into_spl_text_t(device, fd);
    close(fd);
    
    // FIXME cache these somewhere else so we don't keep calling this!
    LIBMTP_folder_t *folders;
    LIBMTP_file_t *files;
    folders = LIBMTP_Get_Folder_List(device);
    files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
    
    // convert the playlist listing to track ids
    pl->no_tracks = trackno_spl_text_t(p);
    LIBMTP_PLST_DEBUG("%u track%s found\n", pl->no_tracks, pl->no_tracks==1?"":"s");
    pl->tracks = malloc(sizeof(uint32_t)*(pl->no_tracks));
    tracks_from_spl_text_t(p, pl->tracks, folders, files);
    
    free_spl_text_t(p);
    
    // debug: add a break since this is the top level function call
    LIBMTP_PLST_DEBUG("------------\n\n");
}
示例#2
0
/**
 * This prints to stdout info about device being UNKNOWN, its
 * ids, and libmtp's version number.
 *
 * @param dev_number the device number
 * @param id_vendor vendor ID from the usb_device_desc struct
 * @param id_product product ID from the usb_device_desc struct
 */
void device_unknown(const int dev_number, const int id_vendor, const int id_product)
{
  // This device is unknown to the developers
  LIBMTP_ERROR("Device %d (VID=%04x and PID=%04x) is UNKNOWN in libmtp v%s.\n",
    dev_number,
    id_vendor,
    id_product,
    LIBMTP_VERSION_STRING);
  LIBMTP_ERROR("Please report this VID/PID and the device model to the "
               "libmtp development team\n");
  /*
   * Trying to get iManufacturer or iProduct from the device at this
   * point would require opening a device handle, that we don't want
   * to do right now. (Takes time for no good enough reason.)
   */
}
示例#3
0
/**
 * Write a .spl text file to a file in preparation for pushing it
 * to the device.
 *
 * @param fd file descriptor to write to
 * @param p the text to output one line per string in the linked list
 * @see playlist_t_to_spl()
 */
static void write_from_spl_text_t(LIBMTP_mtpdevice_t *device,
                                  const int fd,
                                  text_t* p) {
    ssize_t ret;
    // write out BOM for utf16/ucs2 (byte order mark)
    ret = write(fd,"\xff\xfe",2);
    while(p != NULL) {
        char *const t = (char*) utf8_to_utf16(device, p->text);
        // note: 2 bytes per ucs2 character
        const size_t len = ucs2_strlen((uint16_t*)t)*sizeof(uint16_t);
        int i;
        
        LIBMTP_PLST_DEBUG("\nutf8=%s ",p->text);
        for(i=0;i<strlen(p->text);i++)
            LIBMTP_PLST_DEBUG("%02x ", p->text[i] & 0xff);
        LIBMTP_PLST_DEBUG("\n");
        LIBMTP_PLST_DEBUG("ucs2=");
        for(i=0;i<ucs2_strlen((uint16_t*)t)*sizeof(uint16_t);i++)
            LIBMTP_PLST_DEBUG("%02x ", t[i] & 0xff);
        LIBMTP_PLST_DEBUG("\n");
        
        // write: utf8 -> utf16
        ret += write(fd, t, len);
        
        // release the converted string
        free(t);
        
        // check for failures
        if(ret < 0)
            LIBMTP_ERROR("write spl file failed: %s\n", strerror(errno));
        else if(ret != len +2)
            LIBMTP_ERROR("write spl file wrong number of bytes ret=%d len=%d '%s'\n", (int)ret, (int)len, p->text);
        
        // write carriage return, line feed in ucs2
        ret = write(fd, "\r\0\n\0", 4);
        if(ret < 0)
            LIBMTP_ERROR("write spl file failed: %s\n", strerror(errno));
        else if(ret != 4)
            LIBMTP_ERROR("failed to write the correct number of bytes '\\n'!\n");
        
        // fake out count (first time through has two extra bytes from BOM)
        ret = 2;
        
        // advance to the next line
        p = p->next;
    }
}
示例#4
0
/**
 * Find the track names (including path) for this playlist's track ids.
 * (ie: 12345 -> \Music\song.mp3)
 *
 * @param p the text to search
 * @param tracks list of track id's to look up
 * @param folders the folders list for the device
 * @param fiels the files list for the device
 * @see playlist_t_to_spl()
 */
static void spl_text_t_from_tracks(text_t** p,
                                   uint32_t* tracks,
                                   const uint32_t trackno,
                                   const uint32_t ver_major,
                                   const uint32_t ver_minor,
                                   char* dnse,
                                   LIBMTP_folder_t* folders,
                                   LIBMTP_file_t* files)
{
    
    // HEADER
    text_t* c = NULL;
    append_text_t(&c, "SPL PLAYLIST");
    *p = c; // save the top of the list!
    
    char vs[14]; // "VERSION 2.00\0"
    sprintf(vs,"VERSION %d.%02d",ver_major,ver_minor);
    
    append_text_t(&c, vs);
    append_text_t(&c, "");
    
    // TRACKS
    int i;
    char* f;
    for(i=0;i<trackno;i++) {
        discover_filepath_from_id(&f, tracks[i], folders, files);
        
        if(f != NULL) {
            append_text_t(&c, f);
            LIBMTP_PLST_DEBUG("track %d = %s (%u)\n", i+1, f, tracks[i]);
        }
        else
            LIBMTP_ERROR("failed to find filepath for track=%d\n", tracks[i]);
    }
    
    // FOOTER
    append_text_t(&c, "");
    append_text_t(&c, "END PLAYLIST");
    if(ver_major == 2) {
        append_text_t(&c, "");
        append_text_t(&c, "myDNSe DATA");
        if(dnse != NULL) {
            append_text_t(&c, dnse);
        }
        else {
            append_text_t(&c, "");
            append_text_t(&c, "");
        }
        append_text_t(&c, "END myDNSe");
    }
    
    c->next = NULL;
    
    // debug
    LIBMTP_PLST_DEBUG(".spl playlist:\n");
    print_spl_text_t(*p);
}
示例#5
0
/**
 * Load a file descriptor into a string.
 *
 * @param device a pointer to the current device.
 *               (needed for ucs2->utf8 charset conversion)
 * @param fd the file descriptor to load
 * @return text_t* a linked list of lines of text, id is left blank, NULL if nothing read in
 */
static text_t* read_into_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd)
{
    // set MAXREAD to match STRING_BUFFER_LENGTH in unicode.h conversion function
    const size_t MAXREAD = 1024*2;
    char t[MAXREAD];
    // upto 3 bytes per utf8 character, 2 bytes per ucs2 character,
    // +1 for '\0' at end of string
    const size_t WSIZE = MAXREAD/2*3+1;
    char w[WSIZE];
    char* it = t; // iterator on t
    char* iw = w;
    ssize_t rdcnt;
    off_t offcnt;
    text_t* head = NULL;
    text_t* tail = NULL;
    int eof = 0;
    
    // reset file descriptor (fd) to start of file
    offcnt = lseek(fd, 0, SEEK_SET);
    
    while(!eof) {
        // find the current offset in the file
        // to allow us to determine how many bytes we read if we hit the EOF
        // where returned rdcnt=0 from read()
        offcnt = lseek(fd, 0, SEEK_CUR);
        // read to refill buffer
        // (there might be data left from an incomplete last string in t,
        // hence start filling at it)
        it = t; // set ptr to start of buffer
        rdcnt = read(fd, it, sizeof(char)*MAXREAD);
        if(rdcnt < 0)
            LIBMTP_INFO("load_spl_fd read err %s\n", strerror(errno));
        else if(rdcnt == 0) { // for EOF, fix rdcnt
            if(it-t == MAXREAD)
                LIBMTP_ERROR("error -- buffer too small to read in .spl playlist entry\n");
            
            rdcnt = lseek(fd, 0, SEEK_CUR) - offcnt;
            eof = 1;
        }
        
        LIBMTP_PLST_DEBUG("read buff= {%dB new, %dB old/left-over}%s\n",(int)rdcnt, (int)(iw-w), eof?", EOF":"");
        
        // while more input bytes
        char* it_end = t + rdcnt;
        while(it < it_end) {
            // copy byte, unless EOL (then replace with end-of-string \0)
            if(*it == '\r' || *it == '\n')
                *iw = '\0';
            else
                *iw = *it;
            
            it++;
            iw++;
            
            // EOL -- store it
            if( (iw-w) >= 2 && // we must have at least two bytes
               *(iw-1) == '\0' && *(iw-2) == '\0' && // 0x0000 is end-of-string
               // but it must be aligned such that we have an {odd,even} set of
               // bytes since we are expecting to consume bytes two-at-a-time
               !((iw-w)%2) ) {
                
                // drop empty lines
                //  ... cast as a string of 2 byte characters
                if(ucs2_strlen((uint16_t*)w) == 0) {
                    iw = w;
                    continue;
                }
                
                // create a new node in the list
                if(head == NULL) {
                    head = malloc(sizeof(text_t));
                    tail = head;
                }
                else {
                    tail->next = malloc(sizeof(text_t));
                    tail = tail->next;
                }
                // fill in the data for the node
                //  ... cast as a string of 2 byte characters
                tail->text = utf16_to_utf8(device, (uint16_t*) w);
                iw = w; // start again
                
                LIBMTP_PLST_DEBUG("line: %s\n", tail->text);
            }
            
            // prevent buffer overflow
            if(iw >= w + WSIZE) {
                // if we ever see this error its BAD:
                //   we are dropping all the processed bytes for this line and
                //   proceeding on as if everything is okay, probably losing a track
                //   from the playlist
                LIBMTP_ERROR("ERROR %s:%u:%s(): buffer overflow! .spl line too long @ %zuB\n",
                             __FILE__, __LINE__, __func__, WSIZE);
                iw = w; // reset buffer
            }
        }
        
        // if the last thing we did was save our line, then we finished working
        // on the input buffer and we can start fresh
        // otherwise we need to save our partial work, if we're not quiting (eof).
        // there is nothing special we need to do, to achieve this since the
        // partially completed string will sit in 'w' until we return to complete
        // the line
        
    }
    
    // set the next pointer at the end
    // if there is any list
    if(head != NULL)
        tail->next = NULL;
    
    // return the head of the list (NULL if no list)
    return head;
}
示例#6
0
/**
 * Push a playlist_t onto the device after converting it to a .spl format
 *
 * @param device mtp device pointer
 * @param pl the LIBMTP_playlist_t to convert (pl->playlist_id will be updated
 *           with the newly created object's id)
 * @return 0 on success, any other value means failure.
 */
int playlist_t_to_spl(LIBMTP_mtpdevice_t *device,
                      LIBMTP_playlist_t * const pl)
{
    text_t* t;
    LIBMTP_folder_t *folders;
    LIBMTP_file_t *files;
    folders = LIBMTP_Get_Folder_List(device);
    files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL);
    
    char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX"; // must be a var since mkstemp modifies it
    
    LIBMTP_PLST_DEBUG("pl->name='%s'\n",pl->name);
    
    // open a file descriptor
    int fd = mkstemp(tmpname);
    if(fd < 0) {
        LIBMTP_ERROR("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno));
        return -1;
    }
    // make sure the file will be deleted afterwards
    if(unlink(tmpname) < 0)
        LIBMTP_ERROR("failed to delete temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno));
    
    // decide on which version of the .spl format to use
    uint32_t ver_major;
    uint32_t ver_minor = 0;
    PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
    if(FLAG_PLAYLIST_SPL_V2(ptp_usb)) ver_major = 2;
    else ver_major = 1; // FLAG_PLAYLIST_SPL_V1()
    
    LIBMTP_PLST_DEBUG("%u track%s\n", pl->no_tracks, pl->no_tracks==1?"":"s");
    LIBMTP_PLST_DEBUG(".spl version %d.%02d\n", ver_major, ver_minor);
    
    // create the text for the playlist
    spl_text_t_from_tracks(&t, pl->tracks, pl->no_tracks, ver_major, ver_minor, NULL, folders, files);
    write_from_spl_text_t(device, fd, t);
    free_spl_text_t(t); // done with the text
    
    // create the file object for storing
    LIBMTP_file_t* f = malloc(sizeof(LIBMTP_file_t));
    f->item_id = 0;
    f->parent_id = pl->parent_id;
    f->storage_id = pl->storage_id;
    f->filename = malloc(sizeof(char)*(strlen(pl->name)+5));
    strcpy(f->filename, pl->name);
    strcat(f->filename, ".spl"); // append suffix
    f->filesize = lseek(fd, 0, SEEK_CUR); // file desc is currently at end of file
    f->filetype = LIBMTP_FILETYPE_UNKNOWN;
    f->next = NULL;
    
    LIBMTP_PLST_DEBUG("%s is %dB\n", f->filename, (int)f->filesize);
    
    // push the playlist to the device
    lseek(fd, 0, SEEK_SET); // reset file desc. to start of file
    int ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, f, NULL, NULL);
    pl->playlist_id = f->item_id;
    free(f->filename);
    free(f);
    
    // release the memory when we're done with it
    close(fd);
    // debug: add a break since this is the top level function call
    LIBMTP_PLST_DEBUG("------------\n\n");
    
    return ret;
}