FU Logo
  • Startseite
  • Kontakt
  • Impressum
  • Home
  • Listenauswahl
  • Anleitungen

Re: [linux-minidisc] netmd/netmdcli: download support for any .wav file containing pcm audio

<-- thread -->
<-- date -->
  • From: Thomas Arp <manner.moe@gmx.de>
  • Date: Sun, 12 Jan 2014 20:16:34 +0100
  • Cc: "linux-minidisc@lists.fu-berlin.de" <linux-minidisc@lists.fu-berlin.de>
  • Subject: Re: [linux-minidisc] netmd/netmdcli: download support for any .wav file containing pcm audio

Hi,
i updated my patches for netmd download support now.
It is splitted into 3 parts and can be applied to the current master repository one by one:

part 1: modify libnetmd to add download support for any wave audio file by analyzing the RIFF/WAVE header and fmt chunk.

As some functions of libnetmd are modified in part 1 regarding the parameter list, compilation of netmdcli will fail.
part 2: modify netmdcli to use the new/changed functions of libnetmd

part 3: add netmd download support in the gui application


Thomas
>From bc5dd5d8538a4c9d2f7aae3146cb1caf0b76c8b3 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sun, 12 Jan 2014 16:41:22 +0100
Subject: [PATCH 1/3] add download support for any wave audio file in libnetmd

---
 libnetmd/error.c  |    6 ++-
 libnetmd/error.h  |    6 ++-
 libnetmd/secure.c |  151 +++++++++++++++++++++++++++++++++++++++++++++++++----
 libnetmd/secure.h |   46 +++++++++++++++-
 libnetmd/utils.c  |   10 ++++
 libnetmd/utils.h  |    3 ++
 6 files changed, 209 insertions(+), 13 deletions(-)

diff --git a/libnetmd/error.c b/libnetmd/error.c
index ed8d808..53123c0 100644
--- a/libnetmd/error.c
+++ b/libnetmd/error.c
@@ -38,7 +38,11 @@ static struct error_description const descriptions[] = {
     {NETMD_RESPONSE_TO_SHORT, "Response from device is shorter than expected."},
     {NETMD_RESPONSE_NOT_EXPECTED, "Response from device does not match with the expected result."},
 
-    {NETMD_DES_ERROR, "Error during des caluclation."}
+    {NETMD_DES_ERROR, "Error during des caluclation."},
+
+    {NETMD_OUT_OF_MEMORY, "Cannot allocate memory for storing data"},
+    {NETMD_UNSUPPORTED_FILE, "Audio file format not supported"},
+    {NETMD_CORRUPT_FILE, "Audio file is corrupt"}
 };
 
 static char const unknown_error[] = "Unknown Error";
diff --git a/libnetmd/error.h b/libnetmd/error.h
index 6bbdfa8..dd0ed91 100644
--- a/libnetmd/error.h
+++ b/libnetmd/error.h
@@ -24,7 +24,11 @@ typedef enum {
     NETMD_COMMAND_FAILED_REJECTED,
     NETMD_COMMAND_FAILED_UNKNOWN_ERROR,
 
-    NETMD_DES_ERROR
+    NETMD_DES_ERROR,
+
+    NETMD_OUT_OF_MEMORY,
+    NETMD_UNSUPPORTED_FILE,
+    NETMD_CORRUPT_FILE
 
 } netmd_error;
 
diff --git a/libnetmd/secure.c b/libnetmd/secure.c
index a3dbb6e..ad3fc46 100644
--- a/libnetmd/secure.c
+++ b/libnetmd/secure.c
@@ -29,6 +29,7 @@
   These commands are used during check-in/check-out.
 */
 
+#include <sys/stat.h>
 #include <string.h>
 #include <stdio.h>
 #include <libusb.h>
@@ -45,6 +46,21 @@
 static const unsigned char secure_header[] = { 0x18, 0x00, 0x08, 0x00, 0x46,
                                                0xf0, 0x03, 0x01, 0x03 };
 
