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 = ¤t_md;
+ return QNetMDTrack(devh, ¤t_md, trkindex);
+}
- return QNetMDTrack(devh, disc, trkindex);
+/* to be freed !*/
+QMDTrack *QNetMDDevice::track(unsigned int trkindex)
+{
+ return new QNetMDTrack(devh, ¤t_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