Codebase list libmtp / ebd60d4
Import Upstream version 0.3.1 Dylan Aïssi 5 years ago
28 changed file(s) with 1391 addition(s) and 213 deletion(s). Raw diff Collapse all Expand all
2929 Tero Saarni <tero.saarni@gmail.com>
3030 Jeff Mitchell <kde-dev@emailgoeshere.com>
3131 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
054 2008-06-24 Linus Walleij <triad@df.lth.se>
155
256 * TODO: updates.
6868 For information about the Media Transfer Protocol, see:
6969 http://en.wikipedia.org/wiki/Media_Transfer_Protocol
7070
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
7178
7279 Contributing
7380 ------------
381388 the quirks, see:
382389 http://www2.one-eyed-alien.net/~mdharm/linux-usb/target_offenses.txt
383390
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
384413 * The Zen Vision:M (possibly more Creative Zens) has a firmware bug
385414 that makes it drop the last two characters off a playlist name.
386415 It is fixed in later firmware.
451480 usb 4-5: configuration #1 chosen from 1 choice
452481 usb 4-5: can't set config #1, error -110
453482
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.
454485
455486 Lost symbols
456487 ------------
3434
3535 /* Define to 1 if you have the <limits.h> header file. */
3636 #undef HAVE_LIMITS_H
37
38 /* Define to 1 if you have the <locale.h> header file. */
39 #undef HAVE_LOCALE_H
3740
3841 /* Define to 1 if your system has a GNU libc compatible `malloc' function, and
3942 to 0 otherwise. */
00 #! /bin/sh
11 # 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.
33 #
44 # Report bugs to <libmtp-discuss@lists.sourceforge.net>.
55 #
727727 # Identity of this package.
728728 PACKAGE_NAME='libmtp'
729729 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'
732732 PACKAGE_BUGREPORT='libmtp-discuss@lists.sourceforge.net'
733733
734734 ac_unique_file="src/libmtp.c"
14001400 # Omit some internal or obsolete options to make the list less imposing.
14011401 # This message is too long to be a string in the A/UX 3.1 sh.
14021402 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.
14041404
14051405 Usage: $0 [OPTION]... [VAR=VALUE]...
14061406
14701470
14711471 if test -n "$ac_init_help"; then
14721472 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:";;
14741474 esac
14751475 cat <<\_ACEOF
14761476
15721572 test -n "$ac_init_help" && exit $ac_status
15731573 if $ac_init_version; then
15741574 cat <<\_ACEOF
1575 libmtp configure 0.3.0
1575 libmtp configure 0.3.1
15761576 generated by GNU Autoconf 2.61
15771577
15781578 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
15861586 This file contains any messages produced by compilers while
15871587 running configure, to aid debugging if configure makes a mistake.
15881588
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
15901590 generated by GNU Autoconf 2.61. Invocation command line was
15911591
15921592 $ $0 $@
22762276
22772277 # Define the identity of the package.
22782278 PACKAGE='libmtp'
2279 VERSION='0.3.0'
2279 VERSION='0.3.1'
22802280
22812281
22822282 cat >>confdefs.h <<_ACEOF
2014120141
2014220142
2014320143
20144
2014420145 for ac_header in ctype.h errno.h fcntl.h getopt.h libgen.h \
2014520146 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
2014720148 do
2014820149 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
2014920150 if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then
2285722858 # report actual input values of CONFIG_FILES etc. instead of their
2285822859 # values after options handling.
2285922860 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
2286122862 generated by GNU Autoconf 2.61. Invocation command line was
2286222863
2286322864 CONFIG_FILES = $CONFIG_FILES
2291022911 _ACEOF
2291122912 cat >>$CONFIG_STATUS <<_ACEOF
2291222913 ac_cs_version="\\
22913 libmtp config.status 0.3.0
22914 libmtp config.status 0.3.1
2291422915 configured by $0, generated by GNU Autoconf 2.61,
2291522916 with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
2291622917
00 # Process this file with autoconf to produce a configure script.
11 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])
33 AM_INIT_AUTOMAKE([foreign])
44 AC_CONFIG_SRCDIR([src/libmtp.c])
55 AM_CONFIG_HEADER(config.h)
6060 # zlib.h the day we need to decompress firmware
6161 AC_CHECK_HEADERS([ctype.h errno.h fcntl.h getopt.h libgen.h \
6262 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])
6464 AC_CHECK_HEADER([usb.h],,
6565 AC_MSG_ERROR([I can't find the libusb header file on your system.
6666 You may need to set the CPPFLAGS environment variable to include
33 thumb reset
44
55 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
2223
2324 AM_CPPFLAGS=-I$(top_builddir)/src
2425 LDADD=../src/libmtp.la
5050 am__installdirs = "$(DESTDIR)$(bindir)"
5151 binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
5252 PROGRAMS = $(bin_PROGRAMS)
53 am_albumart_OBJECTS = albumart.$(OBJEXT)
53 am_albumart_OBJECTS = albumart.$(OBJEXT) util.$(OBJEXT)
5454 albumart_OBJECTS = $(am_albumart_OBJECTS)
5555 albumart_LDADD = $(LDADD)
5656 albumart_DEPENDENCIES = ../src/libmtp.la
57 am_albums_OBJECTS = albums.$(OBJEXT)
57 am_albums_OBJECTS = albums.$(OBJEXT) util.$(OBJEXT)
5858 albums_OBJECTS = $(am_albums_OBJECTS)
5959 albums_LDADD = $(LDADD)
6060 albums_DEPENDENCIES = ../src/libmtp.la
6161 am_connect_OBJECTS = connect.$(OBJEXT) delfile.$(OBJEXT) \
6262 getfile.$(OBJEXT) newfolder.$(OBJEXT) sendfile.$(OBJEXT) \
63 sendtr.$(OBJEXT) pathutils.$(OBJEXT)
63 sendtr.$(OBJEXT) pathutils.$(OBJEXT) util.$(OBJEXT)
6464 connect_OBJECTS = $(am_connect_OBJECTS)
6565 connect_LDADD = $(LDADD)
6666 connect_DEPENDENCIES = ../src/libmtp.la
67 am_detect_OBJECTS = detect.$(OBJEXT)
67 am_detect_OBJECTS = detect.$(OBJEXT) util.$(OBJEXT)
6868 detect_OBJECTS = $(am_detect_OBJECTS)
6969 detect_LDADD = $(LDADD)
7070 detect_DEPENDENCIES = ../src/libmtp.la
71 am_emptyfolders_OBJECTS = emptyfolders.$(OBJEXT)
71 am_emptyfolders_OBJECTS = emptyfolders.$(OBJEXT) util.$(OBJEXT)
7272 emptyfolders_OBJECTS = $(am_emptyfolders_OBJECTS)
7373 emptyfolders_LDADD = $(LDADD)
7474 emptyfolders_DEPENDENCIES = ../src/libmtp.la
75 am_files_OBJECTS = files.$(OBJEXT)
75 am_files_OBJECTS = files.$(OBJEXT) util.$(OBJEXT)
7676 files_OBJECTS = $(am_files_OBJECTS)
7777 files_LDADD = $(LDADD)
7878 files_DEPENDENCIES = ../src/libmtp.la
79 am_folders_OBJECTS = folders.$(OBJEXT)
79 am_folders_OBJECTS = folders.$(OBJEXT) util.$(OBJEXT)
8080 folders_OBJECTS = $(am_folders_OBJECTS)
8181 folders_LDADD = $(LDADD)
8282 folders_DEPENDENCIES = ../src/libmtp.la
83 am_format_OBJECTS = format.$(OBJEXT)
83 am_format_OBJECTS = format.$(OBJEXT) util.$(OBJEXT)
8484 format_OBJECTS = $(am_format_OBJECTS)
8585 format_LDADD = $(LDADD)
8686 format_DEPENDENCIES = ../src/libmtp.la
87 am_getplaylist_OBJECTS = getplaylist.$(OBJEXT)
87 am_getplaylist_OBJECTS = getplaylist.$(OBJEXT) util.$(OBJEXT)
8888 getplaylist_OBJECTS = $(am_getplaylist_OBJECTS)
8989 getplaylist_LDADD = $(LDADD)
9090 getplaylist_DEPENDENCIES = ../src/libmtp.la
91 am_hotplug_OBJECTS = hotplug.$(OBJEXT)
91 am_hotplug_OBJECTS = hotplug.$(OBJEXT) util.$(OBJEXT)
9292 hotplug_OBJECTS = $(am_hotplug_OBJECTS)
9393 hotplug_LDADD = $(LDADD)
9494 hotplug_DEPENDENCIES = ../src/libmtp.la
95 am_newplaylist_OBJECTS = newplaylist.$(OBJEXT)
95 am_newplaylist_OBJECTS = newplaylist.$(OBJEXT) util.$(OBJEXT)
9696 newplaylist_OBJECTS = $(am_newplaylist_OBJECTS)
9797 newplaylist_LDADD = $(LDADD)
9898 newplaylist_DEPENDENCIES = ../src/libmtp.la
99 am_playlists_OBJECTS = playlists.$(OBJEXT)
99 am_playlists_OBJECTS = playlists.$(OBJEXT) util.$(OBJEXT)
100100 playlists_OBJECTS = $(am_playlists_OBJECTS)
101101 playlists_LDADD = $(LDADD)
102102 playlists_DEPENDENCIES = ../src/libmtp.la
103 am_reset_OBJECTS = reset.$(OBJEXT)
103 am_reset_OBJECTS = reset.$(OBJEXT) util.$(OBJEXT)
104104 reset_OBJECTS = $(am_reset_OBJECTS)
105105 reset_LDADD = $(LDADD)
106106 reset_DEPENDENCIES = ../src/libmtp.la
107 am_thumb_OBJECTS = thumb.$(OBJEXT)
107 am_thumb_OBJECTS = thumb.$(OBJEXT) util.$(OBJEXT)
108108 thumb_OBJECTS = $(am_thumb_OBJECTS)
109109 thumb_LDADD = $(LDADD)
110110 thumb_DEPENDENCIES = ../src/libmtp.la
111 am_tracks_OBJECTS = tracks.$(OBJEXT)
111 am_tracks_OBJECTS = tracks.$(OBJEXT) util.$(OBJEXT)
112112 tracks_OBJECTS = $(am_tracks_OBJECTS)
113113 tracks_LDADD = $(LDADD)
114114 tracks_DEPENDENCIES = ../src/libmtp.la
115 am_trexist_OBJECTS = trexist.$(OBJEXT)
115 am_trexist_OBJECTS = trexist.$(OBJEXT) util.$(OBJEXT)
116116 trexist_OBJECTS = $(am_trexist_OBJECTS)
117117 trexist_LDADD = $(LDADD)
118118 trexist_DEPENDENCIES = ../src/libmtp.la
256256 top_builddir = @top_builddir@
257257 top_srcdir = @top_srcdir@
258258 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
276277 AM_CPPFLAGS = -I$(top_builddir)/src
277278 LDADD = ../src/libmtp.la
278279 EXTRA_DIST = evolution-sync.sh
414415 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/thumb.Po@am__quote@
415416 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tracks.Po@am__quote@
416417 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/trexist.Po@am__quote@
418 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/util.Po@am__quote@
417419
418420 .c.o:
419421 @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
2121 */
2222 #include <libgen.h>
2323 #include <getopt.h>
24 #include <string.h>
2425 #include "common.h"
25 #include "string.h"
26 #include "util.h"
2627 #include "pathutils.h"
27 #ifdef HAVE_LANGINFO_H
28 #include <langinfo.h>
29 #endif
3028
3129 LIBMTP_folder_t *folders;
3230 LIBMTP_file_t *files;
7472 printf(" --newfolder [foldername]\n");
7573 }
7674
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 }
10175
10276 int main (int argc, char **argv)
10377 {
2020 * Boston, MA 02111-1307, USA.
2121 */
2222 #include "common.h"
23 #include "util.h"
2324 #include <unistd.h>
2425 #include <stdlib.h>
2526 #include <stdio.h>
2929 #define _LARGEFILE64_SOURCE
3030
3131 #include "common.h"
32 #include "util.h"
3233 #include <string.h>
3334 #include <libgen.h>
3435 #include <sys/stat.h>
5556 fprintf(stderr, " -l <album> -c <codec> -g <genre> -n <track number> -y <year>\n");
5657 fprintf(stderr, " -d <duration in seconds> <local path> <remote path>\n");
5758 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 }
8359 }
8460
8561 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
66
77 Name: libmtp
88 Description: libmtp is a library for accessing Media Transfer Protocol devices
9 Version: 0.3.0
9 Version: 0.3.1
1010 Requires: libusb
1111 Conflicts:
1212 Libs: -L${libdir} -lmtp
00 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 \
22 libusb-glue.c libusb-glue.h \
33 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
55 include_HEADERS=libmtp.h
66 EXTRA_DIST=libmtp.h.in libmtp.sym ptp-pack.c
77
2929 # ---------------------------------------------------------------------------
3030 CURRENT=8
3131 AGE=0
32 REVISION=0
32 REVISION=1
3333 SOVERSION=$(CURRENT):$(REVISION):$(AGE)
3434
3535 if COMPILE_MINGW32
5454 libLTLIBRARIES_INSTALL = $(INSTALL)
5555 LTLIBRARIES = $(lib_LTLIBRARIES)
5656 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
5959 libmtp_la_OBJECTS = $(am_libmtp_la_OBJECTS)
6060 libmtp_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
6161 $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
193193 top_builddir = @top_builddir@
194194 top_srcdir = @top_srcdir@
195195 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 \
197197 libusb-glue.c libusb-glue.h \
198198 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
200200
201201 include_HEADERS = libmtp.h
202202 EXTRA_DIST = libmtp.h.in libmtp.sym ptp-pack.c
225225 # ---------------------------------------------------------------------------
226226 CURRENT = 8
227227 AGE = 0
228 REVISION = 0
228 REVISION = 1
229229 SOVERSION = $(CURRENT):$(REVISION):$(AGE)
230230 @COMPILE_MINGW32_TRUE@noinst_DATA = libmtp.lib
231231 @COMPILE_MINGW32_TRUE@W32LF = -export-dynamic -no-undefined -export-symbols libmtp.sym
303303
304304 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmtp.Plo@am__quote@
305305 @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@
306307 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ptp.Plo@am__quote@
307308 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unicode.Plo@am__quote@
308309 @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
150 RELATION TO LIBPTP2
161 -------------------
172
4040 * DEVICE_FLAG_BROKEN_MTPGETOBJECTPROPLIST which only signify
4141 * that it's broken when getting metadata for a SINGLE object.
4242 * 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.
4451 */
4552 #define DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL 0x00000001
4653 /**
8895 * The error has only been seen on iriver devices. Turning this
8996 * flag on won't hurt anything, just that the check against
9097 * 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.
91102 */
92103 #define DEVICE_FLAG_IRIVER_OGG_ALZHEIMER 0x00000010
93104 /**
135146 * and a need to report the Ogg support (the device itself does
136147 * not properly claim to support it) and need to set filetype
137148 * 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.
139152 */
140153 #define DEVICE_FLAG_OGG_IS_UNKNOWN 0x00000200
141154 /**
152165 * This flag provides that extra massage.
153166 */
154167 #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
4141 #include "ptp.h"
4242 #include "libusb-glue.h"
4343 #include "device-flags.h"
44 #include "playlist-spl.h"
4445
4546 #include <string.h>
4647 #include <sys/types.h>
4748 #include <sys/stat.h>
4849 #include <fcntl.h>
4950 #include <time.h>
51 #include <errno.h>
5052 #ifdef _MSC_VER // For MSVC++
5153 #define USE_WINDOWS_IO_H
5254 #include <io.h>
25502552 * do not put a reference to any <code>char *</code> field. instead
25512553 * <code>strncpy()</code> it!
25522554 *
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.
25542556 * @param sortby an integer that determines the sorting of the storage list.
25552557 * Valid sort methods are defined in libmtp.h with beginning with
25562558 * LIBMTP_STORAGE_SORTBY_. 0 or LIBMTP_STORAGE_SORTBY_NOTSORTED to not
27082710
27092711 /**
27102712 * 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:
27122715 *
27132716 * <pre>
27142717 * LIBMTP_file_t *filelist;
27242727 * }
27252728 * </pre>
27262729 *
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 *
27272737 * @param device a pointer to the device to get the file listing for.
27282738 * @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.
27312741 * @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.
27352745 * @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.
27402750 * @see LIBMTP_Get_Filemetadata()
27412751 */
27422752 LIBMTP_file_t *LIBMTP_Get_Filelisting_With_Callback(LIBMTP_mtpdevice_t *device,
33573367 }
33583368
33593369 /**
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:
33623373 *
33633374 * <pre>
33643375 * LIBMTP_track_t *tracklist;
33743385 * }
33753386 * </pre>
33763387 *
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 *
33773395 * @param device a pointer to the device to get the track listing for.
33783396 * @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.
33813399 * @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.
33853403 * @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.
33903408 * @see LIBMTP_Get_Trackmetadata()
33913409 */
33923410 LIBMTP_track_t *LIBMTP_Get_Tracklisting_With_Callback(LIBMTP_mtpdevice_t *device,
51915209 */
51925210 LIBMTP_playlist_t *LIBMTP_Get_Playlist_List(LIBMTP_mtpdevice_t *device)
51935211 {
5212 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5213 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
51945214 PTPParams *params = (PTPParams *) device->params;
51955215 LIBMTP_playlist_t *retlists = NULL;
51965216 LIBMTP_playlist_t *curlist = NULL;
52095229 oi = &params->objectinfo[i];
52105230
52115231 // 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 ) {
52135241 continue;
52145242 }
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 }
52315260 }
52325261
52335262 // Add playlist to a list that will be returned afterwards.
52545283 */
52555284 LIBMTP_playlist_t *LIBMTP_Get_Playlist(LIBMTP_mtpdevice_t *device, uint32_t const plid)
52565285 {
5286 PTP_USB *ptp_usb = (PTP_USB*) device->usbinfo;
5287 const int REQ_SPL = FLAG_PLAYLIST_SPL(ptp_usb);
52575288 PTPParams *params = (PTPParams *) device->params;
52585289 uint32_t i;
52595290
52735304
52745305 oi = &params->objectinfo[i];
52755306
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
52765316 // Ignore stuff that isn't playlists
5277 if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
5317 else if ( oi->ObjectFormat != PTP_OFC_MTP_AbstractAudioVideoPlaylist ) {
52785318 return NULL;
52795319 }
52805320
58465886 }
58475887 metadata->parent_id = localph;
58485888
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
58495894 // Just create a new abstract audio/video playlist...
58505895 return create_new_abstract_list(device,
58515896 metadata->name,
58785923 int LIBMTP_Update_Playlist(LIBMTP_mtpdevice_t *device,
58795924 LIBMTP_playlist_t const * const metadata)
58805925 {
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
58815933 return update_abstract_list(device,
58825934 metadata->name,
58835935 NULL,
2828 #ifndef LIBMTP_H_INCLUSION_GUARD
2929 #define LIBMTP_H_INCLUSION_GUARD
3030
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"
3333
3434 /* This handles MSVC pecularities */
3535 #ifdef _MSC_VER
11321132 }
11331133 }
11341134 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 );
11351140 /* stuff data directly to passed data handler */
11361141 while (1) {
11371142 unsigned long readdata;
1138 int xret;
1143 uint16_t xret;
11391144
11401145 xret = ptp_read_func(
11411146 PTP_USB_BULK_HS_MAX_PACKET_LEN_READ,
11451150 0
11461151 );
11471152 if (xret != PTP_RC_OK)
1148 return ret;
1153 return xret;
11491154 if (readdata < PTP_USB_BULK_HS_MAX_PACKET_LEN_READ)
11501155 break;
11511156 }
9090 ((a)->rawdevice.device_entry.device_flags & DEVICE_FLAG_BROKEN_SET_SAMPLE_DIMENSIONS)
9191 #define FLAG_ALWAYS_PROBE_DESCRIPTOR(a) \
9292 ((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))
9399
94100 /* connect_first_device return codes */
95101 #define PTP_CD_RC_CONNECTED 0
2424 * This file is supposed to be included within a struct from both libmtp
2525 * and libgphoto2.
2626 */
27
2827 /*
2928 * MTP device list, trying real bad to get all devices into
3029 * this list by stealing from everyone I know.
6665 { "Creative", 0x041e, "ZEN", 0x4157, DEVICE_FLAG_IGNORE_HEADER_ERRORS | DEVICE_FLAG_BROKEN_SET_SAMPLE_DIMENSIONS },
6766 // Reported by Ringofan <mcroman@users.sourceforge.net>
6867 { "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 },
6970
7071 /*
7172 * Samsung
7273 * We suspect that more of these are dual mode.
7374 * 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.
7477 * YP-NEU, YP-NDU, YP-20, YP-800, YP-MF Series, YP-100, YP-30
7578 * YP-700 and YP-90 are NOT MTP, but use a Samsung custom protocol.
7679 */
7780 // From anonymous SourceForge user, not verified
7881 { "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 },
7986 // 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 },
8188 // Contributed by aronvanammers on SourceForge
8289 { "Samsung", 0x04e8, "YH-925GS", 0x5024, DEVICE_FLAG_NONE },
8390 // From libgphoto2, according to tests by Stephan Fabel it cannot
8491 // get all objects with the getobjectproplist command..
8592 { "Samsung", 0x04e8, "YH-820", 0x502e, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL },
8693 // 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 },
8896 // Contributed by anonymous person on SourceForge
8997 { "Samsung", 0x04e8, "YH-J70J", 0x5033, DEVICE_FLAG_UNLOAD_DRIVER },
9098 // 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 },
92101 // 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 },
94104 // Contributed by anonymous person on SourceForge
95105 { "Samsung", 0x04e8, "YP-T7J", 0x5047, DEVICE_FLAG_NONE },
96106 // Reported by cstrickler@gmail.com
98108 // Reported by Andrew Benson
99109 { "Samsung", 0x04e8, "YP-F2J", 0x5057, DEVICE_FLAG_UNLOAD_DRIVER },
100110 // 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 },
102113 // From dev.local@gmail.com - 0x4e8/0x507c is the UMS mode, apparently
103114 // do not add that device.
104115 // 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 },
106118 // Reported by Matthew Wilcox <matthew@wil.cx>
107119 // 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 },
109122 // 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 },
111125 // 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 },
113128 // 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 },
115131 // From Wim Verwimp <wimverwimp@gmail.com>
116132 // 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 },
118138 // From a rouge .INF file,
119139 // this device ID seems to have been recycled for:
120140 // the Samsung SGH-A707 Cingular cellphone
312332 DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS |
313333 DEVICE_FLAG_IRIVER_OGG_ALZHEIMER },
314334 // 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.
315337 { "iRiver", 0x4102, "E100", 0x1141,
316338 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 },
318345 // Reported by Scott Call
346 // Assume this actually supports OGG though it reports it doesn't.
319347 { "iRiver", 0x4102, "H10 20GB", 0x2101,
320348 DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS |
321 DEVICE_FLAG_IRIVER_OGG_ALZHEIMER },
349 DEVICE_FLAG_OGG_IS_UNKNOWN },
322350 { "iRiver", 0x4102, "H10", 0x2102,
323351 DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST | DEVICE_FLAG_NO_ZERO_READS |
324 DEVICE_FLAG_IRIVER_OGG_ALZHEIMER },
352 DEVICE_FLAG_OGG_IS_UNKNOWN },
325353
326354
327355 /*
348376 { "Toshiba", 0x0930, "Gigabeat MEU202", 0x0018, DEVICE_FLAG_NO_RELEASE_INTERFACE },
349377 // Reported by Rolf <japan (at) dl3lar.de>
350378 { "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 },
351383
352384
353385 /*
380412 * interface.
381413 */
382414 { "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 },
383419
384420 /*
385421 * Microsoft
386422 */
387 // Reported by Farooq Zaman
423 // Reported by Farooq Zaman (used for all Zunes)
388424 { "Microsoft", 0x045e, "Zune", 0x0710, DEVICE_FLAG_NONE },
389425
390426 /*
394430 // Reported by Chris Bagwell <chris@cnpbagwell.com>
395431 // Apparently this comes with a firmware upgrade to the original
396432 // Stiletto as well.
397 { "Sirius", 0x18f6, "Stiletto 2", 0x0110, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST },
433 { "Sirius", 0x18f6, "Stiletto 2", 0x0110, DEVICE_FLAG_BROKEN_MTPGETOBJPROPLIST_ALL },
398434
399435 /*
400436 * Canon
417453 { "Nokia", 0x0421, "3110c Mobile Phone", 0x005f, DEVICE_FLAG_NONE },
418454 // From: Vasily <spc-@users.sourceforge.net>
419455 { "Nokia", 0x0421, "3109c Mobile Phone", 0x0065, DEVICE_FLAG_NONE },
456 // From: <rawc@users.sourceforge.net>
457 { "Nokia", 0x0421, "5310 XpressMusic", 0x006c, DEVICE_FLAG_NONE },
420458 // From: robin (AT) headbank D0Tco DOTuk
421459 { "Nokia", 0x0421, "N95 Mobile Phone 8GB", 0x006e, DEVICE_FLAG_NONE },
460 // From: danielw
461 { "Nokia", 0x0421, "E71", 0x00e4, DEVICE_FLAG_NONE },
422462 // From: Christian Rusa <kristous@users.sourceforge.net>
423463 { "Nokia", 0x0421, "5700 XpressMusic Mobile Phone", 0x04b4, DEVICE_FLAG_NONE },
424464 // From: Mitchell Hicks <mitchix@yahoo.com>
431471 { "Nokia", 0x0421, "N95 Mobile Phone", 0x04ef, DEVICE_FLAG_NONE },
432472 // From: Pat Nicholls <pat@patandannie.co.uk>
433473 { "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 },
434477
435478
436479 /*
466509 { "Palm Handspring", 0x1703, "Pocket Tunes 4", 0x0002, DEVICE_FLAG_NONE },
467510
468511 /*
469 * TrekStor devices
512 * TrekStor and Medion devices
470513 * Their datasheet claims their devices are dualmode so probably needs to
471514 * unload the attached drivers here.
472515 */
473516 // Reported by Stefan Voss <svoss@web.de>
474517 // This is a Sigmatel SoC with a hard disk.
475518 { "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 },
477525 // Reported by Cristi Magherusan <majeru@gentoo.ro>
478526 { "TrekStor", 0x0402, "i.Beat Sweez FM", 0x0611,
479 DEVICE_FLAG_UNLOAD_DRIVER },
527 DEVICE_FLAG_UNLOAD_DRIVER },
480528
481529 /*
482530 * Disney/Tevion (have had no reports of these actually working.)
513561 * LG Electronics
514562 */
515563 // 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 },
517568
518569 /*
519570 * Sony
543594 { "SonyEricsson", 0x0fce, "W910", 0x0076, DEVICE_FLAG_NONE },
544595 // Reported by Zack <zackdvd@users.sourceforge.net>
545596 { "SonyEricsson", 0x0fce, "W890i", 0x00b3, DEVICE_FLAG_NONE },
597 // Reported by robert dot ahlskog at gmail
598 { "SonyEricsson", 0x0fce, "W760i", 0x00c6, DEVICE_FLAG_NONE },
546599 // Reported by Linus Åkesson <linusakesson@users.sourceforge.net>
547600 { "SonyEricsson", 0x0fce, "C902", 0x00d4, DEVICE_FLAG_NONE },
601 // Reported by an anonymous SourceForge user
602 { "SonyEricsson", 0x0fce, "C702", 0x00d9, DEVICE_FLAG_NONE },
548603
549604 /*
550605 * 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
648648 value->str = ptp_unpack_string(params,data,*offset,&len);
649649 *offset += len*2+1;
650650 if (!value->str)
651 return 0;
651 return 1;
652652 break;
653653 }
654654 default:
673673 dpd->DevicePropertyCode=dtoh16a(&data[PTP_dpd_DevicePropertyCode]);
674674 dpd->DataType=dtoh16a(&data[PTP_dpd_DataType]);
675675 dpd->GetSet=dtoh8a(&data[PTP_dpd_GetSet]);
676 dpd->FormFlag=PTP_DPFF_None;
676677
677678 offset = PTP_dpd_FactoryDefaultValue;
678679 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->FactoryDefaultValue, dpd->DataType);
679680 if (!ret) goto outofmemory;
681 if ((dpd->DataType == PTP_DTC_STR) && (offset == dpdlen))
682 return 1;
680683 ret = ptp_unpack_DPV (params, data, &offset, dpdlen, &dpd->CurrentValue, dpd->DataType);
681684 if (!ret) goto outofmemory;
682685
685688 values). In both cases Form Flag should be set to 0x00 and FORM is
686689 not present. */
687690
688 dpd->FormFlag=PTP_DPFF_None;
689691 if (offset==PTP_dpd_FactoryDefaultValue)
690692 return 1;
691693
4141 */
4242 #define STRING_BUFFER_LENGTH 1024
4343
44 /**
45 * Gets the length (in characters, not bytes) of a unicode
44 /**
45 * Gets the length (in characters, not bytes) of a unicode
4646 * UCS-2 string, eg a string which physically is 0x00 0x41 0x00 0x00
4747 * will return a value of 1.
4848 *
4949 * @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
5151 * want to know the length in bytes, multiply this by two and
5252 * add two (for zero terminator).
5353 */
5454 int ucs2_strlen(uint16_t const * const unicstr)
5555 {
5656 int length;
57
57
5858 /* Unicode strings are terminated with 2 * 0x00 */
5959 for(length = 0; unicstr[length] != 0x0000U; length ++);
6060 return length;
7878 size_t nconv;
7979 size_t convlen = (ucs2_strlen(unicstr)+1) * sizeof(uint16_t); // UCS-2 is 16 bit wide, include terminator
8080 size_t convmax = STRING_BUFFER_LENGTH*3;
81
81
8282 loclstr[0]='\0';
8383 /* Do the conversion. */
8484 nconv = iconv(params->cd_ucs2_to_locale, &stringp, &convlen, &locp, &convmax);
9292 return strdup(loclstr+3);
9393 }
9494 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;
95136 }
96137
97138 /**
3535
3636 int ucs2_strlen(uint16_t const * const);
3737 char *utf16_to_utf8(LIBMTP_mtpdevice_t*,const uint16_t*);
38 uint16_t *utf8_to_utf16(LIBMTP_mtpdevice_t*, const char*);
3839 void strip_7bit_from_utf8(char *str);
3940
4041 #endif /* __MTP__UNICODE__H */