+static int wave_data_position(const unsigned char * data, size_t len)
+{
+    int pos = -1, i = 0;
+    while(pos < 0)
+    {
+        if(i >= len-4) // break at end of data
+            break;
+
+        if(strncmp("data", (char *)data+i, 4) == 0)
+            pos = i;
+        i+=2;
+    }
+    return pos;
+}
+
 void build_request(unsigned char *request, const unsigned char cmd, unsigned char *data, const size_t data_size)
 {
     size_t header_length;
@@ -371,7 +387,8 @@ void netmd_transfer_song_packets(netmd_dev_handle *dev,
         memcpy(buf + 16, p->data, p->length);
 
         /* ... send it */
-        error = libusb_bulk_transfer((libusb_device_handle*)dev, 2, packet, (int)packet_size, &transferred, 10000);
+        /* TIMEOUT may be increased for large tracks */
+        error = libusb_bulk_transfer((libusb_device_handle*)dev, 2, packet, (int)packet_size, &transferred, 80000);
         netmd_log(NETMD_LOG_DEBUG, "%d %d\n", packet_size, error);
 
         /* cleanup */
@@ -385,13 +402,14 @@ void netmd_transfer_song_packets(netmd_dev_handle *dev,
     }
 }
 
-netmd_error netmd_prepare_packets(unsigned char* data, size_t data_lenght,
+netmd_error netmd_prepare_packets(netmd_wave_track *track,
                                   netmd_track_packets **packets,
                                   size_t *packet_count,
                                   unsigned char *key_encryption_key)
 {
     size_t position = 0;
     size_t chunksize = 0xffffffffU;
+    size_t frame_size = netmd_get_frame_size(track->wireformat);
     netmd_track_packets *last = NULL;
     netmd_track_packets *next = NULL;
 
@@ -412,14 +430,14 @@ netmd_error netmd_prepare_packets(unsigned char* data, size_t data_lenght,
     gcry_create_nonce(iv, sizeof(iv));
 
     *packet_count = 0;
-    while (position < data_lenght) {
-        if ((data_lenght - position) < chunksize) {
+    while (position < track->audiosize) {
+        if ((track->audiosize - position) < chunksize) {
             /* limit chunksize for last packet */
-            chunksize = data_lenght - position;
+            chunksize = track->audiosize - position;
         }
-
-        if ((chunksize % 8) != 0) {
-            chunksize = chunksize + 8 - (chunksize % 8);
+        /* do not truncate frames */
+        if ((chunksize % frame_size) != 0) {
+            chunksize = chunksize + frame_size - (chunksize % frame_size);
         }
 
         /* alloc memory */
@@ -447,8 +465,8 @@ netmd_error netmd_prepare_packets(unsigned char* data, size_t data_lenght,
         memcpy(next->iv, iv, 8);
         gcry_cipher_setiv(data_handle, iv, 8);
         gcry_cipher_setkey(data_handle, rand, sizeof(rand));
-        gcry_cipher_encrypt(data_handle, next->data, chunksize, data + position, chunksize);
-        memcpy(iv, data + position - 8, 8);
+        gcry_cipher_encrypt(data_handle, next->data, chunksize, track->rawdata + position, chunksize);
+        memcpy(iv, track->rawdata + position - 8, 8);
 
         /* next packet */
         position = position + chunksize;
@@ -459,6 +477,8 @@ netmd_error netmd_prepare_packets(unsigned char* data, size_t data_lenght,
     gcry_cipher_close(key_handle);
     gcry_cipher_close(data_handle);
 
+    track->frames = position/frame_size;
+
     return error;
 }
 
@@ -819,3 +839,114 @@ netmd_error netmd_secure_set_track_protection(netmd_dev_handle *dev,
 
     return error;
 }
+
+netmd_error netmd_wave_track_init(const char *filepath, netmd_wave_track *track)
+{
+    netmd_error err = NETMD_NO_ERROR;
+    struct stat stat_buf;
+    int data_chunk_position;
+    unsigned char * file = NULL;
+    size_t file_size, data_size, rawdata_size;
+    FILE *f;
+
+    /* read source */
+    stat(filepath, &stat_buf);
+    data_size = (size_t)stat_buf.st_size;
+
+    if(!(file = malloc(data_size)))
+        return NETMD_OUT_OF_MEMORY;
+
+    if(!(f = fopen(filepath, "rb")))
+    {
+        free(file);
+        return NETMD_CORRUPT_FILE;
+    }
+    file_size = fread(file, data_size, 1, f);
+    fclose(f);
+
+    /* check if file could be read completely */
+    if(file_size != 1)
+    {
+        free(file);
+        return NETMD_CORRUPT_FILE;
+    }
+
+    /* check if this is a valid wave audio file */
+    if(strncmp("RIFF", (char *)file, 4) != 0
+            || strncmp("WAVE", (char *)file+8, 4) != 0
+            || strncmp("fmt ", (char *)file+12, 4) != 0)
+    {
+        free(file);
+        return NETMD_UNSUPPORTED_FILE;
+    }
+
+    /* read audio data format */
+    if(leword16(file+20) == 1)                                       /* PCM */
+    {
+        track->bo_conv = 1;                                          /* need byte order conversion for pcm raw data*/
+        track->wireformat = NETMD_WIREFORMAT_PCM;
+        if(leword32(file+24) != 44100)                               /* sample rate */
+            err =  NETMD_UNSUPPORTED_FILE;
+        else if(leword16(file+22) == 1 && leword16(file+34) == 8)    /* mono, 8bit */
+            track->diskformat = NETMD_DISKFORMAT_SP_MONO;
+        else if(leword16(file+22) == 2 && leword16(file+34) == 16)   /* stereo, 16 bit */
+            track->diskformat = NETMD_DISKFORMAT_SP_STEREO;
+        else
+            err =  NETMD_UNSUPPORTED_FILE;
+    }
+    else if(leword16(file +20) == NETMD_RIFF_FORMAT_TAG_ATRAC3)   /* ATRAC3 */
+    {
+        track->bo_conv = 0;                                       /* byte order conversion not needed */
+        if(leword32(file+24) != 44100)                            /* sample rate */
+            err =  NETMD_UNSUPPORTED_FILE;
+        else if(leword16(file+32) == 384)                         /* data block size LP2 */
+        {
+            track->wireformat = NETMD_WIREFORMAT_LP2;
+            track->diskformat = NETMD_DISKFORMAT_LP2;
+        }
+        else if(leword16(file+32) == 192)                         /* data block size LP4 */
+        {
+            track->wireformat = NETMD_WIREFORMAT_LP4;
+            track->diskformat = NETMD_DISKFORMAT_LP4;
+        }
+        else
+            err =  NETMD_UNSUPPORTED_FILE;
+    }
+    else
+        err =  NETMD_UNSUPPORTED_FILE;
+
+    /* return if audio format is not supported */
+    if(err != NETMD_NO_ERROR)
+    {
+        free(file);
+        return NETMD_UNSUPPORTED_FILE;
+    }
+
+    /* search for data chunk */
+    if((data_chunk_position = wave_data_position(file, data_size)) < 0)
+    {
+        free(file);
+        return NETMD_CORRUPT_FILE;
+    }
+
+    /* check if the complete raw audio data is present in the file */
+    rawdata_size = leword32(file+data_chunk_position+4);
+    if(rawdata_size > data_size - (data_chunk_position+8))
+    {
+        free(file);
+        return NETMD_CORRUPT_FILE;
+    }
+
+    track->file = file;
+    track->audiosize = rawdata_size;
+    track->rawdata = file+data_chunk_position+8;
+
+    return NETMD_NO_ERROR;
+}
+
+void netmd_wave_track_free(netmd_wave_track *track)
+{
+    free(track->file);
+    track->file = NULL;
+    track->rawdata = NULL;
+}
diff --git a/libnetmd/secure.h b/libnetmd/secure.h
index 41e41ce..65ced82 100644
--- a/libnetmd/secure.h
+++ b/libnetmd/secure.h
@@ -69,6 +69,32 @@ typedef enum {
 } netmd_wireformat;
 
 /**
+   stores all needed information from a wave audio file, used for downloading a track
+*/
+typedef struct netmd_wave_track {
+    /** pointer to audio file data */
+    unsigned char * file;
+
+    /** wireformat to use for download */
+    netmd_wireformat wireformat;
+
+    /** disformat to use for download */
+    unsigned char diskformat;
+
+    /** size of the raw audio data */
+    size_t audiosize;
+
+    /** pointer to the raw audio data inside the file */
+    unsigned char * rawdata;
+
+    /** need of byte order conversion */
+    int bo_conv;
+
+    /** number of frames depending on the wire format */
+    size_t frames;
+} netmd_wave_track;
+
+/**
    Enter a session secured by a root key found in an EKB. The EKB for this
    session has to be download after entering the session.
 */
@@ -189,7 +215,7 @@ netmd_error netmd_secure_get_track_uuid(netmd_dev_handle *dev, uint16_t track,
 netmd_error netmd_secure_delete_track(netmd_dev_handle *dev, uint16_t track,
                                       unsigned char *signature);
 
-netmd_error netmd_prepare_packets(unsigned char* data, size_t data_lenght,
+netmd_error netmd_prepare_packets(netmd_wave_track *track,
                                   netmd_track_packets **packets,
                                   size_t *packet_count,
                                   unsigned char *key_encryption_key);
@@ -199,4 +225,22 @@ void netmd_cleanup_packets(netmd_track_packets **packets);
 netmd_error netmd_secure_set_track_protection(netmd_dev_handle *dev,
                                               unsigned char mode);
 
+size_t netmd_get_frame_size(netmd_wireformat wireformat);
+
+/**
+  Read wave audio file to determine audio format and set wireformat and diskformat
+  correctly to use for download
+
+  @param file path of the audio file
+  @param pointer to a netmd_wave_track struct to store the needed data
+*/
+netmd_error netmd_wave_track_init(const char *filepath, netmd_wave_track *track);
+
+/**
+   free the memory allocated by netmd_wave_track_init() function
+
+   @param pointer to a netmd_wave_track to be freed
+*/
+void netmd_wave_track_free(netmd_wave_track *track);
+
 #endif
diff --git a/libnetmd/utils.c b/libnetmd/utils.c
index 0d9e65e..f623e22 100644
--- a/libnetmd/utils.c
+++ b/libnetmd/utils.c
@@ -291,3 +291,13 @@ uint64_t netmd_read_quadword(netmd_response *response)
 
     return value;
 }
+
+inline unsigned int leword32(const unsigned char * c)
+{
+    return c[3]*16777216+c[2]*65536+c[1]*256+c[0];
+}
+
+inline unsigned int leword16(const unsigned char * c)
+{
+    return c[1]*256+c[0];
+}
diff --git a/libnetmd/utils.h b/libnetmd/utils.h
index 58996f3..85049e1 100644
--- a/libnetmd/utils.h
+++ b/libnetmd/utils.h
@@ -44,4 +44,7 @@ uint16_t netmd_read_word(netmd_response *response);
 uint32_t netmd_read_doubleword(netmd_response *response);
 uint64_t netmd_read_quadword(netmd_response *response);
 
+unsigned int leword32(const unsigned char * c);
+unsigned int leword16(const unsigned char * c);
+
 #endif
-- 
1.7.10.4

>From 695d79e1d9cb1fe75072a16da810d2339801e4aa Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sun, 12 Jan 2014 16:42:41 +0100
Subject: [PATCH 2/3] change netmdcli to use the new/modified funktions of
 libnetmd

---
 netmdcli/netmdcli.c |   44 +++++++++++++++++++++++++++++---------------
 1 file changed, 29 insertions(+), 15 deletions(-)

diff --git a/netmdcli/netmdcli.c b/netmdcli/netmdcli.c
index 354d03c..3f2bf42 100644
--- a/netmdcli/netmdcli.c
+++ b/netmdcli/netmdcli.c
@@ -437,9 +437,7 @@ int main(int argc, char* argv[])
                                           0x2f, 0xa0 };
             netmd_track_packets *packets = NULL;
             size_t packet_count = 0;
-            struct stat stat_buf;
-            unsigned char *data;
-            size_t data_size;
+            netmd_wave_track trk;
 
             uint16_t track;
             unsigned char uuid[8] = { 0 };
@@ -503,27 +501,43 @@ int main(int argc, char* argv[])
             error = netmd_secure_setup_download(devh, contentid, kek, sessionkey);
             puts(netmd_strerror(error));
 
-            /* read source */
-            stat(argv[2], &stat_buf);
-            data_size = (size_t)stat_buf.st_size;
-            data = malloc(data_size);
-            f = fopen(argv[2], "rb");
-            fseek(f, 60, SEEK_CUR);
-            fread(data, data_size - 60, 1, f);
-            fclose(f);
-            error = netmd_prepare_packets(data, data_size-60, &packets, &packet_count, kek);
+            /* read audio format, set disk- and wireformat correctly and check if byte order conversion is needed */
+            error = netmd_wave_track_init(argv[2], &trk);
+            if(error != NETMD_NO_ERROR)
+            {
+                puts(netmd_strerror(error));
+                netmd_clean_disc_info(md);
+                netmd_close(devh);
+                netmd_clean(&device_list);
+                return 0;
+            }
+
+            /* byte order conversion, if needed */
+            if(trk.bo_conv)
+            {
+                for(i = 0; i < trk.audiosize; i+=2)
+                {
+                    unsigned char first = trk.rawdata[i];
+                    trk.rawdata[i] = trk.rawdata[i+1];
+                    trk.rawdata[i+1] = first;
+                }
+            }
+
+            /* prepare packets, recieve number of frames stored in the packet(s) depending on the wireformat */
+            error = netmd_prepare_packets(&trk, &packets, &packet_count, kek);
             puts(netmd_strerror(error));
 
             /* send to device */
-            error = netmd_secure_send_track(devh, NETMD_WIREFORMAT_LP2,
-                                            NETMD_DISKFORMAT_LP2,
-                                            (data_size - 60) / 192, packets,
+            error = netmd_secure_send_track(devh, trk.wireformat,
+                                            trk.diskformat,
+                                            trk.frames, packets,
                                             packet_count, sessionkey,
                                             &track, uuid, new_contentid);
             puts(netmd_strerror(error));
 
             /* cleanup */
             netmd_cleanup_packets(&packets);
+            netmd_wave_track_free(&trk);
 
             /* set title */
             netmd_log(NETMD_LOG_DEBUG, "New Track: %d\n", track);
-- 
1.7.10.4

>From 51fd66cc5766b1b64198e0561be05963acaded15 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sun, 12 Jan 2014 19:53:16 +0100
Subject: [PATCH 3/3] add netmd download routines for any supported wave audio
 file in the gui application

---
 qhimdtransfer/qhimdmainwindow.cpp |    7 +-
 qhimdtransfer/qmddevice.cpp       |  238 ++++++++++++++++++++++++++++++++++++-
 qhimdtransfer/qmddevice.h         |   10 +-
 3 files changed, 250 insertions(+), 5 deletions(-)

diff --git a/qhimdtransfer/qhimdmainwindow.cpp b/qhimdtransfer/qhimdmainwindow.cpp
index 1ce0278..e6f23de 100644
--- a/qhimdtransfer/qhimdmainwindow.cpp
+++ b/qhimdtransfer/qhimdmainwindow.cpp
@@ -346,5 +346,10 @@ void QHiMDMainWindow::current_device_closed()
 
 void QHiMDMainWindow::on_download_button_clicked()
 {
-    /*download_of(localmodel.filePath(ui->localScan->currentIndex()));*/
+    QModelIndex index = ui->localScan->currentIndex();
+    QString title = localmodel.fileInfo(index).baseName();
+    QString path = localmodel.fileInfo(index).absoluteFilePath();
+
+    current_device->download(path, title);
+    open_device(current_device);  //reload tracklist
 }
diff --git a/qhimdtransfer/qmddevice.cpp b/qhimdtransfer/qmddevice.cpp
index 35e01a8..0be30d6 100644
--- a/qhimdtransfer/qmddevice.cpp
+++ b/qhimdtransfer/qmddevice.cpp
@@ -6,6 +6,7 @@
 #include <fileref.h>
 #include <tfile.h>
 #include <tag.h>
+#include <gcrypt.h>
 
 extern "C" {
 #include <sox.h>
@@ -182,9 +183,13 @@ QString QNetMDDevice::discTitle()
 
 QNetMDTrack QNetMDDevice::netmdTrack(unsigned int trkindex)
 {
-    minidisc * disc = &current_md;
+    return QNetMDTrack(devh, &current_md, trkindex);
+}
 
-    return QNetMDTrack(devh, disc, trkindex);
+/* to be freed !*/
+QMDTrack *QNetMDDevice::track(unsigned int trkindex)
+{
+    return new QNetMDTrack(devh, &current_md, trkindex);
 }
 
 QString QNetMDDevice::upload_track_blocks(uint32_t length, FILE *file, size_t chunksize)
@@ -349,6 +354,235 @@ void QNetMDDevice::batchUpload(QMDTrackIndexList tlist, QString path)
     setBusy(false);
 }
 
+void QNetMDDevice::retailmac(unsigned char *rootkey, unsigned char *hostnonce,
+               unsigned char *devnonce, unsigned char *sessionkey)
+{
+    gcry_cipher_hd_t handle1;
+    gcry_cipher_hd_t handle2;
+
+    unsigned char des3_key[24] = { 0 };
+    unsigned char iv[8] = { 0 };
+
+    gcry_cipher_open(&handle1, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+    gcry_cipher_setkey(handle1, rootkey, 8);
+    gcry_cipher_encrypt(handle1, iv, 8, hostnonce, 8);
+
+    memcpy(des3_key, rootkey, 16);
+    memcpy(des3_key+16, rootkey, 8);
+    gcry_cipher_open(&handle2, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
+    gcry_cipher_setkey(handle2, des3_key, 24);
+    gcry_cipher_setiv(handle2, iv, 8);
+    gcry_cipher_encrypt(handle2, sessionkey, 8, devnonce, 8);
+
+    gcry_cipher_close(handle1);
+    gcry_cipher_close(handle2);
+}
+
+/* setting up a secure session til sessionkey generation */
+QString QNetMDDevice::prepare_download(netmd_dev_handle * devh, unsigned char * sky)
+{
+
+    netmd_error error;
+    netmd_ekb ekb;
+    netmd_keychain *keychain;
+    netmd_keychain *next;
+    size_t done;
+    static unsigned char chain[] = {0x25, 0x45, 0x06, 0x4d, 0xea, 0xca,
+                             0x14, 0xf9, 0x96, 0xbd, 0xc8, 0xa4,
+                             0x06, 0xc2, 0x2b, 0x81, 0x49, 0xba,
+                             0xf0, 0xdf, 0x26, 0x9d, 0xb7, 0x1d,
+                             0x49, 0xba, 0xf0, 0xdf, 0x26, 0x9d,
+                             0xb7, 0x1d};
+    static unsigned char signature[] = {0xe8, 0xef, 0x73, 0x45, 0x8d, 0x5b,
+                                 0x8b, 0xf8, 0xe8, 0xef, 0x73, 0x45,
+                                 0x8d, 0x5b, 0x8b, 0xf8, 0x38, 0x5b,
+                                 0x49, 0x36, 0x7b, 0x42, 0x0c, 0x58};
+    static unsigned char rootkey[] = {0x13, 0x37, 0x13, 0x37, 0x13, 0x37,
+                               0x13, 0x37, 0x13, 0x37, 0x13, 0x37,
+                               0x13, 0x37, 0x13, 0x37};
+    static unsigned char hostnonce[8] = { 0 };
+    static unsigned char devnonce[8] = { 0 };
+
+    if((error = netmd_secure_leave_session(devh)) != NETMD_NO_ERROR)
+        return tr("netmd_secure_leave_session: %1").arg(netmd_strerror(error));
+
+    if((error = netmd_secure_set_track_protection(devh, 0x01)) != NETMD_NO_ERROR)
+        return tr("netmd_secure_set_track_protection: %1").arg(netmd_strerror(error));
+
+    if((error = netmd_secure_enter_session(devh)) != NETMD_NO_ERROR)
+        return tr("netmd_secure_enter_session: %1").arg(netmd_strerror(error));
+
+    /* build ekb */
+    ekb.id = 0x26422642;
+    ekb.depth = 9;
+    ekb.signature = (char *)malloc(sizeof(signature));
+    memcpy(ekb.signature, signature, sizeof(signature));
+
+    /* build ekb key chain */
+    ekb.chain = NULL;
+    for (done = 0; done < sizeof(chain); done+=16U)
+    {
+        next = (netmd_keychain *)malloc(sizeof(netmd_keychain));
+        if (ekb.chain == NULL) {
+            ekb.chain = next;
+        }
+        else {
+            keychain->next = next;
+        }
+        next->next = NULL;
+
+        next->key = (char *)malloc(16);
+        memcpy(next->key, chain + done, 16);
+
+        keychain = next;
+    }
+
+    if((error = netmd_secure_send_key_data(devh, &ekb)) != NETMD_NO_ERROR)
+        return tr("netmd_secure_send_key_data: %1").arg(netmd_strerror(error));
+
+    /* cleanup */
+    free(ekb.signature);
+    keychain = ekb.chain;
+    while (keychain != NULL) {
+        next = keychain->next;
+        free(keychain->key);
+        free(keychain);
+        keychain = next;
+    }
+
+    /* exchange nonces */
+    gcry_create_nonce(hostnonce, sizeof(hostnonce));
+
+    if((error = netmd_secure_session_key_exchange(devh, hostnonce, devnonce)) != NETMD_NO_ERROR)
+        return tr("netmd_secure_session_key_exchange: %1").arg(netmd_strerror(error));
+
+    /* calculate session key */
+    retailmac(rootkey, hostnonce, devnonce, sky);
+
+    return QString();
+}
+
+void QNetMDDevice::download(QString audiofile, QString title)
+{
+    /* as chunk size in the netmd_packet(s) is very large, progress bar is not really usable,
+     * just inform the user with a message box for now
+     */
+
+    QMessageBox downloadBox;
+    QString errmsg;
+    netmd_error error;
+    static unsigned char sessionkey[8] = { 0 };
+    static unsigned char kek[] = { 0x14, 0xe3, 0x83, 0x4e, 0xe2, 0xd3, 0xcc, 0xa5 };
+    static unsigned char contentid[] = { 0x01, 0x0F, 0x50, 0x00, 0x00, 0x04,
+                                  0x00, 0x00, 0x00, 0x48, 0xA2, 0x8D,
+                                  0x3E, 0x1A, 0x3B, 0x0C, 0x44, 0xAF,
+                                  0x2f, 0xa0 };
+
+    netmd_track_packets *packets = NULL;
+    size_t packet_count = 0;
+
+    uint16_t track;
+    unsigned char uuid[8] = { 0 };
+    unsigned char new_contentid[20] = { 0 };
+
+    netmd_wave_track trk;
+
+    downloadBox.setWindowTitle(tr("Downloading file to %1").arg(name()));
+    downloadBox.setIconPixmap(QPixmap(":icons/download_to_md.png"));
+    downloadBox.setText(tr("Please wait while transferring audio file\n%1").arg(audiofile));
+    downloadBox.setStandardButtons(0);
+    downloadBox.show();
+    /* call processEvents() periodically to show up message box correctly */
+    QApplication::processEvents();
+
+    /* read audio file and set wireformat, diskformat and byteorder conversion correctly*/
+    if((error = netmd_wave_track_init(audiofile.toUtf8(), &trk)) != NETMD_NO_ERROR)
+    {
+        errmsg = tr("Error:\nnetmd_wave_track_init: %1").arg(netmd_strerror(error));
+        goto clean;
+    }
+    QApplication::processEvents();
+
+    /* byte order conversion if needed*/
+    if(trk.bo_conv)
+    {
+        for(unsigned int i = 0; i < trk.audiosize; i+=2)
+        {
+            unsigned char first = trk.rawdata[i];
+            trk.rawdata[i] = trk.rawdata[i+1];
+            trk.rawdata[i+1] = first;
+        }
+    }
+    QApplication::processEvents();
+
+    /* init a secure session */
+    if(!(errmsg = prepare_download(devh, sessionkey)).isEmpty())
+    {
+        errmsg = tr("Error:\n%1").arg(errmsg);
+        netmd_wave_track_free(&trk);
+        goto clean;
+    }
+    QApplication::processEvents();
+
+    /* prepare download operation*/
+    if((error = netmd_secure_setup_download(devh, contentid, kek, sessionkey)) != NETMD_NO_ERROR)
+    {
+        errmsg = tr("Error:\nnetmd_secure_setup_download: %1").arg(netmd_strerror(error));
+        netmd_wave_track_free(&trk);
+        goto clean;
+    }
+    QApplication::processEvents();
+
+    /* setup data packet(s) and get number of frames stored in the packet(s)*/
+    if((error = netmd_prepare_packets(&trk, &packets, &packet_count, kek)) != NETMD_NO_ERROR)
+    {
+        errmsg = tr("Error:\nnetmd_prepare_packets: %1").arg(netmd_strerror(error));
+        netmd_cleanup_packets(&packets);
+        netmd_wave_track_free(&trk);
+        goto clean;
+    }
+    QApplication::processEvents();
+
+    /* send track to device*/
+    error = netmd_secure_send_track(devh, trk.wireformat,
+                                    trk.diskformat,
+                                    trk.frames, packets,
+                                    packet_count, sessionkey,
+                                    &track, uuid, new_contentid);
+    /* cleanup */
+    netmd_cleanup_packets(&packets);
+    netmd_wave_track_free(&trk);
+
+    if(error != NETMD_NO_ERROR)
+    {
+        errmsg = tr("Error:\nnetmd_secure_send_track: %1").arg(netmd_strerror(error));
+        goto clean;
+    }
+
+    /* set title */
+    netmd_cache_toc(devh);
+    netmd_set_title(devh, track, title.toUtf8());
+    netmd_sync_toc(devh);
+
+    /* commit track */
+    if((error = netmd_secure_commit_track(devh, track, sessionkey)) != NETMD_NO_ERROR)
+        errmsg = tr("Error:\nnetmd_secure_commit_track: %1").arg(netmd_strerror(error));
+
+clean:
+    /* forget key */
+    netmd_secure_session_key_forget(devh);
+    /* leave session */
+    netmd_secure_leave_session(devh);
+
+    if(errmsg.isEmpty())
+        errmsg = tr("Download finished.\n\nsuccessfully transferred audio file\n   %1\nto disk at track number %2").arg(audiofile).arg(track+1);
+    downloadBox.close();
+    downloadBox.setText(errmsg);
+    downloadBox.setStandardButtons(QMessageBox::Ok);
+    downloadBox.exec();
+}
+
+
 /* himd device members */
 
 QHiMDDevice::QHiMDDevice()
diff --git a/qhimdtransfer/qmddevice.h b/qhimdtransfer/qmddevice.h
index c413f9c..16707be 100644
--- a/qhimdtransfer/qmddevice.h
+++ b/qhimdtransfer/qmddevice.h
@@ -48,12 +48,13 @@ public:
     virtual void * deviceHandle();
     virtual void registerMdChange(void * regMdChange);
     virtual void * MdChange();
-    virtual QMDTrack track(unsigned int trkindex) {return QMDTrack();}
+    virtual QMDTrack *track(unsigned int trkindex) {return NULL;}
     virtual int trackCount() {return trk_count;}
     virtual QStringList downloadableFileExtensions() const;
     virtual void checkfile(QString UploadDirectory, QString &filename, QString extension);
     virtual void batchUpload(QMDTrackIndexList tlist, QString path) {}
     virtual void upload(unsigned int trackidx, QString path) {}
+    virtual void download(QString audiofile, QString title) {}
 
 signals:
     void opened();
@@ -67,6 +68,9 @@ class QNetMDDevice : public QMDDevice {
     minidisc current_md;
 private:
     QString upload_track_blocks(uint32_t length, FILE *file, size_t chunksize);
+    void retailmac(unsigned char *rootkey, unsigned char *hostnonce, unsigned char *devnonce, unsigned char *sessionkey);
+    QString prepare_download(netmd_dev_handle * devh, unsigned char * sky);
+
 public:
     explicit QNetMDDevice();
     virtual ~QNetMDDevice();
@@ -75,9 +79,11 @@ public:
     virtual void close();
     virtual QString discTitle();
     virtual QNetMDTrack netmdTrack(unsigned int trkindex);
+    /* returns a pointer to a new QMDTrack object, this has to be freed */
+    virtual QMDTrack *track(unsigned int trkindex);
     virtual void batchUpload(QMDTrackIndexList tlist, QString path);
     virtual void upload(unsigned int trackidx, QString path);
-
+    virtual void download(QString audiofile, QString title);
 };
 
 class QHiMDDevice : public QMDDevice {
-- 
1.7.10.4

<-- thread -->
<-- date -->
  • Follow-Ups:
    • Re: [linux-minidisc] netmd/netmdcli: download support for any .wav file containing pcm audio
      • From: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
  • References:
    • [linux-minidisc] netmd/netmdcli: download support for any .wav file containing pcm audio
      • From: Thomas Arp <manner.moe@gmx.de>
    • Re: [linux-minidisc] netmd/netmdcli: download support for any .wav file containing pcm audio
      • From: Michael Karcher <Michael.Karcher@fu-berlin.de>
  • linux-minidisc - January 2014 - Archives indexes sorted by:
    [ thread ] [ subject ] [ author ] [ date ]
  • Complete archive of the linux-minidisc mailing list
  • More info on this list...

Hilfe

  • FAQ
  • Dienstbeschreibung
  • ZEDAT Beratung
  • postmaster@lists.fu-berlin.de

Service-Navigation

  • Startseite
  • Listenauswahl

Einrichtung Mailingliste

  • ZEDAT-Portal
  • Mailinglisten Portal