Пример #1
0
void main_loop(void)
{
    msgType              dialog_type;
    char                 *message = (char *) malloc(512);
    sacd_reader_t        *sacd_reader;
    scarletbook_handle_t *sb_handle = 0;
    int idx = 0;

    if (output_device_changed && output_device)
    {
        char file_path[100];
        sprintf(file_path, "%s/sacd_log.txt", output_device);
        set_log_file(file_path);
        LOG(lm_main, LOG_NOTICE, ("SACD-Ripper Version " SACD_RIPPER_VERSION_STRING));
    }

    // did the disc change?
    if (bd_contains_sacd_disc && bd_disc_changed)
    {
        // open the BD device
        sacd_reader = sacd_open("/dev_bdvd");
        if (sacd_reader)
        {
            // read the scarletbook information
            sb_handle = scarletbook_open(sacd_reader, 0);
            if (sb_handle)
            {
                master_text_t *master_text = &sb_handle->master_text;
                master_toc_t *mtoc = sb_handle->master_toc;

                if (master_text->disc_title || master_text->disc_title_phonetic)
                {
                    idx += snprintf(message_info + idx, 60, "Title: %s\n", substr((master_text->disc_title ? master_text->disc_title : master_text->disc_title_phonetic), 0, 50));
                    LOG(lm_main, LOG_NOTICE, ("Album Title: %s", substr((master_text->disc_title ? master_text->disc_title : master_text->disc_title_phonetic), 0, 50)));
                }

                if (message_info[idx - 1] != '\n') { message_info[idx++] = '\n'; message_info[idx] = '\0'; }

                if (master_text->disc_artist || master_text->disc_artist_phonetic)
                {
                    idx += snprintf(message_info + idx, 60, "Artist: %s\n", substr((master_text->disc_artist ? master_text->disc_artist : master_text->disc_artist_phonetic), 0, 50));
                    LOG(lm_main, LOG_NOTICE, ("Album Artist: %s", substr((master_text->disc_artist ? master_text->disc_artist : master_text->disc_artist_phonetic), 0, 50)));
                }

                if (message_info[idx - 1] != '\n') { message_info[idx++] = '\n'; message_info[idx] = '\0'; }

                idx += snprintf(message_info + idx, 20, "Version: %02i.%02i\n", mtoc->version.major, mtoc->version.minor);
                LOG(lm_main, LOG_NOTICE, ("Disc Version: %02i.%02i\n", mtoc->version.major, mtoc->version.minor));
                idx += snprintf(message_info + idx, 25, "Created: %4i-%02i-%02i\n", mtoc->disc_date_year, mtoc->disc_date_month, mtoc->disc_date_day);

                idx += snprintf(message_info + idx, 15, "Area 0:\n");
                idx += snprintf(message_info + idx, 35, "   Speakers: %s\n", get_speaker_config_string(sb_handle->area[0].area_toc));
                idx += snprintf(message_info + idx, 35, "   Encoding: %s\n", get_frame_format_string(sb_handle->area[0].area_toc));
                idx += snprintf(message_info + idx, 25, "   Tracks: %d (%.2fGB)\n", sb_handle->area[0].area_toc->track_count, ((double) (sb_handle->area[0].area_toc->track_end - sb_handle->area[0].area_toc->track_start) * SACD_LSN_SIZE) / 1073741824.00);
                if (has_both_channels(sb_handle))
                {
                    idx += snprintf(message_info + idx, 2, "\n");
                    idx += snprintf(message_info + idx, 15, "Area 1:\n");
                    idx += snprintf(message_info + idx, 35, "   Speakers: %s\n", get_speaker_config_string(sb_handle->area[1].area_toc));
                    idx += snprintf(message_info + idx, 35, "   Encoding: %s\n", get_frame_format_string(sb_handle->area[1].area_toc));
                    idx += snprintf(message_info + idx, 25, "   Tracks: %d (%.2fGB)\n", sb_handle->area[1].area_toc->track_count, ((double) (sb_handle->area[1].area_toc->track_end - sb_handle->area[1].area_toc->track_start) * SACD_LSN_SIZE) / 1073741824.00);
                }

                idx += snprintf(message_info + idx, 50, "\nclick X to start ripping, O to change output");

                current_ripping_flags = 0;
                if (has_two_channel(sb_handle))
                {
                    current_ripping_flags |= RIP_2CH;
                    if (sb_handle->area[sb_handle->twoch_area_idx].area_toc->frame_format == FRAME_FORMAT_DST)
                    {
                        current_ripping_flags |= RIP_2CH_DST;
                    }
                }
                if (has_multi_channel(sb_handle))
                {
                    current_ripping_flags |= RIP_MCH;
                }

                // validate output format as the ripping flags have changed
                output_format_changed = 1;
                validate_output_format();

                scarletbook_close(sb_handle);
                sb_handle = 0;
            }
            else
            {
                bd_contains_sacd_disc = 0;
            }

            // close the input device asap
            sacd_close(sacd_reader);
            sacd_reader = 0;
        }
        else
        {
            bd_contains_sacd_disc = 0;
        }
    }

    if (output_device_changed || output_format_changed)
    {
        // output device
        if (output_device)
            idx = snprintf(message_output, 35, "Output: %s %.2fGB\n", output_device, output_device_space);
        else
            idx = snprintf(message_output, 35, "Output: NO DEVICE\n");

        // output format
        idx += snprintf(message_output + idx, 20, "Format: ");

        switch (output_format)
        {
        case 0:
            idx += snprintf(message_output + idx, 20, "2ch DSDIFF (DSD)\n");
            break;
        case 1:
            idx += snprintf(message_output + idx, 20, "2ch DSDIFF (DST)\n");
            break;
        case 2:
            idx += snprintf(message_output + idx, 20, "2ch DSF (DSD)\n");
            break;
        case 3:
            idx += snprintf(message_output + idx, 20, "mch DSDIFF (DSD)\n");
            break;
        case 4:
            idx += snprintf(message_output + idx, 20, "mch DSDIFF (DST)\n");
            break;
        case 5:
            idx += snprintf(message_output + idx, 20, "mch DSF (DSF)\n");
            break;
        case 6:
            idx += snprintf(message_output + idx, 20, "ISO\n");
            break;
        }
        idx += snprintf(message_output + idx, 2, "\n");
    }

    // by default we have no user controls
    dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_DISABLE_CANCEL_ON);

    if (bd_contains_sacd_disc)
    {
        snprintf(message, 512, "%s%s", message_output, message_info);
    }
    else
    {
        snprintf(message, 512, "The current disc is empty or not recognized as an SACD, please re-insert.\n\n%s"
                 , (output_device ? "" : "(Also make sure you connect an external fat32 formatted harddisk!)"));
    }

    // can we start ripping?
    if (bd_contains_sacd_disc)
    {
        dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK);
    }

    msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL);

    dialog_action         = 0;
    bd_disc_changed       = 0;
    output_device_changed = 0;
    output_format_changed = 0;
    while (!dialog_action && !user_requested_exit() && bd_disc_changed == 0 && output_device_changed == 0)
    {
        // poll for new output devices
        poll_output_devices();

        sysUtilCheckCallback();
        flip();
    }
    msgDialogAbort();

    // did user request to start the ripping process?
    if (dialog_action == 1 && bd_contains_sacd_disc)
    {
        start_ripping_gui(output_format_options[output_format]);

        reset_output_devices();

        // action is handled
        dialog_action = 0;
    }
    else if (dialog_action == 2)
    {
#if 0
        output_format++;

        // max of 7 output options
        if (output_format > 6)
        {
            output_format = 0;
        }
#endif

        // is the current selection valid?
        validate_output_format();

        // action is handled
        output_format_changed = 1;
        dialog_action = 0;
    }

    free(message);
}
Пример #2
0
int main(int argc, char* argv[]) 
{
    char *albumdir = 0, *musicfilename, *file_path = 0;
    int i, area_idx;
    sacd_reader_t *sacd_reader;

#ifdef PTW32_STATIC_LIB
    pthread_win32_process_attach_np();
    pthread_win32_thread_attach_np();
#endif

    init();
    if (parse_options(argc, argv)) 
    {
        setlocale(LC_ALL, "");
        if (fwide(stdout, 1) < 0)
        {
            fprintf(stderr, "ERROR: Output not set to wide.\n");
        }

        // default to 2 channel
        if (opts.two_channel == 0 && opts.multi_channel == 0) 
        {
            opts.two_channel = 1;
        }

        sacd_reader = sacd_open(opts.input_device);
        if (sacd_reader) 
        {

            handle = scarletbook_open(sacd_reader, 0);
            if (handle)
            {
                if (opts.print)
                {
                    scarletbook_print(handle);
                }

                if (opts.output_dsf || opts.output_iso || opts.output_dsdiff || opts.output_dsdiff_em || opts.export_cue_sheet)
                {
                    output = scarletbook_output_create(handle, handle_status_update_track_callback, handle_status_update_progress_callback, safe_fwprintf);

                    // select the channel area
                    area_idx = ((has_multi_channel(handle) && opts.multi_channel) || !has_two_channel(handle)) ? handle->mulch_area_idx : handle->twoch_area_idx;

                    albumdir = (strlen(opts.output_file) > 0 ? strdup(opts.output_file) : get_album_dir(handle));

                    if (opts.output_iso)
                    {
                        uint32_t total_sectors = sacd_get_total_sectors(sacd_reader);
#ifdef SECTOR_LIMIT
#define FAT32_SECTOR_LIMIT 2090000
                        uint32_t sector_size = FAT32_SECTOR_LIMIT;
                        uint32_t sector_offset = 0;
                        if (total_sectors > FAT32_SECTOR_LIMIT)
                        {
                            musicfilename = (char *) malloc(512);
                            file_path = make_filename(0, 0, albumdir, "iso");
                            for (i = 1; total_sectors != 0; i++)
                            {
                                sector_size = min(total_sectors, FAT32_SECTOR_LIMIT);
                                snprintf(musicfilename, 512, "%s.%03d", file_path, i);
                                scarletbook_output_enqueue_raw_sectors(output, sector_offset, sector_size, musicfilename, "iso");
                                sector_offset += sector_size;
                                total_sectors -= sector_size;
                            }
                            free(musicfilename);
                        }
                        else
#endif
                        {
                            get_unique_filename(&albumdir, "iso");
                            file_path = make_filename(0, 0, albumdir, "iso");
                            scarletbook_output_enqueue_raw_sectors(output, 0, total_sectors, file_path, "iso");
                        }
                    }
                    else if (opts.output_dsdiff_em)
                    {
                        get_unique_filename(&albumdir, "dff");
                        file_path = make_filename(0, 0, albumdir, "dff");

                        scarletbook_output_enqueue_track(output, area_idx, 0, file_path, "dsdiff_edit_master", 
                            (opts.convert_dst ? 1 : handle->area[area_idx].area_toc->frame_format != FRAME_FORMAT_DST));
                    }
                    else if (opts.output_dsf || opts.output_dsdiff)
                    {
                        // create the output folder
                        get_unique_dir(0, &albumdir);
                        recursive_mkdir(albumdir, 0774);

                        // fill the queue with items to rip
                        for (i = 0; i < handle->area[area_idx].area_toc->track_count; i++) 
                        {
                            if (opts.select_tracks && opts.selected_tracks[i] == 0)
                                continue;

                            musicfilename = get_music_filename(handle, area_idx, i, opts.output_file);

                            if (opts.output_dsf)
                            {
                                file_path = make_filename(0, albumdir, musicfilename, "dsf");
                                scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsf", 
                                    1 /* always decode to DSD */);
                            }
                            else if (opts.output_dsdiff)
                            {
                                file_path = make_filename(0, albumdir, musicfilename, "dff");
                                scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsdiff", 
                                    (opts.convert_dst ? 1 : handle->area[area_idx].area_toc->frame_format != FRAME_FORMAT_DST));
                            }

                            free(musicfilename);
                            free(file_path);
                            file_path = 0;
                        }
                    }

                    if (opts.export_cue_sheet)
                    {
                        char *cue_file_path = make_filename(0, 0, albumdir, "cue");
#ifdef _WIN32
                        wchar_t *wide_filename = (wchar_t *) charset_convert(cue_file_path, strlen(cue_file_path), "UTF-8", sizeof(wchar_t) == 2 ? "UCS-2-INTERNAL" : "UCS-4-INTERNAL");
#else
                        wchar_t *wide_filename = (wchar_t *) charset_convert(cue_file_path, strlen(cue_file_path), "UTF-8", "WCHAR_T");
#endif
                        fwprintf(stdout, L"Exporting CUE sheet [%ls]\n", wide_filename);
                        if (!file_path)
                            file_path = make_filename(0, 0, albumdir, "dff");
                        write_cue_sheet(handle, file_path, area_idx, cue_file_path);
                        free(cue_file_path);
                        free(wide_filename);
                    }

                    free(file_path);

                    started_processing = time(0);
                    scarletbook_output_start(output);
                    scarletbook_output_destroy(output);

                    fprintf(stdout, "\rWe are done..                                                          \n");
                }
                scarletbook_close(handle);

                free(albumdir);
            }
        }

        sacd_close(sacd_reader);

