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