Import Upstream version 0.3.1
Dylan Aïssi
5 years ago
29 | 29 | Tero Saarni <tero.saarni@gmail.com> |
30 | 30 | Jeff Mitchell <kde-dev@emailgoeshere.com> |
31 | 31 | Johannes Huber <johub1180@gmx.at> |
32 | Alistair Boyle <alistair.js.boyle@gmail.com> |
0 | 2008-08-25 Linus Walleij <triad@df.lth.se> | |
1 | ||
2 | * src/Makefile.am: bump interface a patchlevel. (Fully | |
3 | compatible.) | |
4 | * configure.ac: bump version to 0.3.1. | |
5 | * Release as libmtp 0.3.1. | |
6 | ||
7 | 2008-08-18 Linus Walleij <triad@df.lth.se> | |
8 | ||
9 | * src/libusb-glue.c: some vartype and return flunkies. | |
10 | * configure.ac: check for locale.h | |
11 | * examples/util.c: set locale to pick up environment. | |
12 | ||
13 | 2008-08-17 Linus Walleij <triad@df.lth.se> | |
14 | ||
15 | * src/libusb-glue.c: some handling of ptp_usb_getdata() | |
16 | when passed in data size was 0xffffffffU, data | |
17 | sent in first transaction was ignored, fix by | |
18 | Rob Woolley. | |
19 | * src/ptp-pack.c: sync in from upstream libgphoto2. | |
20 | * src/README: move relevant stuff to README. | |
21 | * README: see above. | |
22 | ||
23 | 2008-08-15 Alistair Boyle <alistair.js.boyle@gmail.com> | |
24 | ||
25 | * src/playlist-spl.c: added handling of Samsung's | |
26 | proprietary .spl playlist format. | |
27 | * src/playlist-spl.h: dito. | |
28 | * src/device-flags.h: new flags for Samsung playlists. | |
29 | * src/music-players.h: assign flags. | |
30 | * src/libusb-glue.h: convenience macros. | |
31 | * src/libmtp.c: integrate Samsung playlists. | |
32 | ||
33 | 2008-08-15 Linus Walleij <triad@df.lth.se> | |
34 | ||
35 | * examples/Makefile.am: break out utility functions | |
36 | (currently only checklang()) to a separate file. | |
37 | * examples/util.h: dito. | |
38 | * examples/util.c: dito. | |
39 | * examples/detect.c: dito. | |
40 | * examples/sendtr.c: dito. | |
41 | * examples/connect.c: dito. | |
42 | ||
43 | 2008-08-14 Linus Walleij <triad@df.lth.se> | |
44 | ||
45 | * src/libmtp.c: add some documentation to file and track | |
46 | listing functions to that it's clear that you have to | |
47 | inspect storage_id and parent_id in order to group files | |
48 | into storages and/or folders. | |
49 | ||
50 | 2008-07-31 Linus Walleij <triad@df.lth.se> | |
51 | ||
52 | * src/music-players.h: several new devices and flags. | |
53 | ||
0 | 54 | 2008-06-24 Linus Walleij <triad@df.lth.se> |
1 | 55 | |
2 | 56 | * TODO: updates. |
68 | 68 | For information about the Media Transfer Protocol, see: |
69 | 69 | http://en.wikipedia.org/wiki/Media_Transfer_Protocol |
70 | 70 | |
71 | The official 1.0 specification for MTP was released by the | |
72 | USB Implementers Forum in may, 2008. Prior to this, only a | |
73 | proprietary Microsoft version was available, and quite a few | |
74 | devices out there still use some aspects of the Microsoft | |
75 | version, which deviates from the specified standard. You can | |
76 | find the official specification here: | |
77 | http://www.usb.org/developers/devclass_docs/MTP_1.0.zip | |
71 | 78 | |
72 | 79 | Contributing |
73 | 80 | ------------ |
381 | 388 | the quirks, see: |
382 | 389 | http://www2.one-eyed-alien.net/~mdharm/linux-usb/target_offenses.txt |
383 | 390 | |
391 | * Kernel bug on Linux. Linux 2.6.16 is generally speaking required | |
392 | to use any MTP device under USB 2.0. This is because the EHCI | |
393 | driver previously did not support zero-length writes to endpoints. | |
394 | It should work in most cases however, or if you connect it | |
395 | to an UHCI/OHCI port instead (yielding lower speed). But | |
396 | please just use a recent kernel. | |
397 | ||
398 | * Zen models AVI file seeking problem: the Zens cannot parse the | |
399 | files for the runlength metadata. Do not transfer file with e.g. | |
400 | mtp-sendfile, use mtp-sendtr and set the length of the track to | |
401 | the apropriate number of seconds and it will work. In graphical | |
402 | clients, use a "track transfer" function to send these AVI files, | |
403 | the Zens need the metadata associated with tracks to play back | |
404 | movies properly. Movies are considered "tracks" in the MTP world. | |
405 | ||
406 | * Some devices that disregard the metadata sent with the MTP | |
407 | commands will parse the files for e.g. ID3 metadata. Some still | |
408 | of these devices expect only ID3v2.3 metadata and will fail with | |
409 | a modern ID3v2,4 tag writer, like many of those found in Linux | |
410 | applications. Windows Media Player use ID3v2.3 only, so many | |
411 | manufacturers only test this version. | |
412 | ||
384 | 413 | * The Zen Vision:M (possibly more Creative Zens) has a firmware bug |
385 | 414 | that makes it drop the last two characters off a playlist name. |
386 | 415 | It is fixed in later firmware. |
451 | 480 | usb 4-5: configuration #1 chosen from 1 choice |
452 | 481 | usb 4-5: can't set config #1, error -110 |
453 | 482 | |
483 | * The Sirus Stiletto does not seem to allow you to copy any files | |
484 | off the device. This may be someone's idea of copy protection. | |
454 | 485 | |
455 | 486 | Lost symbols |
456 | 487 | ------------ |
34 | 34 | |
35 | 35 | /* Define to 1 if you have the <limits.h> header file. */ |
36 | 36 | #undef HAVE_LIMITS_H |
37 | ||
38 | /* Define to 1 if you have the <locale.h> header file. */ | |
39 | #undef HAVE_LOCALE_H | |
37 | 40 | |
38 | 41 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and |
39 | 42 | to 0 otherwise. */ |
0 | 0 | #! /bin/sh |
1 | 1 | # Guess values for system-dependent variables and create Makefiles. |
2 | # Generated by GNU Autoconf 2.61 for libmtp 0.3.0. | |
2 | # Generated by GNU Autoconf 2.61 for libmtp 0.3.1. | |
3 | 3 | # |
4 | 4 | # Report bugs to <libmtp-discuss@lists.sourceforge.net>. |
5 | 5 | # |
727 | 727 | # Identity of this package. |
728 | 728 | PACKAGE_NAME='libmtp' |
729 | 729 | PACKAGE_TARNAME='libmtp' |
730 | PACKAGE_VERSION='0.3.0' | |
731 | PACKAGE_STRING='libmtp 0.3.0' | |
730 | PACKAGE_VERSION='0.3.1' | |
731 | PACKAGE_STRING='libmtp 0.3.1' | |
732 | 732 | PACKAGE_BUGREPORT='libmtp-discuss@lists.sourceforge.net' |
733 | 733 | |
734 | 734 | ac_unique_file="src/libmtp.c" |
1400 | 1400 | # Omit some internal or obsolete options to make the list less imposing. |
1401 | 1401 | # This message is too long to be a string in the A/UX 3.1 sh. |
1402 | 1402 | cat <<_ACEOF |
1403 | \`configure' configures libmtp 0.3.0 to adapt to many kinds of systems. | |
1403 | \`configure' configures libmtp 0.3.1 to adapt to many kinds of systems. | |
1404 | 1404 | |
1405 | 1405 | Usage: $0 [OPTION]... [VAR=VALUE]... |
1406 | 1406 | |
1470 | 1470 | |
1471 | 1471 | if test -n "$ac_init_help"; then |
1472 | 1472 | case $ac_init_help in |
1473 | short | recursive ) echo "Configuration of libmtp 0.3.0:";; | |
1473 | short | recursive ) echo "Configuration of libmtp 0.3.1:";; | |
1474 | 1474 | esac |
1475 | 1475 | cat <<\_ACEOF |
1476 | 1476 | |
1572 | 1572 | test -n "$ac_init_help" && exit $ac_status |
1573 | 1573 | if $ac_init_version; then |
1574 | 1574 | cat <<\_ACEOF |
1575 | libmtp configure 0.3.0 | |
1575 | libmtp configure 0.3.1 | |
1576 | 1576 | generated by GNU Autoconf 2.61 |
1577 | 1577 | |
1578 | 1578 | Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, |
1586 | 1586 | This file contains any messages produced by compilers while |
1587 | 1587 | running configure, to aid debugging if configure makes a mistake. |
1588 | 1588 | |
1589 | It was created by libmtp $as_me 0.3.0, which was | |
1589 | It was created by libmtp $as_me 0.3.1, which was | |
1590 | 1590 | generated by GNU Autoconf 2.61. Invocation command line was |
1591 | 1591 | |
1592 | 1592 | $ $0 $@ |
2276 | 2276 | |
2277 | 2277 | # Define the identity of the package. |
2278 | 2278 | PACKAGE='libmtp' |
2279 | VERSION='0.3.0' | |
2279 | VERSION='0.3.1' | |
2280 | 2280 | |
2281 | 2281 | |
2282 | 2282 | cat >>confdefs.h <<_ACEOF |
20141 | 20141 | |
20142 | 20142 | |
20143 | 20143 | |
20144 | ||
20144 | 20145 | for ac_header in ctype.h errno.h fcntl.h getopt.h libgen.h \ |
20145 | 20146 | limits.h stdio.h string.h sys/stat.h sys/time.h unistd.h \ |
20146 | iconv.h langinfo.h | |
20147 | iconv.h langinfo.h locale.h | |
20147 | 20148 | do |
20148 | 20149 | as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` |
20149 | 20150 | if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then |
22857 | 22858 | # report actual input values of CONFIG_FILES etc. instead of their |
22858 | 22859 | # values after options handling. |
22859 | 22860 | ac_log=" |
22860 | This file was extended by libmtp $as_me 0.3.0, which was | |
22861 | This file was extended by libmtp $as_me 0.3.1, which was | |
22861 | 22862 | generated by GNU Autoconf 2.61. Invocation command line was |
22862 | 22863 | |
22863 | 22864 | CONFIG_FILES = $CONFIG_FILES |
22910 | 22911 | _ACEOF |
22911 | 22912 | cat >>$CONFIG_STATUS <<_ACEOF |
22912 | 22913 | ac_cs_version="\\ |
22913 | libmtp config.status 0.3.0 | |
22914 | libmtp config.status 0.3.1 | |
22914 | 22915 | configured by $0, generated by GNU Autoconf 2.61, |
22915 | 22916 | with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" |
22916 | 22917 |
0 | 0 | # Process this file with autoconf to produce a configure script. |
1 | 1 | AC_PREREQ(2.52) |
2 | AC_INIT([libmtp], [0.3.0], [libmtp-discuss@lists.sourceforge.net]) | |
2 | AC_INIT([libmtp], [0.3.1], [libmtp-discuss@lists.sourceforge.net]) | |
3 | 3 | AM_INIT_AUTOMAKE([foreign]) |
4 | 4 | AC_CONFIG_SRCDIR([src/libmtp.c]) |
5 | 5 | AM_CONFIG_HEADER(config.h) |
60 | 60 | # zlib.h the day we need to decompress firmware |
61 | 61 | AC_CHECK_HEADERS([ctype.h errno.h fcntl.h getopt.h libgen.h \ |
62 | 62 | limits.h stdio.h string.h sys/stat.h sys/time.h unistd.h \ |
63 | iconv.h langinfo.h]) | |
63 | iconv.h langinfo.h locale.h]) | |
64 | 64 | AC_CHECK_HEADER([usb.h],, |
65 | 65 | AC_MSG_ERROR([I can't find the libusb header file on your system. |
66 | 66 | You may need to set the CPPFLAGS environment variable to include |
3 | 3 | thumb reset |
4 | 4 | |
5 | 5 | connect_SOURCES=connect.c delfile.c getfile.c newfolder.c \ |
6 | sendfile.c sendtr.c pathutils.c pathutils.h common.h | |
7 | detect_SOURCES=detect.c common.h | |
8 | tracks_SOURCES=tracks.c common.h | |
9 | files_SOURCES=files.c common.h | |
10 | hotplug_SOURCES=hotplug.c common.h | |
11 | folders_SOURCES=folders.c common.h | |
12 | trexist_SOURCES=trexist.c common.h | |
13 | playlists_SOURCES=playlists.c common.h | |
14 | getplaylist_SOURCES=getplaylist.c common.h | |
15 | newplaylist_SOURCES=newplaylist.c common.h | |
16 | format_SOURCES=format.c common.h | |
17 | albumart_SOURCES=albumart.c common.h | |
18 | albums_SOURCES=albums.c common.h | |
19 | emptyfolders_SOURCES=emptyfolders.c common.h | |
20 | thumb_SOURCES=thumb.c common.h | |
21 | reset_SOURCES=reset.c common.h | |
6 | sendfile.c sendtr.c pathutils.c pathutils.h \ | |
7 | util.c util.h common.h | |
8 | detect_SOURCES=detect.c util.c util.h common.h | |
9 | tracks_SOURCES=tracks.c util.c util.h common.h | |
10 | files_SOURCES=files.c util.c util.h common.h | |
11 | hotplug_SOURCES=hotplug.c util.c util.h common.h | |
12 | folders_SOURCES=folders.c util.c util.h common.h | |
13 | trexist_SOURCES=trexist.c util.c util.h common.h | |
14 | playlists_SOURCES=playlists.c util.c util.h common.h | |
15 | getplaylist_SOURCES=getplaylist.c util.c util.h common.h | |
16 | newplaylist_SOURCES=newplaylist.c util.c util.h common.h | |
17 | format_SOURCES=format.c util.c util.h common.h | |
18 | albumart_SOURCES=albumart.c util.c util.h common.h | |
19 | albums_SOURCES=albums.c util.c util.h common.h | |
20 | emptyfolders_SOURCES=emptyfolders.c util.c util.h common.h | |
21 | thumb_SOURCES=thumb.c util.c util.h common.h | |
22 | reset_SOURCES=reset.c util.c util.h common.h | |
22 | 23 | |
23 | 24 | AM_CPPFLAGS=-I$(top_builddir)/src |
24 | 25 | LDADD=../src/libmtp.la |
50 | 50 | am__installdirs = "$(DESTDIR)$(bindir)" |
51 | 51 | binPROGRAMS_INSTALL = $(INSTALL_PROGRAM) |
52 | 52 | PROGRAMS = $(bin_PROGRAMS) |
53 | am_albumart_OBJECTS = albumart.$(OBJEXT) | |
53 | am_albumart_OBJECTS = albumart.$(OBJEXT) util.$(OBJEXT) | |
54 | 54 | albumart_OBJECTS = $(am_albumart_OBJECTS) |
55 | 55 | albumart_LDADD = $(LDADD) |
56 | 56 | albumart_DEPENDENCIES = ../src/libmtp.la |
57 | am_albums_OBJECTS = albums.$(OBJEXT) | |
57 | am_albums_OBJECTS = albums.$(OBJEXT) util.$(OBJEXT) | |
58 | 58 | albums_OBJECTS = $(am_albums_OBJECTS) |
59 | 59 | albums_LDADD = $(LDADD) |
60 | 60 | albums_DEPENDENCIES = ../src/libmtp.la |
61 | 61 | am_connect_OBJECTS = connect.$(OBJEXT) delfile.$(OBJEXT) \ |
62 | 62 | getfile.$(OBJEXT) newfolder.$(OBJEXT) sendfile.$(OBJEXT) \ |
63 | sendtr.$(OBJEXT) pathutils.$(OBJEXT) | |
63 | sendtr.$(OBJEXT) pathutils.$(OBJEXT) util.$(OBJEXT) | |
64 | 64 | connect_OBJECTS = $(am_connect_OBJECTS) |
65 | 65 | connect_LDADD = $(LDADD) |
66 | 66 | connect_DEPENDENCIES = ../src/libmtp.la |
67 | am_detect_OBJECTS = detect.$(OBJEXT) | |
67 | am_detect_OBJECTS = detect.$(OBJEXT) util.$(OBJEXT) | |
68 | 68 | detect_OBJECTS = $(am_detect_OBJECTS) |
69 | 69 | detect_LDADD = $(LDADD) |
70 | 70 | detect_DEPENDENCIES = ../src/libmtp.la |
71 | am_emptyfolders_OBJECTS = emptyfolders.$(OBJEXT) | |
71 | am_emptyfolders_OBJECTS = emptyfolders.$(OBJEXT) util.$(OBJEXT) | |
72 | 72 | emptyfolders_OBJECTS = $(am_emptyfolders_OBJECTS) |
73 | 73 | emptyfolders_LDADD = $(LDADD) |
74 | 74 | emptyfolders_DEPENDENCIES = ../src/libmtp.la |
75 | am_files_OBJECTS = files.$(OBJEXT) | |
75 | am_files_OBJECTS = files.$(OBJEXT) util.$(OBJEXT) | |
76 | 76 | files_OBJECTS = $(am_files_OBJECTS) |
77 | 77 | files_LDADD = $(LDADD) |
78 | 78 | files_DEPENDENCIES = ../src/libmtp.la |
79 | am_folders_OBJECTS = folders.$(OBJEXT) | |
79 | am_folders_OBJECTS = folders.$(OBJEXT) util.$(OBJEXT) | |
80 | 80 | folders_OBJECTS = $(am_folders_OBJECTS) |
81 | 81 | folders_LDADD = $(LDADD) |
82 | 82 | folders_DEPENDENCIES = ../src/libmtp.la |
83 | am_format_OBJECTS = format.$(OBJEXT) | |
83 | am_format_OBJECTS = format.$(OBJEXT) util.$(OBJEXT) | |
84 | 84 | format_OBJECTS = $(am_format_OBJECTS) |
85 | 85 | format_LDADD = $(LDADD) |
86 | 86 | format_DEPENDENCIES = ../src/libmtp.la |
87 | am_getplaylist_OBJECTS = getplaylist.$(OBJEXT) | |
87 | am_getplaylist_OBJECTS = getplaylist.$(OBJEXT) util.$(OBJEXT) | |
88 | 88 | getplaylist_OBJECTS = $(am_getplaylist_OBJECTS) |
89 | 89 | getplaylist_LDADD = $(LDADD) |
90 | 90 | getplaylist_DEPENDENCIES = ../src/libmtp.la |
91 | am_hotplug_OBJECTS = hotplug.$(OBJEXT) | |
91 | am_hotplug_OBJECTS = hotplug.$(OBJEXT) util.$(OBJEXT) | |
92 | 92 | hotplug_OBJECTS = $(am_hotplug_OBJECTS) |
93 | 93 | hotplug_LDADD = $(LDADD) |
94 | 94 | hotplug_DEPENDENCIES = ../src/libmtp.la |
95 | am_newplaylist_OBJECTS = newplaylist.$(OBJEXT) | |
95 | am_newplaylist_OBJECTS = newplaylist.$(OBJEXT) util.$(OBJEXT) | |
96 | 96 | newplaylist_OBJECTS = $(am_newplaylist_OBJECTS) |
97 | 97 | newplaylist_LDADD = $(LDADD) |
98 | 98 | newplaylist_DEPENDENCIES = ../src/libmtp.la |
99 | am_playlists_OBJECTS = playlists.$(OBJEXT) | |
99 | am_playlists_OBJECTS = playlists.$(OBJEXT) util.$(OBJEXT) | |
100 | 100 | playlists_OBJECTS = $(am_playlists_OBJECTS) |
101 | 101 | playlists_LDADD = $(LDADD) |
102 | 102 | playlists_DEPENDENCIES = ../src/libmtp.la |
103 | am_reset_OBJECTS = reset.$(OBJEXT) | |
103 | am_reset_OBJECTS = reset.$(OBJEXT) util.$(OBJEXT) | |
104 | 104 | reset_OBJECTS = $(am_reset_OBJECTS) |
105 | 105 | reset_LDADD = $(LDADD) |
106 | 106 | reset_DEPENDENCIES = ../src/libmtp.la |
107 | am_thumb_OBJECTS = thumb.$(OBJEXT) | |
107 | am_thumb_OBJECTS = thumb.$(OBJEXT) util.$(OBJEXT) | |
108 | 108 | thumb_OBJECTS = $(am_thumb_OBJECTS) |
109 | 109 | thumb_LDADD = $(LDADD) |
110 | 110 | thumb_DEPENDENCIES = ../src/libmtp.la |
111 | am_tracks_OBJECTS = tracks.$(OBJEXT) | |
111 | am_tracks_OBJECTS = tracks.$(OBJEXT) util.$(OBJEXT) | |
112 | 112 | tracks_OBJECTS = $(am_tracks_OBJECTS) |
113 | 113 | tracks_LDADD = $(LDADD) |
114 | 114 | tracks_DEPENDENCIES = ../src/libmtp.la |
115 | am_trexist_OBJECTS = trexist.$(OBJEXT) | |
115 | am_trexist_OBJECTS = trexist.$(OBJEXT) util.$(OBJEXT) | |
116 | 116 | trexist_OBJECTS = $(am_trexist_OBJECTS) |
117 | 117 | trexist_LDADD = $(LDADD) |
118 | 118 | trexist_DEPENDENCIES = ../src/libmtp.la |
256 | 256 | top_builddir = @top_builddir@ |
257 | 257 | top_srcdir = @top_srcdir@ |
258 | 258 | connect_SOURCES = connect.c delfile.c getfile.c newfolder.c \ |
259 | sendfile.c sendtr.c pathutils.c pathutils.h common.h | |
260 | ||
261 | detect_SOURCES = detect.c common.h | |
262 | tracks_SOURCES = tracks.c common.h | |
263 | files_SOURCES = files.c common.h | |
264 | hotplug_SOURCES = hotplug.c common.h | |
265 | folders_SOURCES = folders.c common.h | |
266 | trexist_SOURCES = trexist.c common.h | |
267 | playlists_SOURCES = playlists.c common.h | |
268 | getplaylist_SOURCES = getplaylist.c common.h | |
269 | newplaylist_SOURCES = newplaylist.c common.h | |
270 | format_SOURCES = format.c common.h | |
271 | albumart_SOURCES = albumart.c common.h | |
272 | albums_SOURCES = albums.c common.h | |
273 | emptyfolders_SOURCES = emptyfolders.c common.h | |
274 | thumb_SOURCES = thumb.c common.h | |
275 | reset_SOURCES = reset.c common.h | |
259 | sendfile.c sendtr.c pathutils.c pathutils.h \ | |
260 | util.c util.h common.h | |
261 | ||
262 | detect_SOURCES = detect.c util.c util.h common.h | |
263 | tracks_SOURCES = tracks.c util.c util.h common.h | |
264 | files_SOURCES = files.c util.c util.h common.h | |
265 | hotplug_SOURCES = hotplug.c util.c util.h common.h | |
266 | folders_SOURCES = folders.c util.c util.h common.h | |
267 | trexist_SOURCES = trexist.c util.c util.h common.h | |
268 | playlists_SOURCES = playlists.c util.c util.h common.h | |
269 | getplaylist_SOURCES = getplaylist.c util.c util.h common.h | |
270 | newplaylist_SOURCES = newplaylist.c util.c util.h common.h | |
271 | format_SOURCES = format.c util.c util.h common.h | |
272 | albumart_SOURCES = albumart.c util.c util.h common.h | |
273 | albums_SOURCES = albums.c util.c util.h common.h | |
274 | emptyfolders_SOURCES = emptyfolders.c util.c util.h common.h | |
275 | thumb_SOURCES = thumb.c util.c util.h common.h | |
276 | reset_SOURCES = reset.c util.c util.h common.h | |
276 | 277 | AM_CPPFLAGS = -I$(top_builddir)/src |
277 | 278 | LDADD = ../src/libmtp.la |
278 | 279 | EXTRA_DIST = evolution-sync.sh |
414 | 415 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thumb.Po@am__quote@ |
415 | 416 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tracks.Po@am__quote@ |
416 | 417 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trexist.Po@am__quote@ |
418 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@ | |
417 | 419 | |
418 | 420 | .c.o: |
419 | 421 | @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< |
21 | 21 | */ |
22 | 22 | #include <libgen.h> |
23 | 23 | #include <getopt.h> |
24 | #include <string.h> | |
24 | 25 | #include "common.h" |
25 | #include "string.h" | |
26 | #include "util.h" | |
26 | 27 | #include "pathutils.h" |
27 | #ifdef HAVE_LANGINFO_H | |
28 | #include <langinfo.h> | |
29 | #endif | |
30 | 28 | |
31 | 29 | LIBMTP_folder_t *folders; |
32 | 30 | LIBMTP_file_t *files; |
74 | 72 | printf(" --newfolder [foldername]\n"); |
75 | 73 | } |
76 | 74 | |
77 | static void checklang(void) | |
78 | { | |
79 | char *langsuff = NULL; | |
80 | char *lang = getenv("LANG"); | |
81 | ||
82 | #ifdef HAVE_LANGINFO_H | |
83 | langsuff = nl_langinfo(CODESET); | |
84 | #else | |
85 | /* | |
86 | * Check environment variables $LANG and $LC_CTYPE | |
87 | * to see if we want to support UTF-8 unicode | |
88 | */ | |
89 | if (lang != NULL) { | |
90 | if (strlen(lang) > 5) { | |
91 | langsuff = &lang[strlen(lang)-5]; | |
92 | } | |
93 | } | |
94 | #endif | |
95 | if (strcmp(langsuff, "UTF-8")) { | |
96 | printf("Your system does not appear to have UTF-8 enabled ($LANG=\"%s\")\n", lang); | |
97 | printf("If you want to have support for diacritics and Unicode characters,\n"); | |
98 | printf("please switch your locale to an UTF-8 locale, e.g. \"en_US.UTF-8\".\n"); | |
99 | } | |
100 | } | |
101 | 75 | |
102 | 76 | int main (int argc, char **argv) |
103 | 77 | { |
20 | 20 | * Boston, MA 02111-1307, USA. |
21 | 21 | */ |
22 | 22 | #include "common.h" |
23 | #include "util.h" | |
23 | 24 | #include <unistd.h> |
24 | 25 | #include <stdlib.h> |
25 | 26 | #include <stdio.h> |
29 | 29 | #define _LARGEFILE64_SOURCE |
30 | 30 | |
31 | 31 | #include "common.h" |
32 | #include "util.h" | |
32 | 33 | #include <string.h> |
33 | 34 | #include <libgen.h> |
34 | 35 | #include <sys/stat.h> |
55 | 56 | fprintf(stderr, " -l <album> -c <codec> -g <genre> -n <track number> -y <year>\n"); |
56 | 57 | fprintf(stderr, " -d <duration in seconds> <local path> <remote path>\n"); |
57 | 58 | fprintf(stderr, "(-q means the program will not ask for missing information.)\n"); |
58 | } | |
59 | ||
60 | static void checklang(void) | |
61 | { | |
62 | char *langsuff = NULL; | |
63 | char *lang = getenv("LANG"); | |
64 | ||
65 | #ifdef HAVE_LANGINFO_H | |
66 | langsuff = nl_langinfo(CODESET); | |
67 | #else | |
68 | /* | |
69 | * Check environment variables $LANG and $LC_CTYPE | |
70 | * to see if we want to support UTF-8 unicode | |
71 | */ | |
72 | if (lang != NULL) { | |
73 | if (strlen(lang) > 5) { | |
74 | langsuff = &lang[strlen(lang)-5]; | |
75 | } | |
76 | } | |
77 | #endif | |
78 | if (strcmp(langsuff, "UTF-8")) { | |
79 | printf("Your system does not appear to have UTF-8 enabled ($LANG=\"%s\")\n", lang); | |
80 | printf("If you want to have support for diacritics and Unicode characters,\n"); | |
81 | printf("please switch your locale to an UTF-8 locale, e.g. \"en_US.UTF-8\".\n"); | |
82 | } | |
83 | 59 | } |
84 | 60 | |
85 | 61 | static char *prompt (const char *prompt, char *buffer, size_t bufsz, int required) |
0 | /** | |
1 | * \file util.c | |
2 | * A set of common utility functions found | |
3 | * in all samples. | |
4 | * | |
5 | * Copyright (C) 2008 Linus Walleij <triad@df.lth.se> | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the | |
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | * Boston, MA 02111-1307, USA. | |
21 | */ | |
22 | #include "util.h" | |
23 | #ifdef HAVE_LANGINFO_H | |
24 | #include <langinfo.h> | |
25 | #endif | |
26 | #ifdef HAVE_LOCALE_H | |
27 | #include <locale.h> | |
28 | #endif | |
29 | #include <stdlib.h> | |
30 | #include <stdio.h> | |
31 | #include <string.h> | |
32 | ||
33 | void checklang(void) | |
34 | { | |
35 | char *langsuff = NULL; | |
36 | char *lang = getenv("LANG"); | |
37 | ||
38 | #ifdef HAVE_LOCALE_H | |
39 | // Set the locale in accordance with environment | |
40 | setlocale(LC_ALL, ""); | |
41 | #endif | |
42 | #ifdef HAVE_LANGINFO_H | |
43 | langsuff = nl_langinfo(CODESET); | |
44 | #else | |
45 | /* | |
46 | * Check environment variables $LANG and $LC_CTYPE | |
47 | * to see if we want to support UTF-8 unicode | |
48 | */ | |
49 | if (lang != NULL) { | |
50 | if (strlen(lang) > 5) { | |
51 | langsuff = &lang[strlen(lang)-5]; | |
52 | } | |
53 | } | |
54 | #endif | |
55 | if (strcmp(langsuff, "UTF-8")) { | |
56 | printf("Your system does not appear to have UTF-8 enabled ($LANG=\"%s\")\n", lang); | |
57 | printf("If you want to have support for diacritics and Unicode characters,\n"); | |
58 | printf("please switch your locale to an UTF-8 locale, e.g. \"en_US.UTF-8\".\n"); | |
59 | } | |
60 | } |
0 | /** | |
1 | * \file util.h | |
2 | * Header for a set of common utility functions found | |
3 | * in all samples. | |
4 | * | |
5 | * Copyright (C) 2008 Linus Walleij <triad@df.lth.se> | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the | |
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | * Boston, MA 02111-1307, USA. | |
21 | */ | |
22 | #ifndef LIBMTP_EXAMPLES_UTIL_H | |
23 | #define LIBMTP_EXAMPLES_UTIL_H | |
24 | void checklang(void); | |
25 | #endif |
6 | 6 | |
7 | 7 | Name: libmtp |
8 | 8 | Description: libmtp is a library for accessing Media Transfer Protocol devices |
9 | Version: 0.3.0 | |
9 | Version: 0.3.1 | |
10 | 10 | Requires: libusb |
11 | 11 | Conflicts: |
12 | 12 | Libs: -L${libdir} -lmtp |
0 | 0 | lib_LTLIBRARIES=libmtp.la |
1 | libmtp_la_SOURCES=libmtp.c unicode.c unicode.h util.c util.h \ | |
1 | libmtp_la_SOURCES=libmtp.c unicode.c unicode.h util.c util.h playlist-spl.c \ | |
2 | 2 | libusb-glue.c libusb-glue.h \ |
3 | 3 | gphoto2-endian.h libptp-stdint.h ptp.c ptp.h \ |
4 | music-players.h device-flags.h | |
4 | music-players.h device-flags.h playlist-spl.h | |
5 | 5 | include_HEADERS=libmtp.h |
6 | 6 | EXTRA_DIST=libmtp.h.in libmtp.sym ptp-pack.c |
7 | 7 | |
29 | 29 | # --------------------------------------------------------------------------- |
30 | 30 | CURRENT=8 |
31 | 31 | AGE=0 |
32 | REVISION=0 | |
32 | REVISION=1 | |
33 | 33 | SOVERSION=$(CURRENT):$(REVISION):$(AGE) |
34 | 34 | |
35 | 35 | if COMPILE_MINGW32 |
54 | 54 | libLTLIBRARIES_INSTALL = $(INSTALL) |
55 | 55 | LTLIBRARIES = $(lib_LTLIBRARIES) |
56 | 56 | libmtp_la_LIBADD = |
57 | am_libmtp_la_OBJECTS = libmtp.lo unicode.lo util.lo libusb-glue.lo \ | |
58 | ptp.lo | |
57 | am_libmtp_la_OBJECTS = libmtp.lo unicode.lo util.lo playlist-spl.lo \ | |
58 | libusb-glue.lo ptp.lo | |
59 | 59 | libmtp_la_OBJECTS = $(am_libmtp_la_OBJECTS) |
60 | 60 | libmtp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \ |
61 | 61 | $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ |
193 | 193 | top_builddir = @top_builddir@ |
194 | 194 | top_srcdir = @top_srcdir@ |
195 | 195 | lib_LTLIBRARIES = libmtp.la |
196 | libmtp_la_SOURCES = libmtp.c unicode.c unicode.h util.c util.h \ | |
196 | libmtp_la_SOURCES = libmtp.c unicode.c unicode.h util.c util.h playlist-spl.c \ | |
197 | 197 | libusb-glue.c libusb-glue.h \ |
198 | 198 | gphoto2-endian.h libptp-stdint.h ptp.c ptp.h \ |
199 | music-players.h device-flags.h | |
199 | music-players.h device-flags.h playlist-spl.h | |
200 | 200 | |
201 | 201 | include_HEADERS = libmtp.h |
202 | 202 | EXTRA_DIST = libmtp.h.in libmtp.sym ptp-pack.c |
225 | 225 | # --------------------------------------------------------------------------- |
226 | 226 | CURRENT = 8 |
227 | 227 | AGE = 0 |
228 | REVISION = 0 | |
228 | REVISION = 1 | |
229 | 229 | SOVERSION = $(CURRENT):$(REVISION):$(AGE) |
230 | 230 | @COMPILE_MINGW32_TRUE@noinst_DATA = libmtp.lib |
231 | 231 | @COMPILE_MINGW32_TRUE@W32LF = -export-dynamic -no-undefined -export-symbols libmtp.sym |
303 | 303 | |
304 | 304 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtp.Plo@am__quote@ |
305 | 305 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libusb-glue.Plo@am__quote@ |
306 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playlist-spl.Plo@am__quote@ | |
306 | 307 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptp.Plo@am__quote@ |
307 | 308 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unicode.Plo@am__quote@ |
308 | 309 | @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Plo@am__quote@ |
0 | Lots of docs to follow... | |
1 | ||
2 | KERNEL BUG ON LINUX | |
3 | ------------------- | |
4 | ||
5 | Linux 2.6.16 is generally speaking required to use any MTP | |
6 | device under USB 2.0. This is because the EHCI driver | |
7 | previously did not support zero-length writes to endpoints. | |
8 | ||
9 | It should work in most cases however, or if you connect it | |
10 | to an UHCI/OHCI port instead (yielding lower speed). But | |
11 | please just use a recent kernel. | |
12 | ||
13 | ||
14 | ||
15 | 0 | RELATION TO LIBPTP2 |
16 | 1 | ------------------- |
17 | 2 |
40 | 40 | * DEVICE_FLAG_BROKEN_MTPGETOBJECTPROPLIST which only signify |
41 | 41 | * that it's broken when getting metadata for a SINGLE object. |
42 | 42 | * A typical way the implementation may be broken is that it |
43 | * may not return a proper count of the objects. | |
43 | * may not return a proper count of the objects, and sometimes | |
44 | * (like on the ZENs) objects are simply missing from the list | |
45 | * if you use this. Sometimes it has been used incorrectly to | |
46 | * mask bugs in the code (like handling transactions of data | |
47 | * with size given to -1 (0xFFFFFFFFU), in that case please | |
48 | * help us remove it now the code is fixed. Sometimes this is | |
49 | * used because getting all the objects is just too slow and | |
50 | * the USB transaction will time out if you use this command. | |
44 | 51 | */ |
45 | 52 | #define DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL 0x00000001 |
46 | 53 | /** |
88 | 95 | * The error has only been seen on iriver devices. Turning this |
89 | 96 | * flag on won't hurt anything, just that the check against |
90 | 97 | * filename extension will be done for files of "unknown" type. |
98 | * If the player does not even know (reports) that it supports | |
99 | * ogg even though it does, please use the stronger | |
100 | * OGG_IS_UNKNOWN flag, which will forcedly support ogg on | |
101 | * anything with the .ogg filename extension. | |
91 | 102 | */ |
92 | 103 | #define DEVICE_FLAG_IRIVER_OGG_ALZHEIMER 0x00000010 |
93 | 104 | /** |
135 | 146 | * and a need to report the Ogg support (the device itself does |
136 | 147 | * not properly claim to support it) and need to set filetype |
137 | 148 | * to unknown when storing Ogg files, even though they're not |
138 | * actually unknown. | |
149 | * actually unknown. Later iRivers seem to need this flag since | |
150 | * they do not report to support OGG even though they actually | |
151 | * do. | |
139 | 152 | */ |
140 | 153 | #define DEVICE_FLAG_OGG_IS_UNKNOWN 0x00000200 |
141 | 154 | /** |
152 | 165 | * This flag provides that extra massage. |
153 | 166 | */ |
154 | 167 | #define DEVICE_FLAG_ALWAYS_PROBE_DESCRIPTOR 0x00000800 |
168 | /** | |
169 | * Samsung has implimented its own playlist format as a .spl file | |
170 | * stored in the normal file system, rather than a proper mtp | |
171 | * playlist. There are multiple versions of the .spl format | |
172 | * identified by a line in the file: VERSION X.XX | |
173 | * Version 1.00 is just a simple playlist. | |
174 | */ | |
175 | #define DEVICE_FLAG_PLAYLIST_SPL_V1 0x00001000 | |
176 | /** | |
177 | * Samsung has implimented its own playlist format as a .spl file | |
178 | * stored in the normal file system, rather than a proper mtp | |
179 | * playlist. There are multiple versions of the .spl format | |
180 | * identified by a line in the file: VERSION X.XX | |
181 | * Version 2.00 is playlist but allows DNSe sound settings | |
182 | * to be stored, per playlist. | |
183 | */ | |
184 | #define DEVICE_FLAG_PLAYLIST_SPL_V2 0x00002000 |
41 | 41 | #include "ptp.h" |
42 | 42 | #include "libusb-glue.h" |
43 | 43 | #include "device-flags.h" |
44 | #include "playlist-spl.h" | |
44 | 45 | |
45 | 46 | #include <string.h> |
46 | 47 | #include <sys/types.h> |
47 | 48 | #include <sys/stat.h> |
48 | 49 | #include <fcntl.h> |
49 | 50 | #include <time.h> |
51 | #include <errno.h> | |
50 | 52 | #ifdef _MSC_VER // For MSVC++ |
51 | 53 | #define USE_WINDOWS_IO_H |
52 | 54 | #include <io.h> |
2550 | 2552 | * do not put a reference to any <code>char *</code> field. instead |
2551 | 2553 | * <code>strncpy()</code> it! |
2552 | 2554 | * |
2553 | * @param device a pointer to the device to get the filetype capabilities for. | |
2555 | * @param device a pointer to the device to get the storage for. | |
2554 | 2556 | * @param sortby an integer that determines the sorting of the storage list. |
2555 | 2557 | * Valid sort methods are defined in libmtp.h with beginning with |
2556 | 2558 | * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not |
2708 | 2710 | |
2709 | 2711 | /** |
2710 | 2712 | * This returns a long list of all files available |
2711 | * on the current MTP device. Folders will not be returned. Typical usage: | |
2713 | * on the current MTP device. Folders will not be returned, but abstract | |
2714 | * entities like playlists and albums will show up as "files". Typical usage: | |
2712 | 2715 | * |
2713 | 2716 | * <pre> |
2714 | 2717 | * LIBMTP_file_t *filelist; |
2724 | 2727 | * } |
2725 | 2728 | * </pre> |
2726 | 2729 | * |
2730 | * If you want to group your file listing by storage (per storage unit) or | |
2731 | * arrange files into folders, you must dereference the <code>storage_id</code> | |
2732 | * and/or <code>parent_id</code> field of the returned <code>LIBMTP_file_t</code> | |
2733 | * struct. To arrange by folders or files you typically have to create the proper | |
2734 | * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or | |
2735 | * <code>LIBMTP_Get_Folder_List()</code> first. | |
2736 | * | |
2727 | 2737 | * @param device a pointer to the device to get the file listing for. |
2728 | 2738 | * @param callback a function to be called during the tracklisting retrieveal |
2729 | * for displaying progress bars etc, or NULL if you don't want | |
2730 | * any callbacks. | |
2739 | * for displaying progress bars etc, or NULL if you don't want | |
2740 | * any callbacks. | |
2731 | 2741 | * @param data a user-defined pointer that is passed along to |
2732 | * the <code>progress</code> function in order to | |
2733 | * pass along some user defined data to the progress | |
2734 | * updates. If not used, set this to NULL. | |
2742 | * the <code>progress</code> function in order to | |
2743 | * pass along some user defined data to the progress | |
2744 | * updates. If not used, set this to NULL. | |
2735 | 2745 | * @return a list of files that can be followed using the <code>next</code> |
2736 | * field of the <code>LIBMTP_file_t</code> data structure. | |
2737 | * Each of the metadata tags must be freed after use, and may | |
2738 | * contain only partial metadata information, i.e. one or several | |
2739 | * fields may be NULL or 0. | |
2746 | * field of the <code>LIBMTP_file_t</code> data structure. | |
2747 | * Each of the metadata tags must be freed after use, and may | |
2748 | * contain only partial metadata information, i.e. one or several | |
2749 | * fields may be NULL or 0. | |
2740 | 2750 | * @see LIBMTP_Get_Filemetadata() |
2741 | 2751 | */ |
2742 | 2752 | LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device, |
3357 | 3367 | } |
3358 | 3368 | |
3359 | 3369 | /** |
3360 | * This returns a long list of all tracks available | |
3361 | * on the current MTP device. Typical usage: | |
3370 | * This returns a long list of all tracks available on the current MTP device. | |
3371 | * Tracks include multimedia objects, both music tracks and video tracks. | |
3372 | * Typical usage: | |
3362 | 3373 | * |
3363 | 3374 | * <pre> |
3364 | 3375 | * LIBMTP_track_t *tracklist; |
3374 | 3385 | * } |
3375 | 3386 | * </pre> |
3376 | 3387 | * |
3388 | * If you want to group your track listing by storage (per storage unit) or | |
3389 | * arrange tracks into folders, you must dereference the <code>storage_id</code> | |
3390 | * and/or <code>parent_id</code> field of the returned <code>LIBMTP_track_t</code> | |
3391 | * struct. To arrange by folders or files you typically have to create the proper | |
3392 | * trees by calls to <code>LIBMTP_Get_Storage()</code> and/or | |
3393 | * <code>LIBMTP_Get_Folder_List()</code> first. | |
3394 | * | |
3377 | 3395 | * @param device a pointer to the device to get the track listing for. |
3378 | 3396 | * @param callback a function to be called during the tracklisting retrieveal |
3379 | * for displaying progress bars etc, or NULL if you don't want | |
3380 | * any callbacks. | |
3397 | * for displaying progress bars etc, or NULL if you don't want | |
3398 | * any callbacks. | |
3381 | 3399 | * @param data a user-defined pointer that is passed along to |
3382 | * the <code>progress</code> function in order to | |
3383 | * pass along some user defined data to the progress | |
3384 | * updates. If not used, set this to NULL. | |
3400 | * the <code>progress</code> function in order to | |
3401 | * pass along some user defined data to the progress | |
3402 | * updates. If not used, set this to NULL. | |
3385 | 3403 | * @return a list of tracks that can be followed using the <code>next</code> |
3386 | * field of the <code>LIBMTP_track_t</code> data structure. | |
3387 | * Each of the metadata tags must be freed after use, and may | |
3388 | * contain only partial metadata information, i.e. one or several | |
3389 | * fields may be NULL or 0. | |
3404 | * field of the <code>LIBMTP_track_t</code> data structure. | |
3405 | * Each of the metadata tags must be freed after use, and may | |
3406 | * contain only partial metadata information, i.e. one or several | |
3407 | * fields may be NULL or 0. | |
3390 | 3408 | * @see LIBMTP_Get_Trackmetadata() |
3391 | 3409 | */ |
3392 | 3410 | LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device, |
5191 | 5209 | */ |
5192 | 5210 | LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device) |
5193 | 5211 | { |
5212 | PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; | |
5213 | const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb); | |
5194 | 5214 | PTPParams *params = (PTPParams *) device->params; |
5195 | 5215 | LIBMTP_playlist_t *retlists = NULL; |
5196 | 5216 | LIBMTP_playlist_t *curlist = NULL; |
5209 | 5229 | oi = ¶ms->objectinfo[i]; |
5210 | 5230 | |
5211 | 5231 | // Ignore stuff that isn't playlists |
5212 | if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) { | |
5232 | ||
5233 | // For Samsung players we must look for the .spl extension explicitly since | |
5234 | // playlists are not stored as playlist objects. | |
5235 | if ( REQ_SPL && is_spl_playlist(oi) ) { | |
5236 | // Allocate a new playlist type | |
5237 | pl = LIBMTP_new_playlist_t(); | |
5238 | spl_to_playlist_t(device, oi, params->handles.Handler[i], pl); | |
5239 | } | |
5240 | else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) { | |
5213 | 5241 | continue; |
5214 | 5242 | } |
5215 | ||
5216 | // Allocate a new playlist type | |
5217 | pl = LIBMTP_new_playlist_t(); | |
5218 | ||
5219 | // Ignoring the oi->Filename field. | |
5220 | pl->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name); | |
5221 | pl->playlist_id = params->handles.Handler[i]; | |
5222 | pl->parent_id = oi->ParentObject; | |
5223 | pl->storage_id = oi->StorageID; | |
5224 | ||
5225 | // Then get the track listing for this playlist | |
5226 | ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks); | |
5227 | if (ret != PTP_RC_OK) { | |
5228 | add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist: Could not get object references."); | |
5229 | pl->tracks = NULL; | |
5230 | pl->no_tracks = 0; | |
5243 | else { | |
5244 | // Allocate a new playlist type | |
5245 | pl = LIBMTP_new_playlist_t(); | |
5246 | ||
5247 | // Ignoring the oi->Filename field. | |
5248 | pl->name = get_string_from_object(device, params->handles.Handler[i], PTP_OPC_Name); | |
5249 | pl->playlist_id = params->handles.Handler[i]; | |
5250 | pl->parent_id = oi->ParentObject; | |
5251 | pl->storage_id = oi->StorageID; | |
5252 | ||
5253 | // Then get the track listing for this playlist | |
5254 | ret = ptp_mtp_getobjectreferences(params, pl->playlist_id, &pl->tracks, &pl->no_tracks); | |
5255 | if (ret != PTP_RC_OK) { | |
5256 | add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist: Could not get object references."); | |
5257 | pl->tracks = NULL; | |
5258 | pl->no_tracks = 0; | |
5259 | } | |
5231 | 5260 | } |
5232 | 5261 | |
5233 | 5262 | // Add playlist to a list that will be returned afterwards. |
5254 | 5283 | */ |
5255 | 5284 | LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid) |
5256 | 5285 | { |
5286 | PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; | |
5287 | const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb); | |
5257 | 5288 | PTPParams *params = (PTPParams *) device->params; |
5258 | 5289 | uint32_t i; |
5259 | 5290 | |
5273 | 5304 | |
5274 | 5305 | oi = ¶ms->objectinfo[i]; |
5275 | 5306 | |
5307 | // For Samsung players we must look for the .spl extension explicitly since | |
5308 | // playlists are not stored as playlist objects. | |
5309 | if ( REQ_SPL && is_spl_playlist(oi) ) { | |
5310 | // Allocate a new playlist type | |
5311 | pl = LIBMTP_new_playlist_t(); | |
5312 | spl_to_playlist_t(device, oi, params->handles.Handler[i], pl); | |
5313 | return pl; | |
5314 | } | |
5315 | ||
5276 | 5316 | // Ignore stuff that isn't playlists |
5277 | if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) { | |
5317 | else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) { | |
5278 | 5318 | return NULL; |
5279 | 5319 | } |
5280 | 5320 | |
5846 | 5886 | } |
5847 | 5887 | metadata->parent_id = localph; |
5848 | 5888 | |
5889 | // Samsung needs its own special type of playlists | |
5890 | if(FLAG_PLAYLIST_SPL(ptp_usb)) { | |
5891 | return playlist_t_to_spl(device, metadata); | |
5892 | } | |
5893 | ||
5849 | 5894 | // Just create a new abstract audio/video playlist... |
5850 | 5895 | return create_new_abstract_list(device, |
5851 | 5896 | metadata->name, |
5878 | 5923 | int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device, |
5879 | 5924 | LIBMTP_playlist_t const * const metadata) |
5880 | 5925 | { |
5926 | ||
5927 | // Samsung needs its own special type of playlists | |
5928 | PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; | |
5929 | if(FLAG_PLAYLIST_SPL(ptp_usb)) { | |
5930 | return update_spl_playlist(device, metadata); | |
5931 | } | |
5932 | ||
5881 | 5933 | return update_abstract_list(device, |
5882 | 5934 | metadata->name, |
5883 | 5935 | NULL, |
28 | 28 | #ifndef LIBMTP_H_INCLUSION_GUARD |
29 | 29 | #define LIBMTP_H_INCLUSION_GUARD |
30 | 30 | |
31 | #define LIBMTP_VERSION 0.3.0 | |
32 | #define LIBMTP_VERSION_STRING "0.3.0" | |
31 | #define LIBMTP_VERSION 0.3.1 | |
32 | #define LIBMTP_VERSION_STRING "0.3.1" | |
33 | 33 | |
34 | 34 | /* This handles MSVC pecularities */ |
35 | 35 | #ifdef _MSC_VER |
1132 | 1132 | } |
1133 | 1133 | } |
1134 | 1134 | if (usbdata.length == 0xffffffffU) { |
1135 | /* Copy first part of data to 'data' */ | |
1136 | handler->putfunc( | |
1137 | params, handler->private, rlen - PTP_USB_BULK_HDR_LEN, usbdata.payload.data, | |
1138 | &written | |
1139 | ); | |
1135 | 1140 | /* stuff data directly to passed data handler */ |
1136 | 1141 | while (1) { |
1137 | 1142 | unsigned long readdata; |
1138 | int xret; | |
1143 | uint16_t xret; | |
1139 | 1144 | |
1140 | 1145 | xret = ptp_read_func( |
1141 | 1146 | PTP_USB_BULK_HS_MAX_PACKET_LEN_READ, |
1145 | 1150 | 0 |
1146 | 1151 | ); |
1147 | 1152 | if (xret != PTP_RC_OK) |
1148 | return ret; | |
1153 | return xret; | |
1149 | 1154 | if (readdata < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ) |
1150 | 1155 | break; |
1151 | 1156 | } |
90 | 90 | ((a)->rawdevice.device_entry.device_flags & DEVICE_FLAG_BROKEN_SET_SAMPLE_DIMENSIONS) |
91 | 91 | #define FLAG_ALWAYS_PROBE_DESCRIPTOR(a) \ |
92 | 92 | ((a)->rawdevice.device_entry.device_flags & DEVICE_FLAG_ALWAYS_PROBE_DESCRIPTOR) |
93 | #define FLAG_PLAYLIST_SPL_V1(a) \ | |
94 | ((a)->rawdevice.device_entry.device_flags & DEVICE_FLAG_PLAYLIST_SPL_V1) | |
95 | #define FLAG_PLAYLIST_SPL_V2(a) \ | |
96 | ((a)->rawdevice.device_entry.device_flags & DEVICE_FLAG_PLAYLIST_SPL_V2) | |
97 | #define FLAG_PLAYLIST_SPL(a) \ | |
98 | ((a)->rawdevice.device_entry.device_flags & (DEVICE_FLAG_PLAYLIST_SPL_V1 | DEVICE_FLAG_PLAYLIST_SPL_V2)) | |
93 | 99 | |
94 | 100 | /* connect_first_device return codes */ |
95 | 101 | #define PTP_CD_RC_CONNECTED 0 |
24 | 24 | * This file is supposed to be included within a struct from both libmtp |
25 | 25 | * and libgphoto2. |
26 | 26 | */ |
27 | ||
28 | 27 | /* |
29 | 28 | * MTP device list, trying real bad to get all devices into |
30 | 29 | * this list by stealing from everyone I know. |
66 | 65 | { "Creative", 0x041e, "ZEN", 0x4157, DEVICE_FLAG_IGNORE_HEADER_ERRORS | DEVICE_FLAG_BROKEN_SET_SAMPLE_DIMENSIONS }, |
67 | 66 | // Reported by Ringofan <mcroman@users.sourceforge.net> |
68 | 67 | { "Creative", 0x041e, "ZEN V 2GB", 0x4158, DEVICE_FLAG_NONE }, |
68 | // Reported by Aaron F. Gonzalez <sub_tex@users.sourceforge.net> | |
69 | { "Creative", 0x041e, "ZEN X-Fi", 0x4162, DEVICE_FLAG_NONE }, | |
69 | 70 | |
70 | 71 | /* |
71 | 72 | * Samsung |
72 | 73 | * We suspect that more of these are dual mode. |
73 | 74 | * We suspect more of these might need DEVICE_FLAG_NO_ZERO_READS |
75 | * We suspect more of these might need DEVICE_FLAG_PLAYLIST_SPL_V1 | |
76 | * or DEVICE_FLAG_PLAYLIST_SPL_V2 to get playlists working. | |
74 | 77 | * YP-NEU, YP-NDU, YP-20, YP-800, YP-MF Series, YP-100, YP-30 |
75 | 78 | * YP-700 and YP-90 are NOT MTP, but use a Samsung custom protocol. |
76 | 79 | */ |
77 | 80 | // From anonymous SourceForge user, not verified |
78 | 81 | { "Samsung", 0x04e8, "YP-900", 0x0409, DEVICE_FLAG_NONE }, |
82 | // From MItch <dbaker@users.sourceforge.net> | |
83 | { "Samsung", 0x04e8, "I550W Phone", 0x04a4, DEVICE_FLAG_NONE }, | |
84 | // From Gabriel Nunes <gabrielkm1@yahoo.com.br> | |
85 | { "Samsung", 0x04e8, "YH-920 (501d)", 0x501d, DEVICE_FLAG_UNLOAD_DRIVER }, | |
79 | 86 | // From Soren O'Neill |
80 | { "Samsung", 0x04e8, "YH-920", 0x5022, DEVICE_FLAG_UNLOAD_DRIVER }, | |
87 | { "Samsung", 0x04e8, "YH-920 (5022)", 0x5022, DEVICE_FLAG_UNLOAD_DRIVER }, | |
81 | 88 | // Contributed by aronvanammers on SourceForge |
82 | 89 | { "Samsung", 0x04e8, "YH-925GS", 0x5024, DEVICE_FLAG_NONE }, |
83 | 90 | // From libgphoto2, according to tests by Stephan Fabel it cannot |
84 | 91 | // get all objects with the getobjectproplist command.. |
85 | 92 | { "Samsung", 0x04e8, "YH-820", 0x502e, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL }, |
86 | 93 | // Contributed by polux2001@users.sourceforge.net |
87 | { "Samsung", 0x04e8, "YH-925(-GS)", 0x502f, DEVICE_FLAG_UNLOAD_DRIVER | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL }, | |
94 | { "Samsung", 0x04e8, "YH-925(-GS)", 0x502f, DEVICE_FLAG_UNLOAD_DRIVER | | |
95 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL }, | |
88 | 96 | // Contributed by anonymous person on SourceForge |
89 | 97 | { "Samsung", 0x04e8, "YH-J70J", 0x5033, DEVICE_FLAG_UNLOAD_DRIVER }, |
90 | 98 | // From XNJB user |
91 | { "Samsung", 0x04e8, "YP-Z5", 0x503c, DEVICE_FLAG_UNLOAD_DRIVER }, | |
99 | // Guessing on .spl flag | |
100 | { "Samsung", 0x04e8, "YP-Z5", 0x503c, DEVICE_FLAG_UNLOAD_DRIVER | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
92 | 101 | // From XNJB user |
93 | { "Samsung", 0x04e8, "YP-Z5 2GB", 0x5041, DEVICE_FLAG_NONE }, | |
102 | // Guessing on .spl flag | |
103 | { "Samsung", 0x04e8, "YP-Z5 2GB", 0x5041, DEVICE_FLAG_NONE | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
94 | 104 | // Contributed by anonymous person on SourceForge |
95 | 105 | { "Samsung", 0x04e8, "YP-T7J", 0x5047, DEVICE_FLAG_NONE }, |
96 | 106 | // Reported by cstrickler@gmail.com |
98 | 108 | // Reported by Andrew Benson |
99 | 109 | { "Samsung", 0x04e8, "YP-F2J", 0x5057, DEVICE_FLAG_UNLOAD_DRIVER }, |
100 | 110 | // Reported by Patrick <skibler@gmail.com> |
101 | { "Samsung", 0x04e8, "YP-K5", 0x505a, DEVICE_FLAG_NO_ZERO_READS }, | |
111 | // Just guessing but looks like .spl v1 http://www.anythingbutipod.com/forum/showthread.php?t=14160 | |
112 | { "Samsung", 0x04e8, "YP-K5", 0x505a, DEVICE_FLAG_NO_ZERO_READS | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
102 | 113 | // From dev.local@gmail.com - 0x4e8/0x507c is the UMS mode, apparently |
103 | 114 | // do not add that device. |
104 | 115 | // From m.eik michalke |
105 | { "Samsung", 0x04e8, "YP-U3", 0x507d, DEVICE_FLAG_NONE }, | |
116 | // Guessing on .spl flag | |
117 | { "Samsung", 0x04e8, "YP-U3", 0x507d, DEVICE_FLAG_NONE | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
106 | 118 | // Reported by Matthew Wilcox <matthew@wil.cx> |
107 | 119 | // Sergio <sfrdll@tiscali.it> reports this device need the BROKEN ALL flag. |
108 | { "Samsung", 0x04e8, "YP-T9", 0x507f, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL }, | |
120 | // Guessing on .spl flag | |
121 | { "Samsung", 0x04e8, "YP-T9", 0x507f, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
109 | 122 | // From Paul Clinch |
110 | { "Samsung", 0x04e8, "YP-K3", 0x5081, DEVICE_FLAG_NONE }, | |
123 | // Just guessing but looks like .spl v1 http://www.anythingbutipod.com/forum/showthread.php?t=14160 | |
124 | { "Samsung", 0x04e8, "YP-K3", 0x5081, DEVICE_FLAG_NONE | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
111 | 125 | // From XNJB user |
112 | { "Samsung", 0x04e8, "YP-P2", 0x5083, DEVICE_FLAG_NO_ZERO_READS }, | |
126 | // From Alistair Boyle, .spl v2 required for playlists | |
127 | { "Samsung", 0x04e8, "YP-P2", 0x5083, DEVICE_FLAG_NO_ZERO_READS | DEVICE_FLAG_PLAYLIST_SPL_V2 }, | |
113 | 128 | // From Paul Clinch |
114 | { "Samsung", 0x04e8, "YP-T10", 0x508a, DEVICE_FLAG_OGG_IS_UNKNOWN | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST }, | |
129 | // Guessing on .spl flag | |
130 | { "Samsung", 0x04e8, "YP-T10", 0x508a, DEVICE_FLAG_OGG_IS_UNKNOWN | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
115 | 131 | // From Wim Verwimp <wimverwimp@gmail.com> |
116 | 132 | // Not sure about the Ogg and broken proplist flags here. Just guessing. |
117 | { "Samsung", 0x04e8, "YP-S5", 0x508b, DEVICE_FLAG_OGG_IS_UNKNOWN | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST }, | |
133 | // Guessing on .spl flag | |
134 | { "Samsung", 0x04e8, "YP-S5", 0x508b, DEVICE_FLAG_OGG_IS_UNKNOWN | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
135 | // From Ludovic Danigo | |
136 | // Guessing on .spl flag | |
137 | { "Samsung", 0x04e8, "YP-S3", 0x5091, DEVICE_FLAG_OGG_IS_UNKNOWN | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_PLAYLIST_SPL_V1 }, | |
118 | 138 | // From a rouge .INF file, |
119 | 139 | // this device ID seems to have been recycled for: |
120 | 140 | // the Samsung SGH-A707 Cingular cellphone |
312 | 332 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS | |
313 | 333 | DEVICE_FLAG_IRIVER_OGG_ALZHEIMER }, |
314 | 334 | // Reported by two anonymous SourceForge users |
335 | // Needs the stronger OGG_IS_UNKNOWN flag to support OGG properly, | |
336 | // be aware of newer players that may be needing this too. | |
315 | 337 | { "iRiver", 0x4102, "E100", 0x1141, |
316 | 338 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS | |
317 | DEVICE_FLAG_IRIVER_OGG_ALZHEIMER }, | |
339 | DEVICE_FLAG_OGG_IS_UNKNOWN }, | |
340 | // Reported by anonymous SourceForge user | |
341 | // Need verification of whether this firmware really need all these flags | |
342 | { "iRiver", 0x4102, "E100 v2", 0x1142, | |
343 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS | | |
344 | DEVICE_FLAG_OGG_IS_UNKNOWN }, | |
318 | 345 | // Reported by Scott Call |
346 | // Assume this actually supports OGG though it reports it doesn't. | |
319 | 347 | { "iRiver", 0x4102, "H10 20GB", 0x2101, |
320 | 348 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS | |
321 | DEVICE_FLAG_IRIVER_OGG_ALZHEIMER }, | |
349 | DEVICE_FLAG_OGG_IS_UNKNOWN }, | |
322 | 350 | { "iRiver", 0x4102, "H10", 0x2102, |
323 | 351 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS | |
324 | DEVICE_FLAG_IRIVER_OGG_ALZHEIMER }, | |
352 | DEVICE_FLAG_OGG_IS_UNKNOWN }, | |
325 | 353 | |
326 | 354 | |
327 | 355 | /* |
348 | 376 | { "Toshiba", 0x0930, "Gigabeat MEU202", 0x0018, DEVICE_FLAG_NO_RELEASE_INTERFACE }, |
349 | 377 | // Reported by Rolf <japan (at) dl3lar.de> |
350 | 378 | { "Toshiba", 0x0930, "Gigabeat T", 0x0019, DEVICE_FLAG_NONE }, |
379 | // Reported by Phil Ingram <ukpbert@users.sourceforge.net> | |
380 | // Tentatively added - no real reports of this device ID being MTP, | |
381 | // reports as USB Mass Storage currently. | |
382 | { "Toshiba", 0x0930, "Gigabeat MEU201", 0x001a, DEVICE_FLAG_NONE }, | |
351 | 383 | |
352 | 384 | |
353 | 385 | /* |
380 | 412 | * interface. |
381 | 413 | */ |
382 | 414 | { "Dunlop", 0x10d6, "MP3 player 1GB / EGOMAN MD223AFD", 0x2200, DEVICE_FLAG_UNLOAD_DRIVER}, |
415 | // Reported by Steven Black <stevenblack1956@users.sourceforge.net> | |
416 | // Obviously this company goes by many names. | |
417 | // This device is USB 2.0 only. | |
418 | { "Memorex", 0x10d6, "MMP 8585/8586", 0x2300, DEVICE_FLAG_UNLOAD_DRIVER }, | |
383 | 419 | |
384 | 420 | /* |
385 | 421 | * Microsoft |
386 | 422 | */ |
387 | // Reported by Farooq Zaman | |
423 | // Reported by Farooq Zaman (used for all Zunes) | |
388 | 424 | { "Microsoft", 0x045e, "Zune", 0x0710, DEVICE_FLAG_NONE }, |
389 | 425 | |
390 | 426 | /* |
394 | 430 | // Reported by Chris Bagwell <chris@cnpbagwell.com> |
395 | 431 | // Apparently this comes with a firmware upgrade to the original |
396 | 432 | // Stiletto as well. |
397 | { "Sirius", 0x18f6, "Stiletto 2", 0x0110, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST }, | |
433 | { "Sirius", 0x18f6, "Stiletto 2", 0x0110, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL }, | |
398 | 434 | |
399 | 435 | /* |
400 | 436 | * Canon |
417 | 453 | { "Nokia", 0x0421, "3110c Mobile Phone", 0x005f, DEVICE_FLAG_NONE }, |
418 | 454 | // From: Vasily <spc-@users.sourceforge.net> |
419 | 455 | { "Nokia", 0x0421, "3109c Mobile Phone", 0x0065, DEVICE_FLAG_NONE }, |
456 | // From: <rawc@users.sourceforge.net> | |
457 | { "Nokia", 0x0421, "5310 XpressMusic", 0x006c, DEVICE_FLAG_NONE }, | |
420 | 458 | // From: robin (AT) headbank D0Tco DOTuk |
421 | 459 | { "Nokia", 0x0421, "N95 Mobile Phone 8GB", 0x006e, DEVICE_FLAG_NONE }, |
460 | // From: danielw | |
461 | { "Nokia", 0x0421, "E71", 0x00e4, DEVICE_FLAG_NONE }, | |
422 | 462 | // From: Christian Rusa <kristous@users.sourceforge.net> |
423 | 463 | { "Nokia", 0x0421, "5700 XpressMusic Mobile Phone", 0x04b4, DEVICE_FLAG_NONE }, |
424 | 464 | // From: Mitchell Hicks <mitchix@yahoo.com> |
431 | 471 | { "Nokia", 0x0421, "N95 Mobile Phone", 0x04ef, DEVICE_FLAG_NONE }, |
432 | 472 | // From: Pat Nicholls <pat@patandannie.co.uk> |
433 | 473 | { "Nokia", 0x0421, "N80 Internet Edition (Media Player)", 0x04f1, DEVICE_FLAG_UNLOAD_DRIVER }, |
474 | // Reported by anonymous SourceForge user | |
475 | // One thing stated by reporter (Nokia model) another by the detect log... | |
476 | { "Nokia/Verizon", 0x05c6, "6205 Balboa/Verizon Music Phone", 0x3196, DEVICE_FLAG_NONE }, | |
434 | 477 | |
435 | 478 | |
436 | 479 | /* |
466 | 509 | { "Palm Handspring", 0x1703, "Pocket Tunes 4", 0x0002, DEVICE_FLAG_NONE }, |
467 | 510 | |
468 | 511 | /* |
469 | * TrekStor devices | |
512 | * TrekStor and Medion devices | |
470 | 513 | * Their datasheet claims their devices are dualmode so probably needs to |
471 | 514 | * unload the attached drivers here. |
472 | 515 | */ |
473 | 516 | // Reported by Stefan Voss <svoss@web.de> |
474 | 517 | // This is a Sigmatel SoC with a hard disk. |
475 | 518 | { "TrekStor", 0x066f, "Vibez 8/12GB", 0x842a, |
476 | DEVICE_FLAG_UNLOAD_DRIVER | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST }, | |
519 | DEVICE_FLAG_UNLOAD_DRIVER | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST }, | |
520 | // Reported by anonymous SourceForge user. | |
521 | // This one done for Medion, whatever that is. Error reported so assume | |
522 | // the same bug flag as its ancestor above. | |
523 | { "Medion", 0x066f, "MD8333", 0x8550, | |
524 | DEVICE_FLAG_UNLOAD_DRIVER | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST }, | |
477 | 525 | // Reported by Cristi Magherusan <majeru@gentoo.ro> |
478 | 526 | { "TrekStor", 0x0402, "i.Beat Sweez FM", 0x0611, |
479 | DEVICE_FLAG_UNLOAD_DRIVER }, | |
527 | DEVICE_FLAG_UNLOAD_DRIVER }, | |
480 | 528 | |
481 | 529 | /* |
482 | 530 | * Disney/Tevion (have had no reports of these actually working.) |
513 | 561 | * LG Electronics |
514 | 562 | */ |
515 | 563 | // Not verified - anonymous submission |
516 | { "LG", 0x043e, "UP3", 0x70b1, DEVICE_FLAG_NONE }, | |
564 | { "LG Electronics Inc.", 0x043e, "UP3", 0x70b1, DEVICE_FLAG_NONE }, | |
565 | // Reported by Joseph Nahmias <joe@nahimas.net> | |
566 | { "LG Electronics Inc.", 0x1004, "VX8550 V CAST Mobile Phone", 0x6010, | |
567 | DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_ALWAYS_PROBE_DESCRIPTOR }, | |
517 | 568 | |
518 | 569 | /* |
519 | 570 | * Sony |
543 | 594 | { "SonyEricsson", 0x0fce, "W910", 0x0076, DEVICE_FLAG_NONE }, |
544 | 595 | // Reported by Zack <zackdvd@users.sourceforge.net> |
545 | 596 | { "SonyEricsson", 0x0fce, "W890i", 0x00b3, DEVICE_FLAG_NONE }, |
597 | // Reported by robert dot ahlskog at gmail | |
598 | { "SonyEricsson", 0x0fce, "W760i", 0x00c6, DEVICE_FLAG_NONE }, | |
546 | 599 | // Reported by Linus Åkesson <linusakesson@users.sourceforge.net> |
547 | 600 | { "SonyEricsson", 0x0fce, "C902", 0x00d4, DEVICE_FLAG_NONE }, |
601 | // Reported by an anonymous SourceForge user | |
602 | { "SonyEricsson", 0x0fce, "C702", 0x00d9, DEVICE_FLAG_NONE }, | |
548 | 603 | |
549 | 604 | /* |
550 | 605 | * Motorola |
0 | /** | |
1 | * \file playlist-spl.c | |
2 | * | |
3 | * Playlist_t to Samsung (.spl) and back conversion functions. | |
4 | * | |
5 | * Copyright (C) 2008 Alistair Boyle <alistair.js.boyle@gmail.com> | |
6 | * | |
7 | * This library is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU Lesser General Public | |
9 | * License as published by the Free Software Foundation; either | |
10 | * version 2 of the License, or (at your option) any later version. | |
11 | * | |
12 | * This library is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | * Lesser General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU Lesser General Public | |
18 | * License along with this library; if not, write to the | |
19 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
20 | * Boston, MA 02111-1307, USA. | |
21 | */ | |
22 | ||
23 | ||
24 | // TODO do I actually use all these? | |
25 | #include <stdio.h> | |
26 | #include <stdlib.h> // mkstmp() | |
27 | #include <errno.h> | |
28 | #include <sys/stat.h> | |
29 | #include <fcntl.h> | |
30 | ||
31 | #include <string.h> | |
32 | ||
33 | #include "libmtp.h" | |
34 | #include "libusb-glue.h" | |
35 | #include "ptp.h" | |
36 | #include "unicode.h" | |
37 | ||
38 | #include "playlist-spl.h" | |
39 | ||
40 | // set this to 1 to add lots of messy debug output to the playlist code | |
41 | #define DEBUG_ENABLED 0 | |
42 | ||
43 | // debug macro | |
44 | // d = indenting depth | |
45 | #define IF_DEBUG() if(DEBUG_ENABLED) {\ | |
46 | printf("%s:%u:%s(): ", __FILE__, __LINE__, __func__); \ | |
47 | } \ | |
48 | if(DEBUG_ENABLED) | |
49 | ||
50 | // Internal singly linked list of strings | |
51 | // used to hold .spl playlist in memory | |
52 | typedef struct text_struct { | |
53 | char* text; // String | |
54 | struct text_struct *next; // Link to next line, NULL if end of list | |
55 | } text_t; | |
56 | ||
57 | ||
58 | /** | |
59 | * Forward declarations of local (static) functions. | |
60 | */ | |
61 | static text_t* read_into_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd); | |
62 | static void write_from_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd, text_t* p); | |
63 | static void free_spl_text_t(text_t* p); | |
64 | static void print_spl_text_t(text_t* p); | |
65 | static uint32_t trackno_spl_text_t(text_t* p); | |
66 | static void tracks_from_spl_text_t(text_t* p, uint32_t* tracks, LIBMTP_folder_t* folders, LIBMTP_file_t* files); | |
67 | 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); | |
68 | ||
69 | static uint32_t discover_id_from_filepath(const char* s, LIBMTP_folder_t* folders, LIBMTP_file_t* files); // TODO add file/dir cached args | |
70 | static void discover_filepath_from_id(char** p, uint32_t track, LIBMTP_folder_t* folders, LIBMTP_file_t* files); | |
71 | static void find_folder_name(LIBMTP_folder_t* folders, uint32_t* id, char** name); | |
72 | static uint32_t find_folder_id(LIBMTP_folder_t* folders, uint32_t parent, char* name); | |
73 | ||
74 | static void append_text_t(text_t** t, char* s); | |
75 | ||
76 | ||
77 | ||
78 | ||
79 | /** | |
80 | * Decides if the indicated object index is an .spl playlist. | |
81 | * | |
82 | * @param oi object we are deciding on | |
83 | * @return 1 if this is a Samsung .spl object, 0 otherwise | |
84 | */ | |
85 | int is_spl_playlist(PTPObjectInfo *oi) | |
86 | { | |
87 | return (oi->ObjectFormat == PTP_OFC_Undefined) && | |
88 | (strlen(oi->Filename) > 4) && | |
89 | (strcmp((oi->Filename + strlen(oi->Filename) -4), ".spl") == 0); | |
90 | } | |
91 | ||
92 | /** | |
93 | * Take an object ID, a .spl playlist on the MTP device, | |
94 | * and convert it to a playlist_t object. | |
95 | * | |
96 | * @param device mtp device pointer | |
97 | * @param oi object we are reading | |
98 | * @param id .spl playlist id on MTP device | |
99 | * @param pl the LIBMTP_playlist_t pointer to be filled with info from id | |
100 | */ | |
101 | ||
102 | void spl_to_playlist_t(LIBMTP_mtpdevice_t* device, PTPObjectInfo *oi, | |
103 | const uint32_t id, LIBMTP_playlist_t * const pl) | |
104 | { | |
105 | // Fill in playlist metadata | |
106 | // Use the Filename as the playlist name, dropping the ".spl" extension | |
107 | pl->name = malloc(sizeof(char)*(strlen(oi->Filename) -4 +1)); | |
108 | memcpy(pl->name, oi->Filename, strlen(oi->Filename) -4); | |
109 | pl->playlist_id = id; | |
110 | pl->parent_id = oi->ParentObject; | |
111 | pl->storage_id = oi->StorageID; | |
112 | pl->tracks = NULL; | |
113 | pl->no_tracks = 0; | |
114 | ||
115 | IF_DEBUG() printf("pl->name='%s'\n",pl->name); | |
116 | ||
117 | // open a temporary file | |
118 | char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX"; | |
119 | int fd = mkstemp(tmpname); | |
120 | if(fd < 0) { | |
121 | printf("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); | |
122 | return; | |
123 | } | |
124 | // make sure the file will be deleted afterwards | |
125 | if(unlink(tmpname) < 0) | |
126 | printf("failed to delete temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); | |
127 | int ret = LIBMTP_Get_File_To_File_Descriptor(device, pl->playlist_id, fd, NULL, NULL); | |
128 | if( ret < 0 ) { | |
129 | // FIXME add_ptp_error_to_errorstack(device, ret, "LIBMTP_Get_Playlist: Could not get .spl playlist file."); | |
130 | close(fd); | |
131 | printf("FIXME closed\n"); | |
132 | } | |
133 | ||
134 | text_t* p = read_into_spl_text_t(device, fd); | |
135 | close(fd); | |
136 | ||
137 | // FIXME cache these somewhere else so we don't keep calling this! | |
138 | LIBMTP_folder_t *folders; | |
139 | LIBMTP_file_t *files; | |
140 | folders = LIBMTP_Get_Folder_List(device); | |
141 | files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL); | |
142 | ||
143 | // convert the playlist listing to track ids | |
144 | pl->no_tracks = trackno_spl_text_t(p); | |
145 | IF_DEBUG() printf("%u track%s found\n", pl->no_tracks, pl->no_tracks==1?"":"s"); | |
146 | pl->tracks = malloc(sizeof(uint32_t)*(pl->no_tracks)); | |
147 | tracks_from_spl_text_t(p, pl->tracks, folders, files); | |
148 | ||
149 | free_spl_text_t(p); | |
150 | ||
151 | // debug: add a break since this is the top level function call | |
152 | IF_DEBUG() printf("------------\n\n"); | |
153 | } | |
154 | ||
155 | ||
156 | /** | |
157 | * Push a playlist_t onto the device after converting it to a .spl format | |
158 | * | |
159 | * @param device mtp device pointer | |
160 | * @param pl the LIBMTP_playlist_t to convert (pl->playlist_id will be updated | |
161 | * with the newly created object's id) | |
162 | * @return 0 on success, any other value means failure. | |
163 | */ | |
164 | int playlist_t_to_spl(LIBMTP_mtpdevice_t *device, | |
165 | LIBMTP_playlist_t * const pl) | |
166 | { | |
167 | text_t* t; | |
168 | LIBMTP_folder_t *folders; | |
169 | LIBMTP_file_t *files; | |
170 | folders = LIBMTP_Get_Folder_List(device); | |
171 | files = LIBMTP_Get_Filelisting_With_Callback(device, NULL, NULL); | |
172 | ||
173 | char tmpname[] = "/tmp/mtp-spl2pl-XXXXXX"; // must be a var since mkstemp modifies it | |
174 | ||
175 | IF_DEBUG() printf("pl->name='%s'\n",pl->name); | |
176 | ||
177 | // open a file descriptor | |
178 | int fd = mkstemp(tmpname); | |
179 | if(fd < 0) { | |
180 | printf("failed to make temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); | |
181 | return -1; | |
182 | } | |
183 | // make sure the file will be deleted afterwards | |
184 | if(unlink(tmpname) < 0) | |
185 | printf("failed to delete temp file for %s.spl -> %s, errno=%s\n", pl->name, tmpname, strerror(errno)); | |
186 | ||
187 | // decide on which version of the .spl format to use | |
188 | uint32_t ver_major; | |
189 | uint32_t ver_minor = 0; | |
190 | PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo; | |
191 | if(FLAG_PLAYLIST_SPL_V2(ptp_usb)) ver_major = 2; | |
192 | else ver_major = 1; // FLAG_PLAYLIST_SPL_V1() | |
193 | ||
194 | IF_DEBUG() printf("%u track%s\n", pl->no_tracks, pl->no_tracks==1?"":"s"); | |
195 | IF_DEBUG() printf(".spl version %d.%02d\n", ver_major, ver_minor); | |
196 | ||
197 | // create the text for the playlist | |
198 | spl_text_t_from_tracks(&t, pl->tracks, pl->no_tracks, ver_major, ver_minor, NULL, folders, files); | |
199 | write_from_spl_text_t(device, fd, t); | |
200 | free_spl_text_t(t); // done with the text | |
201 | ||
202 | // create the file object for storing | |
203 | LIBMTP_file_t* f = malloc(sizeof(LIBMTP_file_t)); | |
204 | f->item_id = 0; | |
205 | f->parent_id = pl->parent_id; | |
206 | f->storage_id = pl->storage_id; | |
207 | f->filename = malloc(sizeof(char)*(strlen(pl->name)+5)); | |
208 | strcpy(f->filename, pl->name); | |
209 | strcat(f->filename, ".spl"); // append suffix | |
210 | f->filesize = lseek(fd, 0, SEEK_CUR); // file desc is currently at end of file | |
211 | f->filetype = LIBMTP_FILETYPE_UNKNOWN; | |
212 | f->next = NULL; | |
213 | ||
214 | IF_DEBUG() printf("%s is %dB\n", f->filename, (int)f->filesize); | |
215 | ||
216 | // push the playlist to the device | |
217 | lseek(fd, 0, SEEK_SET); // reset file desc. to start of file | |
218 | int ret = LIBMTP_Send_File_From_File_Descriptor(device, fd, f, NULL, NULL); | |
219 | pl->playlist_id = f->item_id; | |
220 | free(f->filename); | |
221 | free(f); | |
222 | ||
223 | // release the memory when we're done with it | |
224 | close(fd); | |
225 | // debug: add a break since this is the top level function call | |
226 | IF_DEBUG() printf("------------\n\n"); | |
227 | ||
228 | return ret; | |
229 | } | |
230 | ||
231 | ||
232 | ||
233 | /** | |
234 | * Update a playlist on the device. If only the playlist's name is being | |
235 | * changed the pl->playlist_id will likely remain the same. An updated track | |
236 | * list will result in the old playlist being replaced (ie: new playlist_id). | |
237 | * NOTE: Other playlist metadata aside from playlist name and tracks are | |
238 | * ignored. | |
239 | * | |
240 | * @param device mtp device pointer | |
241 | * @param new the LIBMTP_playlist_t to convert (pl->playlist_id will be updated | |
242 | * with the newly created object's id) | |
243 | * @return 0 on success, any other value means failure. | |
244 | */ | |
245 | int update_spl_playlist(LIBMTP_mtpdevice_t *device, | |
246 | LIBMTP_playlist_t const * const new) | |
247 | { | |
248 | IF_DEBUG() printf("pl->name='%s'\n",new->name); | |
249 | ||
250 | // read in the playlist of interest | |
251 | LIBMTP_playlist_t * old = LIBMTP_Get_Playlist(device, new->playlist_id); | |
252 | ||
253 | // check if the playlists match | |
254 | int delta = 0; | |
255 | int i; | |
256 | if(old->no_tracks != new->no_tracks) | |
257 | delta++; | |
258 | for(i=0;i<new->no_tracks && delta==0;i++) { | |
259 | if(old->tracks[i] != new->tracks[i]) | |
260 | delta++; | |
261 | } | |
262 | ||
263 | // if not, kill the playlist and replace it | |
264 | if(delta) { | |
265 | IF_DEBUG() printf("new tracks detected:\n"); | |
266 | IF_DEBUG() printf("delete old playlist and build a new one\n"); | |
267 | IF_DEBUG() printf(" NOTE: new playlist_id will result!\n"); | |
268 | if(LIBMTP_Delete_Object(device, old->playlist_id) != 0) | |
269 | return -1; | |
270 | ||
271 | IF_DEBUG() { | |
272 | if(strcmp(old->name,new->name) == 0) | |
273 | printf("name unchanged\n"); | |
274 | else | |
275 | printf("name is changing too -> %s\n",new->name); | |
276 | } | |
277 | ||
278 | return LIBMTP_Create_New_Playlist(device, new); | |
279 | } | |
280 | ||
281 | ||
282 | // update the name only | |
283 | if(strcmp(old->name,new->name) != 0) { | |
284 | IF_DEBUG() printf("ONLY name is changing -> %s\n",new->name); | |
285 | IF_DEBUG() printf("playlist_id will remain unchanged\n"); | |
286 | char* s = malloc(sizeof(char)*(strlen(new->name)+5)); | |
287 | strcpy(s, new->name); | |
288 | strcat(s,".spl"); // FIXME check for success | |
289 | int ret = LIBMTP_Set_Object_Filename(device, new->playlist_id, s); | |
290 | free(s); | |
291 | return ret; | |
292 | } | |
293 | ||
294 | IF_DEBUG() printf("no change\n"); | |
295 | return 0; // nothing to be done, success | |
296 | } | |
297 | ||
298 | ||
299 | /** | |
300 | * Load a file descriptor into a string. | |
301 | * | |
302 | * @param device a pointer to the current device. | |
303 | * (needed for ucs2->utf8 charset conversion) | |
304 | * @param fd the file descriptor to load | |
305 | * @return text_t* a linked list of lines of text, id is left blank, NULL if nothing read in | |
306 | */ | |
307 | static text_t* read_into_spl_text_t(LIBMTP_mtpdevice_t *device, const int fd) | |
308 | { | |
309 | // set MAXREAD to match STRING_BUFFER_LENGTH in unicode.h conversion function | |
310 | const size_t MAXREAD = 1024*2; | |
311 | char t[MAXREAD]; | |
312 | // upto 3 bytes per utf8 character, 2 bytes per ucs2 character, | |
313 | // +1 for '\0' at end of string | |
314 | const size_t WSIZE = MAXREAD/2*3+1; | |
315 | char w[WSIZE]; | |
316 | char* it = t; // iterator on t | |
317 | char* iw = w; | |
318 | ssize_t rdcnt; | |
319 | off_t offcnt; | |
320 | text_t* head = NULL; | |
321 | text_t* tail = NULL; | |
322 | int eof = 0; | |
323 | ||
324 | // reset file descriptor (fd) to start of file | |
325 | offcnt = lseek(fd, 0, SEEK_SET); | |
326 | ||
327 | while(!eof) { | |
328 | // find the current offset in the file | |
329 | // to allow us to determine how many bytes we read if we hit the EOF | |
330 | // where returned rdcnt=0 from read() | |
331 | offcnt = lseek(fd, 0, SEEK_CUR); | |
332 | // read to refill buffer | |
333 | // (there might be data left from an incomplete last string in t, | |
334 | // hence start filling at it) | |
335 | it = t; // set ptr to start of buffer | |
336 | rdcnt = read(fd, it, sizeof(char)*MAXREAD); | |
337 | if(rdcnt < 0) | |
338 | printf("load_spl_fd read err %s\n", strerror(errno)); | |
339 | else if(rdcnt == 0) { // for EOF, fix rdcnt | |
340 | if(it-t == MAXREAD) | |
341 | printf("error -- buffer too small to read in .spl playlist entry\n"); | |
342 | ||
343 | rdcnt = lseek(fd, 0, SEEK_CUR) - offcnt; | |
344 | eof = 1; | |
345 | } | |
346 | ||
347 | IF_DEBUG() printf("read buff= {%dB new, %dB old/left-over}%s\n",(int)rdcnt, (int)(iw-w), eof?", EOF":""); | |
348 | ||
349 | // while more input bytes | |
350 | char* it_end = t + rdcnt; | |
351 | while(it < it_end) { | |
352 | // copy byte, unless EOL (then replace with end-of-string \0) | |
353 | if(*it == '\r' || *it == '\n') | |
354 | *iw = '\0'; | |
355 | else | |
356 | *iw = *it; | |
357 | ||
358 | it++; | |
359 | iw++; | |
360 | ||
361 | // EOL -- store it | |
362 | if( (iw-w) >= 2 && // we must have at least two bytes | |
363 | *(iw-1) == '\0' && *(iw-2) == '\0' && // 0x0000 is end-of-string | |
364 | // but it must be aligned such that we have an {odd,even} set of | |
365 | // bytes since we are expecting to consume bytes two-at-a-time | |
366 | !((iw-w)%2) ) { | |
367 | ||
368 | // drop empty lines | |
369 | // ... cast as a string of 2 byte characters | |
370 | if(ucs2_strlen((uint16_t*)w) == 0) { | |
371 | iw = w; | |
372 | continue; | |
373 | } | |
374 | ||
375 | // create a new node in the list | |
376 | if(head == NULL) { | |
377 | head = malloc(sizeof(text_t)); | |
378 | tail = head; | |
379 | } | |
380 | else { | |
381 | tail->next = malloc(sizeof(text_t)); | |
382 | tail = tail->next; | |
383 | } | |
384 | // fill in the data for the node | |
385 | // ... cast as a string of 2 byte characters | |
386 | tail->text = utf16_to_utf8(device, (uint16_t*) w); | |
387 | iw = w; // start again | |
388 | ||
389 | IF_DEBUG() printf("line: %s\n", tail->text); | |
390 | } | |
391 | ||
392 | // prevent buffer overflow | |
393 | if(iw >= w + WSIZE) { | |
394 | // if we ever see this error its BAD: | |
395 | // we are dropping all the processed bytes for this line and | |
396 | // proceeding on as if everything is okay, probably losing a track | |
397 | // from the playlist | |
398 | printf("ERROR %s:%u:%s(): buffer overflow! .spl line too long @ %luB\n", | |
399 | __FILE__, __LINE__, __func__, WSIZE); | |
400 | iw = w; // reset buffer | |
401 | } | |
402 | } | |
403 | ||
404 | // if the last thing we did was save our line, then we finished working | |
405 | // on the input buffer and we can start fresh | |
406 | // otherwise we need to save our partial work, if we're not quiting (eof). | |
407 | // there is nothing special we need to do, to achieve this since the | |
408 | // partially completed string will sit in 'w' until we return to complete | |
409 | // the line | |
410 | ||
411 | } | |
412 | ||
413 | // set the next pointer at the end | |
414 | // if there is any list | |
415 | if(head != NULL) | |
416 | tail->next = NULL; | |
417 | ||
418 | // return the head of the list (NULL if no list) | |
419 | return head; | |
420 | } | |
421 | ||
422 | ||
423 | /** | |
424 | * Write a .spl text file to a file in preparation for pushing it | |
425 | * to the device. | |
426 | * | |
427 | * @param fd file descriptor to write to | |
428 | * @param p the text to output one line per string in the linked list | |
429 | * @see playlist_t_to_spl() | |
430 | */ | |
431 | static void write_from_spl_text_t(LIBMTP_mtpdevice_t *device, | |
432 | const int fd, | |
433 | text_t* p) { | |
434 | ssize_t ret; | |
435 | // write out BOM for utf16/ucs2 (byte order mark) | |
436 | ret = write(fd,"\xff\xfe",2); | |
437 | while(p != NULL) { | |
438 | char *const t = (char*) utf8_to_utf16(device, p->text); | |
439 | // note: 2 bytes per ucs2 character | |
440 | const size_t len = ucs2_strlen((uint16_t*)t)*sizeof(uint16_t); | |
441 | int i; | |
442 | ||
443 | IF_DEBUG() { | |
444 | printf("\nutf8=%s ",p->text); | |
445 | for(i=0;i<strlen(p->text);i++) | |
446 | printf("%02x ", p->text[i] & 0xff); | |
447 | printf("\n"); | |
448 | printf("ucs2="); | |
449 | for(i=0;i<ucs2_strlen((uint16_t*)t)*sizeof(uint16_t);i++) | |
450 | printf("%02x ", t[i] & 0xff); | |
451 | printf("\n"); | |
452 | } | |
453 | ||
454 | // write: utf8 -> utf16 | |
455 | ret += write(fd, t, len); | |
456 | ||
457 | // release the converted string | |
458 | free(t); | |
459 | ||
460 | // check for failures | |
461 | if(ret < 0) | |
462 | printf("write spl file failed: %s\n", strerror(errno)); | |
463 | else if(ret != len +2) | |
464 | printf("write spl file wrong number of bytes ret=%d len=%d '%s'\n", (int)ret, (int)len, p->text); | |
465 | ||
466 | // write carriage return, line feed in ucs2 | |
467 | ret = write(fd, "\r\0\n\0", 4); | |
468 | if(ret < 0) | |
469 | printf("write spl file failed: %s\n", strerror(errno)); | |
470 | else if(ret != 4) | |
471 | printf("failed to write the correct number of bytes '\\n'!\n"); | |
472 | ||
473 | // fake out count (first time through has two extra bytes from BOM) | |
474 | ret = 2; | |
475 | ||
476 | // advance to the next line | |
477 | p = p->next; | |
478 | } | |
479 | } | |
480 | ||
481 | /** | |
482 | * Destroy a linked-list of strings. | |
483 | * | |
484 | * @param p the list to destroy | |
485 | * @see spl_to_playlist_t() | |
486 | * @see playlist_t_to_spl() | |
487 | */ | |
488 | static void free_spl_text_t(text_t* p) | |
489 | { | |
490 | text_t* d; | |
491 | while(p != NULL) { | |
492 | d = p; | |
493 | free(p->text); | |
494 | p = p->next; | |
495 | free(d); | |
496 | } | |
497 | } | |
498 | ||
499 | /** | |
500 | * Print a linked-list of strings to stdout. | |
501 | * | |
502 | * @param p the list to print | |
503 | */ | |
504 | static void print_spl_text_t(text_t* p) | |
505 | { | |
506 | while(p != NULL) { | |
507 | printf("%s\n",p->text); | |
508 | p = p->next; | |
509 | } | |
510 | } | |
511 | ||
512 | /** | |
513 | * Count the number of tracks in this playlist. A track will be counted as | |
514 | * such if the line starts with a leading slash. | |
515 | * | |
516 | * @param p the text to search | |
517 | * @return number of tracks in the playlist | |
518 | * @see spl_to_playlist_t() | |
519 | */ | |
520 | static uint32_t trackno_spl_text_t(text_t* p) { | |
521 | uint32_t c = 0; | |
522 | while(p != NULL) { | |
523 | if(p->text[0] == '\\' ) c++; | |
524 | p = p->next; | |
525 | } | |
526 | ||
527 | return c; | |
528 | } | |
529 | ||
530 | /** | |
531 | * Find the track ids for this playlist's files. | |
532 | * (ie: \Music\song.mp3 -> 12345) | |
533 | * | |
534 | * @param p the text to search | |
535 | * @param tracks returned list of track id's for the playlist_t, must be large | |
536 | * enough to accomodate all the tracks as reported by | |
537 | * trackno_spl_text_t() | |
538 | * @param folders the folders list for the device | |
539 | * @param fiels the files list for the device | |
540 | * @see spl_to_playlist_t() | |
541 | */ | |
542 | static void tracks_from_spl_text_t(text_t* p, | |
543 | uint32_t* tracks, | |
544 | LIBMTP_folder_t* folders, | |
545 | LIBMTP_file_t* files) | |
546 | { | |
547 | uint32_t c = 0; | |
548 | while(p != NULL) { | |
549 | if(p->text[0] == '\\' ) { | |
550 | tracks[c] = discover_id_from_filepath(p->text, folders, files); | |
551 | IF_DEBUG() | |
552 | printf("track %d = %s (%u)\n", c+1, p->text, tracks[c]); | |
553 | c++; | |
554 | } | |
555 | p = p->next; | |
556 | } | |
557 | } | |
558 | ||
559 | ||
560 | /** | |
561 | * Find the track names (including path) for this playlist's track ids. | |
562 | * (ie: 12345 -> \Music\song.mp3) | |
563 | * | |
564 | * @param p the text to search | |
565 | * @param tracks list of track id's to look up | |
566 | * @param folders the folders list for the device | |
567 | * @param fiels the files list for the device | |
568 | * @see playlist_t_to_spl() | |
569 | */ | |
570 | static void spl_text_t_from_tracks(text_t** p, | |
571 | uint32_t* tracks, | |
572 | const uint32_t trackno, | |
573 | const uint32_t ver_major, | |
574 | const uint32_t ver_minor, | |
575 | char* dnse, | |
576 | LIBMTP_folder_t* folders, | |
577 | LIBMTP_file_t* files) | |
578 | { | |
579 | ||
580 | // HEADER | |
581 | text_t* c = NULL; | |
582 | append_text_t(&c, "SPL PLAYLIST"); | |
583 | *p = c; // save the top of the list! | |
584 | ||
585 | char vs[14]; // "VERSION 2.00\0" | |
586 | sprintf(vs,"VERSION %d.%02d",ver_major,ver_minor); | |
587 | ||
588 | append_text_t(&c, vs); | |
589 | append_text_t(&c, ""); | |
590 | ||
591 | // TRACKS | |
592 | int i; | |
593 | char* f; | |
594 | for(i=0;i<trackno;i++) { | |
595 | discover_filepath_from_id(&f, tracks[i], folders, files); | |
596 | ||
597 | if(f != NULL) { | |
598 | append_text_t(&c, f); | |
599 | IF_DEBUG() | |
600 | printf("track %d = %s (%u)\n", i+1, f, tracks[i]); | |
601 | } | |
602 | else | |
603 | printf("failed to find filepath for track=%d\n", tracks[i]); | |
604 | } | |
605 | ||
606 | // FOOTER | |
607 | append_text_t(&c, ""); | |
608 | append_text_t(&c, "END PLAYLIST"); | |
609 | if(ver_major == 2) { | |
610 | append_text_t(&c, ""); | |
611 | append_text_t(&c, "myDNSe DATA"); | |
612 | if(dnse != NULL) { | |
613 | append_text_t(&c, dnse); | |
614 | } | |
615 | else { | |
616 | append_text_t(&c, ""); | |
617 | append_text_t(&c, ""); | |
618 | } | |
619 | append_text_t(&c, "END myDNSe"); | |
620 | } | |
621 | ||
622 | c->next = NULL; | |
623 | ||
624 | // debug | |
625 | IF_DEBUG() { | |
626 | printf(".spl playlist:\n"); | |
627 | print_spl_text_t(*p); | |
628 | } | |
629 | } | |
630 | ||
631 | ||
632 | /** | |
633 | * Find the track names (including path) given a fileid | |
634 | * (ie: 12345 -> \Music\song.mp3) | |
635 | * | |
636 | * @param p returns the file path (ie: \Music\song.mp3), | |
637 | * (*p) == NULL if the look up fails | |
638 | * @param track track id to look up | |
639 | * @param folders the folders list for the device | |
640 | * @param files the files list for the device | |
641 | * @see spl_text_t_from_tracks() | |
642 | */ | |
643 | ||
644 | // returns p = NULL on failure, else the filepath to the track including track name, allocated as a correct length string | |
645 | static void discover_filepath_from_id(char** p, | |
646 | uint32_t track, | |
647 | LIBMTP_folder_t* folders, | |
648 | LIBMTP_file_t* files) | |
649 | { | |
650 | // fill in a string from the right side since we don't know the root till the end | |
651 | const int M = 1024; | |
652 | char w[M]; | |
653 | char* iw = w + M; // iterator on w | |
654 | ||
655 | // in case of failure return NULL string | |
656 | *p = NULL; | |
657 | ||
658 | ||
659 | // find the right file | |
660 | while(files != NULL && files->item_id != track) { | |
661 | files = files->next; | |
662 | } | |
663 | // if we didn't find a matching file, abort | |
664 | if(files == NULL) | |
665 | return; | |
666 | ||
667 | // stuff the filename into our string | |
668 | // FIXME: check for string overflow before it occurs | |
669 | iw = iw - (strlen(files->filename) +1); // leave room for '\0' at the end | |
670 | strcpy(iw,files->filename); | |
671 | ||
672 | // next follow the directories to the root | |
673 | // prepending folders to the path as we go | |
674 | uint32_t id = files->parent_id; | |
675 | char* f = NULL; | |
676 | while(id != 0) { | |
677 | find_folder_name(folders, &id, &f); | |
678 | if(f == NULL) return; // fail if the next part of the path couldn't be found | |
679 | iw = iw - (strlen(f) +1); | |
680 | // FIXME: check for string overflow before it occurs | |
681 | strcpy(iw, f); | |
682 | iw[strlen(f)] = '\\'; | |
683 | free(f); | |
684 | } | |
685 | ||
686 | // prepend a slash | |
687 | iw--; | |
688 | iw[0] = '\\'; | |
689 | ||
690 | // now allocate a string of the right length to be returned | |
691 | *p = strdup(iw); | |
692 | } | |
693 | ||
694 | ||
695 | /** | |
696 | * Find the track id given a track's name (including path) | |
697 | * (ie: \Music\song.mp3 -> 12345) | |
698 | * | |
699 | * @param s file path to look up (ie: \Music\song.mp3), | |
700 | * (*p) == NULL if the look up fails | |
701 | * @param folders the folders list for the device | |
702 | * @param files the files list for the device | |
703 | * @return track id, 0 means failure | |
704 | * @see tracks_from_spl_text_t() | |
705 | */ | |
706 | static uint32_t discover_id_from_filepath(const char* s, LIBMTP_folder_t* folders, LIBMTP_file_t* files) | |
707 | { | |
708 | // abort if this isn't a path | |
709 | if(s[0] != '\\') | |
710 | return 0; | |
711 | ||
712 | int i; | |
713 | uint32_t id = 0; | |
714 | char* sc = strdup(s); | |
715 | char* sci = sc +1; // iterator | |
716 | // skip leading slash in path | |
717 | ||
718 | // convert all \ to \0 | |
719 | size_t len = strlen(s); | |
720 | for(i=0;i<len;i++) { | |
721 | if(sc[i] == '\\') { | |
722 | sc[i] = '\0'; | |
723 | } | |
724 | } | |
725 | ||
726 | // now for each part of the string, find the id | |
727 | while(sci != sc + len +1) { | |
728 | // if its the last part of the string, its the filename | |
729 | if(sci + strlen(sci) == sc + len) { | |
730 | ||
731 | while(files != NULL) { | |
732 | // check parent matches id and name matches sci | |
733 | if( (files->parent_id == id) && | |
734 | (strcmp(files->filename, sci) == 0) ) { // found it! | |
735 | id = files->item_id; | |
736 | break; | |
737 | } | |
738 | files = files->next; | |
739 | } | |
740 | } | |
741 | else { // otherwise its part of the directory path | |
742 | id = find_folder_id(folders, id, sci); | |
743 | } | |
744 | ||
745 | // move to next folder/file | |
746 | sci += strlen(sci) +1; | |
747 | } | |
748 | ||
749 | // release our copied string | |
750 | free(sc); | |
751 | ||
752 | // FIXME check that we actually have a file | |
753 | ||
754 | return id; | |
755 | } | |
756 | ||
757 | ||
758 | ||
759 | /** | |
760 | * Find the folder name given the folder's id. | |
761 | * | |
762 | * @param folders the folders list for the device | |
763 | * @param id the folder_id to look up, returns the folder's parent folder_id | |
764 | * @param name returns the name of the folder or NULL on failure | |
765 | * @see discover_filepath_from_id() | |
766 | */ | |
767 | static void find_folder_name(LIBMTP_folder_t* folders, uint32_t* id, char** name) | |
768 | { | |
769 | ||
770 | // FIXME this function is exactly LIBMTP_Find_Folder | |
771 | ||
772 | LIBMTP_folder_t* f = LIBMTP_Find_Folder(folders, *id); | |
773 | if(f == NULL) { | |
774 | *name = NULL; | |
775 | } | |
776 | else { // found it! | |
777 | *name = strdup(f->name); | |
778 | *id = f->parent_id; | |
779 | } | |
780 | } | |
781 | ||
782 | ||
783 | /** | |
784 | * Find the folder id given the folder's name and parent id. | |
785 | * | |
786 | * @param folders the folders list for the device | |
787 | * @param parent the folder's parent's id | |
788 | * @param name the name of the folder | |
789 | * @return the folder_id or 0 on failure | |
790 | * @see discover_filepath_from_id() | |
791 | */ | |
792 | static uint32_t find_folder_id(LIBMTP_folder_t* folders, uint32_t parent, char* name) { | |
793 | ||
794 | if(folders == NULL) | |
795 | return 0; | |
796 | ||
797 | // found it! | |
798 | else if( (folders->parent_id == parent) && | |
799 | (strcmp(folders->name, name) == 0) ) | |
800 | return folders->folder_id; | |
801 | ||
802 | // no luck so far, search both siblings and children | |
803 | else { | |
804 | uint32_t id = 0; | |
805 | ||
806 | if(folders->sibling != NULL) | |
807 | id = find_folder_id(folders->sibling, parent, name); | |
808 | if( (id == 0) && (folders->child != NULL) ) | |
809 | id = find_folder_id(folders->child, parent, name); | |
810 | ||
811 | return id; | |
812 | } | |
813 | } | |
814 | ||
815 | ||
816 | /** | |
817 | * Append a string to a linked-list of strings. | |
818 | * | |
819 | * @param t the list-of-strings, returns with the added string | |
820 | * @param s the string to append | |
821 | * @see spl_text_t_from_tracks() | |
822 | */ | |
823 | static void append_text_t(text_t** t, char* s) | |
824 | { | |
825 | if(*t == NULL) { | |
826 | *t = malloc(sizeof(text_t)); | |
827 | } | |
828 | else { | |
829 | (*t)->next = malloc(sizeof(text_t)); | |
830 | (*t) = (*t)->next; | |
831 | } | |
832 | (*t)->text = strdup(s); | |
833 | } |
0 | /* | |
1 | * \file playlist-spl.h | |
2 | * Playlist to .spl conversion functions. | |
3 | * | |
4 | * Copyright (C) 2008 Alistair Boyle <alistair.js.boyle@gmail.com> | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, write to the | |
18 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
19 | * Boston, MA 02111-1307, USA. | |
20 | */ | |
21 | ||
22 | #ifndef __MTP__PLAYLIST_SPL__H | |
23 | #define __MTP__PLAYLIST_SPL__H | |
24 | ||
25 | int is_spl_playlist(PTPObjectInfo *oi); | |
26 | ||
27 | void spl_to_playlist_t(LIBMTP_mtpdevice_t* device, PTPObjectInfo *oi, | |
28 | const uint32_t id, LIBMTP_playlist_t * const pl); | |
29 | int playlist_t_to_spl(LIBMTP_mtpdevice_t *device, | |
30 | LIBMTP_playlist_t * const metadata); | |
31 | int update_spl_playlist(LIBMTP_mtpdevice_t *device, | |
32 | LIBMTP_playlist_t const * const metadata); | |
33 | ||
34 | #endif //__MTP__PLAYLIST_SPL__H |
648 | 648 | value->str = ptp_unpack_string(params,data,*offset,&len); |
649 | 649 | *offset += len*2+1; |
650 | 650 | if (!value->str) |
651 | return 0; | |
651 | return 1; | |
652 | 652 | break; |
653 | 653 | } |
654 | 654 | default: |
673 | 673 | dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]); |
674 | 674 | dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]); |
675 | 675 | dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]); |
676 | dpd->FormFlag=PTP_DPFF_None; | |
676 | 677 | |
677 | 678 | offset = PTP_dpd_FactoryDefaultValue; |
678 | 679 | ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType); |
679 | 680 | if (!ret) goto outofmemory; |
681 | if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen)) | |
682 | return 1; | |
680 | 683 | ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType); |
681 | 684 | if (!ret) goto outofmemory; |
682 | 685 | |
685 | 688 | values). In both cases Form Flag should be set to 0x00 and FORM is |
686 | 689 | not present. */ |
687 | 690 | |
688 | dpd->FormFlag=PTP_DPFF_None; | |
689 | 691 | if (offset==PTP_dpd_FactoryDefaultValue) |
690 | 692 | return 1; |
691 | 693 |
41 | 41 | */ |
42 | 42 | #define STRING_BUFFER_LENGTH 1024 |
43 | 43 | |
44 | /** | |
45 | * Gets the length (in characters, not bytes) of a unicode | |
44 | /** | |
45 | * Gets the length (in characters, not bytes) of a unicode | |
46 | 46 | * UCS-2 string, eg a string which physically is 0x00 0x41 0x00 0x00 |
47 | 47 | * will return a value of 1. |
48 | 48 | * |
49 | 49 | * @param unicstr a UCS-2 Unicode string |
50 | * @return the length of the string, in number of characters. If you | |
50 | * @return the length of the string, in number of characters. If you | |
51 | 51 | * want to know the length in bytes, multiply this by two and |
52 | 52 | * add two (for zero terminator). |
53 | 53 | */ |
54 | 54 | int ucs2_strlen(uint16_t const * const unicstr) |
55 | 55 | { |
56 | 56 | int length; |
57 | ||
57 | ||
58 | 58 | /* Unicode strings are terminated with 2 * 0x00 */ |
59 | 59 | for(length = 0; unicstr[length] != 0x0000U; length ++); |
60 | 60 | return length; |
78 | 78 | size_t nconv; |
79 | 79 | size_t convlen = (ucs2_strlen(unicstr)+1) * sizeof(uint16_t); // UCS-2 is 16 bit wide, include terminator |
80 | 80 | size_t convmax = STRING_BUFFER_LENGTH*3; |
81 | ||
81 | ||
82 | 82 | loclstr[0]='\0'; |
83 | 83 | /* Do the conversion. */ |
84 | 84 | nconv = iconv(params->cd_ucs2_to_locale, &stringp, &convlen, &locp, &convmax); |
92 | 92 | return strdup(loclstr+3); |
93 | 93 | } |
94 | 94 | return strdup(loclstr); |
95 | } | |
96 | ||
97 | /** | |
98 | * Converts a UTF-8 string to a big-endian UTF-16 2-byte string | |
99 | * Actually just a UCS-2 internal conversion. | |
100 | * | |
101 | * @param device a pointer to the current device. | |
102 | * @param localstr the UTF-8 unicode string to convert | |
103 | * @return a UTF-16 string. | |
104 | */ | |
105 | uint16_t *utf8_to_utf16(LIBMTP_mtpdevice_t *device, const char *localstr) | |
106 | { | |
107 | PTPParams *params = (PTPParams *) device->params; | |
108 | char *stringp = (char *) localstr; // cast away "const" | |
109 | char unicstr[(STRING_BUFFER_LENGTH+1)*2]; // UCS2 encoding is 2 bytes per UTF-8 char. | |
110 | char *unip = unicstr; | |
111 | size_t nconv = 0; | |
112 | size_t convlen = strlen(localstr)+1; // utf8 bytes, include terminator | |
113 | size_t convmax = STRING_BUFFER_LENGTH*2; | |
114 | ||
115 | unicstr[0]='\0'; | |
116 | unicstr[1]='\0'; | |
117 | ||
118 | /* Do the conversion. */ | |
119 | nconv = iconv(params->cd_locale_to_ucs2, &stringp, &convlen, &unip, &convmax); | |
120 | ||
121 | if (nconv == (size_t) -1) { | |
122 | // Return partial string anyway. | |
123 | unip[0] = '\0'; | |
124 | unip[1] = '\0'; | |
125 | } | |
126 | // make sure the string is null terminated | |
127 | unicstr[STRING_BUFFER_LENGTH*2] = '\0'; | |
128 | unicstr[STRING_BUFFER_LENGTH*2+1] = '\0'; | |
129 | ||
130 | // allocate the string to be returned | |
131 | // Note: can't use strdup since every other byte is a null byte | |
132 | int ret_len = ucs2_strlen((uint16_t*)unicstr)*sizeof(uint16_t)+2; | |
133 | uint16_t* ret = malloc(ret_len); | |
134 | memcpy(ret,unicstr,(size_t)ret_len); | |
135 | return ret; | |
95 | 136 | } |
96 | 137 | |
97 | 138 | /** |