#ifndef _WIN32
        freopen(0, "w", stdout);
#endif
        if (fwide(stdout, -1) >= 0)
        {
            fprintf(stderr, "ERROR: Output not set to byte oriented.\n");
        }
    }

    free_lock(g_fwprintf_lock);
    destroy_logging();

#ifdef PTW32_STATIC_LIB
    pthread_win32_process_detach_np();
    pthread_win32_thread_detach_np();
#endif

    printf("\n");
    return 0;
}
Пример #3
0
int start_ripping_gui(int ripping_flags)
{
    char *albumdir, *musicfilename, *file_path = 0;
    sacd_reader_t   *sacd_reader;
    scarletbook_handle_t *handle;
    scarletbook_output_t *output;
    msgType          dialog_type;
    int              area_idx, i, ret;

    uint32_t prev_upper_progress = 0;
    uint32_t prev_lower_progress = 0;
    uint32_t delta;

    int prev_current_track = 0;
    uint32_t prev_stats_total_sectors_processed = 0;
    uint32_t prev_stats_current_file_sectors_processed = 0;
    uint64_t tb_start, tb_freq;
    uint64_t tmp_total_ripping_sectors = 0;

    char progress_message[64];

    sysAtomicSet(&stats_total_sectors, 0);
    sysAtomicSet(&stats_total_sectors_processed, 0);
    sysAtomicSet(&stats_current_file_total_sectors, 0);
    sysAtomicSet(&stats_current_file_sectors_processed, 0); 
    sysAtomicSet(&stats_current_track, 0);
    sysAtomicSet(&stats_total_tracks, 0);

    sacd_reader = sacd_open("/dev_bdvd");
    if (sacd_reader) 
    {
        handle = scarletbook_open(sacd_reader, 0);

        if (check_disc_space(sacd_reader, handle, ripping_flags))
        {
            ret = sacd_authenticate(sacd_reader);
            if (ret != 0)
            {
                LOG(lm_main, LOG_ERROR, ("authentication failed: %x", ret));
            }

            // select the channel area
            area_idx = ((has_multi_channel(handle) && ripping_flags & RIP_MCH) || !has_two_channel(handle)) ? handle->mulch_area_idx : handle->twoch_area_idx;

            albumdir = get_album_dir(handle);

            output = scarletbook_output_create(handle, handle_status_update_track_callback, handle_status_update_progress_callback, safe_fwprintf);

            if (ripping_flags & RIP_ISO)
            {
                #define FAT32_SECTOR_LIMIT 2090000
                uint32_t total_sectors = sacd_get_total_sectors(sacd_reader);
                uint32_t sector_size = FAT32_SECTOR_LIMIT;
                uint32_t sector_offset = 0;
                if (total_sectors > FAT32_SECTOR_LIMIT)
                 {
                    musicfilename = (char *) malloc(512);
                    file_path = make_filename(output_device, 0, albumdir, "iso");
                    for (i = 1; total_sectors != 0; i++)
                    {
                        sector_size = min(total_sectors, FAT32_SECTOR_LIMIT);
                        snprintf(musicfilename, 512, "%s.%03d", file_path, i);
                        scarletbook_output_enqueue_raw_sectors(output, sector_offset, sector_size, musicfilename, "iso");
                        sector_offset += sector_size;
                        total_sectors -= sector_size;
                    }
                    free(file_path);
                    free(musicfilename);
                }
                else
                {
                    file_path = make_filename(output_device, 0, albumdir, "iso");
                    scarletbook_output_enqueue_raw_sectors(output, 0, total_sectors, file_path, "iso");
                    free(file_path);
                }
                tmp_total_ripping_sectors = sacd_get_total_sectors(sacd_reader);
            }
            else 
            {
                // do not overwrite previous dump
                get_unique_dir(output_device, &albumdir);

                // fill the queue with items to rip
                for (i = 0; i < handle->area[area_idx].area_toc->track_count; i++) 
                {
                    musicfilename = get_music_filename(handle, area_idx, i, 0);
                    if (ripping_flags & RIP_DSF)
                    {
                        file_path = make_filename(output_device, albumdir, musicfilename, "dsf");
                        scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsf", 
                            1 /* always decode to DSD */);
                    }
                    else if (ripping_flags & RIP_DSDIFF)
                    {
                        file_path = make_filename(output_device, albumdir, musicfilename, "dff");
                        scarletbook_output_enqueue_track(output, area_idx, i, file_path, "dsdiff", 
                            ((ripping_flags & RIP_2CH_DST || ripping_flags & RIP_MCH_DST) ? 0 : 1));
                    }

                    tmp_total_ripping_sectors += handle->area[area_idx].area_tracklist_offset->track_length_lsn[i];

                    free(musicfilename);
                    free(file_path);
                }

                file_path = make_filename(output_device, albumdir, 0, 0);
                LOG(lm_main, LOG_NOTICE, ("setting output folder to: %s", file_path));
                recursive_mkdir(file_path, 0777);
                free(file_path);
            }

            scarletbook_output_start(output);

            tb_freq = sysGetTimebaseFrequency();
            tb_start = __gettime(); 

            {
                char *message = (char *) malloc(512);

                file_path = make_filename(output_device, albumdir, 0, 0);
                snprintf(message, 512, "Title: %s\nOutput: %s\nFormat: %s\nSize: %.2fGB\nArea: %s\nEncoding: %s", 
                        substr(albumdir, 0, 100), 
                        file_path, 
                        (ripping_flags & RIP_DSDIFF ? "DSDIFF" : (ripping_flags & RIP_DSF ? "DSF" : "ISO")),
                        ((double) ((tmp_total_ripping_sectors * SACD_LSN_SIZE) / 1073741824.00)),
                        (ripping_flags & RIP_2CH ? "2ch" : "mch"),
                        (ripping_flags & RIP_2CH_DST || ripping_flags & RIP_MCH_DST ? "DST" : (ripping_flags & RIP_ISO ? "DECRYPTED" : "DSD"))
                        );
                free(file_path);

                dialog_action = 0;
                dialog_type   = MSG_DIALOG_MUTE_ON | MSG_DIALOG_DOUBLE_PROGRESSBAR;
                msgDialogOpen2(dialog_type, message, dialog_handler, NULL, NULL);
                while (!user_requested_exit() && dialog_action == 0 && scarletbook_output_is_busy(output))
                {
                    uint32_t tmp_stats_total_sectors_processed = sysAtomicRead(&stats_total_sectors_processed);
                    uint32_t tmp_stats_total_sectors = sysAtomicRead(&stats_total_sectors);
                    uint32_t tmp_stats_current_file_sectors_processed = sysAtomicRead(&stats_current_file_sectors_processed);
                    uint32_t tmp_stats_current_file_total_sectors = sysAtomicRead(&stats_current_file_total_sectors);
                    int tmp_current_track = sysAtomicRead(&stats_current_track);

                    if (tmp_current_track != 0 && tmp_current_track != prev_current_track)
                    {
                        memset(progress_message, 0, 64);
       
                        musicfilename = get_music_filename(handle, area_idx, tmp_current_track - 1, 0);
                        // HACK: substr is not thread safe, but it's only used in this thread..
                        snprintf(progress_message, 63, "Track (%d/%d): [%s...]", tmp_current_track, sysAtomicRead(&stats_total_tracks), substr(musicfilename, 0, 40));
                        free(musicfilename);

                        msgDialogProgressBarReset(MSG_PROGRESSBAR_INDEX0);
                        msgDialogProgressBarSetMsg(MSG_PROGRESSBAR_INDEX1, progress_message);
                        prev_upper_progress = 0;
                        prev_stats_current_file_sectors_processed = 0;

                        prev_current_track = tmp_current_track;
                    }

                    if (tmp_stats_total_sectors != 0 && prev_stats_total_sectors_processed != tmp_stats_total_sectors_processed)
                    {
                        delta = (tmp_stats_current_file_sectors_processed + (tmp_stats_current_file_sectors_processed - prev_stats_current_file_sectors_processed)) * 100 / tmp_stats_current_file_total_sectors - prev_upper_progress;
                        prev_upper_progress += delta;
                        msgDialogProgressBarInc(MSG_PROGRESSBAR_INDEX0, delta);

                        delta = (tmp_stats_total_sectors_processed + (tmp_stats_total_sectors_processed - prev_stats_total_sectors_processed)) * 100 / tmp_stats_total_sectors - prev_lower_progress;
                        prev_lower_progress += delta;
                        msgDialogProgressBarInc(MSG_PROGRESSBAR_INDEX1, delta);

                        snprintf(progress_message, 64, "Ripping %.1fMB/%.1fMB at %.2fMB/sec", 
                                ((float)(tmp_stats_current_file_sectors_processed * SACD_LSN_SIZE) / 1048576.00),
                                ((float)(tmp_stats_current_file_total_sectors * SACD_LSN_SIZE) / 1048576.00),
                                (float)((float) tmp_stats_total_sectors_processed * SACD_LSN_SIZE / 1048576.00) / (float)((__gettime() - tb_start) / (float)(tb_freq)));
                        
                        msgDialogProgressBarSetMsg(MSG_PROGRESSBAR_INDEX0, progress_message);
                        
                        prev_stats_total_sectors_processed = tmp_stats_total_sectors_processed;
                        prev_stats_current_file_sectors_processed = tmp_stats_current_file_sectors_processed;
                    }

                    sysUtilCheckCallback();
                    flip();
                }
                msgDialogAbort();
                free(message);
            }
            free(albumdir);

            scarletbook_output_destroy(output);
        }
        scarletbook_close(handle);
    }
    sacd_close(sacd_reader);

    if (user_requested_exit())
    {
        return 0;
    }
    else if (1)
    {
        dialog_type = (MSG_DIALOG_NORMAL | MSG_DIALOG_BTN_TYPE_OK | MSG_DIALOG_DISABLE_CANCEL_ON);
        msgDialogOpen2(dialog_type, "ripping process completed.", dialog_handler, NULL, NULL);

        dialog_action = 0;
        while (!dialog_action && !user_requested_exit())
        {
            sysUtilCheckCallback();
            flip();
        }
        msgDialogAbort();
    }

    return 0;
}
Пример #4
0
static void client_thread(void *userdata)
{
	p_socket client = (p_socket) userdata;
    ServerRequest request;
    ServerResponse response;
    uint8_t zero = 0;
    uint8_t *output_buf = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024);
    pb_istream_t input = pb_istream_from_socket(client);
    pb_ostream_t output;
    sacd_reader_t   *sacd_reader = 0;
    scarletbook_handle_t *handle = 0;
    int non_encrypted_disc = 0;
    int checked_for_non_encrypted_disc = 0;
    uint32_t encrypted_start_1 = 0;
    uint32_t encrypted_start_2 = 0;
    uint32_t encrypted_end_1 = 0;
    uint32_t encrypted_end_2 = 0;
    uint32_t block_size = 0;
    uint32_t end_lsn = 0;

	client_connected = 1;
	
	response.data.bytes = (uint8_t *) malloc(MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE);

    for (;;)
    {
        if (!pb_decode(&input, ServerRequest_fields, &request))
        {
            break;
        }

        response.has_data = false;
        response.data.size = 0;
        response.result = -1;
    
        switch(request.type)
        {
        case ServerRequest_Type_DISC_READ:
            {
                response.type = ServerResponse_Type_DISC_READ;
                if (handle && sacd_reader)
                {
                    int encrypted = 0;
                    end_lsn = request.sector_offset + request.sector_count;
     
                    // check what block ranges are encrypted..
                    if (request.sector_offset < encrypted_start_1)
                    {
                        block_size = min(encrypted_start_1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE);
                        encrypted = 0;
                    }
                    else if (request.sector_offset >= encrypted_start_1 && request.sector_offset <= encrypted_end_1)
                    {
                        block_size = min(encrypted_end_1 + 1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE);
                        encrypted = 1;
                    }
                    else if (request.sector_offset > encrypted_end_1 && request.sector_offset < encrypted_start_2)
                    {
                        block_size = min(encrypted_start_2 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE);
                        encrypted = 0;
                    }
                    else if (request.sector_offset >= encrypted_start_2 && request.sector_offset <= encrypted_end_2)
                    {
                        block_size = min(encrypted_end_2 + 1 - request.sector_offset, MAX_PROCESSING_BLOCK_SIZE);
                        encrypted = 1;
                    }
                    block_size = min(end_lsn - request.sector_offset, block_size);

                    response.result = sacd_read_block_raw(sacd_reader, request.sector_offset, block_size, response.data.bytes);
                    response.has_data = response.result > 0;
                    response.data.size = response.result * SACD_LSN_SIZE;
                    
                    // the ATAPI call which returns the flag if the disc is encrypted or not is unknown at this point. 
                    // user reports tell me that the only non-encrypted discs out there are DSD 3 14/16 discs. 
                    // this is a quick hack/fix for these discs.
                    if (encrypted && checked_for_non_encrypted_disc == 0)
                    {
                        switch (handle->area[0].area_toc->frame_format)
                        {
                        case FRAME_FORMAT_DSD_3_IN_14:
                        case FRAME_FORMAT_DSD_3_IN_16:
                            non_encrypted_disc = *(uint64_t *)(response.data.bytes + 16) == 0;
                            break;
                        }

                        checked_for_non_encrypted_disc = 1;
                    }

                    // encrypted blocks need to be decrypted first
                    if (encrypted && non_encrypted_disc == 0)
                    {
                        sacd_decrypt(sacd_reader, response.data.bytes, block_size);
                    }
                }
            }
            break;
        case ServerRequest_Type_DISC_OPEN:
            response.type = ServerResponse_Type_DISC_OPENED;
            sacd_reader = sacd_open("/dev_bdvd");
            if (sacd_reader) 
            {
                handle = scarletbook_open(sacd_reader, 0);
                checked_for_non_encrypted_disc = 0;
                non_encrypted_disc = 0;
                
                if (handle)
                {
                    // set the encryption range
                    if (handle->area[0].area_toc != 0)
                    {
                        encrypted_start_1 = handle->area[0].area_toc->track_start;
                        encrypted_end_1 = handle->area[0].area_toc->track_end;
                    }
                    if (handle->area[1].area_toc != 0)
                    {
                        encrypted_start_2 = handle->area[1].area_toc->track_start;
                        encrypted_end_2 = handle->area[1].area_toc->track_end;
                    }

                    response.result = sacd_authenticate(sacd_reader);
                }
            }
            break;
        case ServerRequest_Type_DISC_CLOSE:
            {
                response.type = ServerResponse_Type_DISC_CLOSED;
                if (handle)
                {
                    scarletbook_close(handle);
                    handle = 0;
                }
                if (sacd_reader)
                {
                    sacd_close(sacd_reader);
                    sacd_reader = 0;
                }
                response.result = 0;
            }
            break;
        case ServerRequest_Type_DISC_SIZE:
            response.type = ServerResponse_Type_DISC_SIZE;
            if (sacd_reader)
            {
                response.result = sacd_get_total_sectors(sacd_reader);
            }
            break;
        }

        // reset output stream
        output = pb_ostream_from_buffer(output_buf, MAX_PROCESSING_BLOCK_SIZE * SACD_LSN_SIZE + 1024);
        
        if (!pb_encode(&output, ServerResponse_fields, &response))
        {
            break;
        }
    
        /* We signal the end of a request with a 0 tag. */
        pb_write(&output, &zero, 1);
        
        // write the output buffer to the opened socket
        {
            bool ret;
            size_t written; 
            ret = (socket_send(client, (char *) output_buf, output.bytes_written, &written, 0, 0) == IO_DONE && written == output.bytes_written);

            if (!ret)
                break;
        }
    
        if (request.type == ServerRequest_Type_DISC_CLOSE)
        {
            break;
        }
    }

    if (handle)
        scarletbook_close(handle);
        
    if (sacd_reader)
        sacd_close(sacd_reader);
    
    free(response.data.bytes);
    free(output_buf);
	
	closesocket((int) *client);
	client_connected = 0;
	
	sysThreadExit(0);
}