Source avrcpSourceFromData(AVRCP *avrcp, uint8 *data, uint16 length)
{
    /* Create a source from the data */
    Source src = StreamRegionSource(data, length);

    /* Register a task for freeing the data and store a ptr to it */
    avrcp->dataFreeTask.sent_data = data;
    MessageSinkTask(StreamSinkFromSource(src), &avrcp->dataFreeTask.cleanUpTask);

    return src;
}
static uint32 read_sectors(FileInfoType *file_info, uint32 logical_address, uint32 transfer_length, uint32 area_start_sector)
{
    uint32 start_sector;
    uint32 end_sector;
    uint32 file_end_sector = file_info->end_sector;
    uint16 i = 0;
    Sink sink = StreamUsbEndPointSink(end_point_bulk_out);
    
    /* correct end sector for FAT2, as it's otherwise treated as FAT1 */
    if (area_start_sector == FAT2_SECTOR)
        file_end_sector += SECTORS_PER_FAT;
    
    /* find the start sector and end sector for this type of data */
    start_sector = logical_address - area_start_sector;
    end_sector = start_sector + transfer_length - 1;
    if (end_sector > (file_end_sector - area_start_sector))
        end_sector = file_end_sector - area_start_sector;

    MS_DEBUG(("FAT16: start %ld end %ld fileend %ld log %ld areastart %ld\n",start_sector,end_sector,file_info->end_sector,logical_address,area_start_sector));
    
    /* check to see if the file read should begin at the start of the file */
    if ((file_info->src == 0) || (start_sector < file_info->current_start_sector))
    {
        if (file_info->params)
            file_info->src = StreamRegionSource(file_info->params, file_info->size);
        else
            file_info->src = StreamFileSource(file_info->index);
        file_info->current_start_sector = 0;
        
        MS_DEBUG(("FAT16: new file\n"));
    }
    
    /* seek through the file until the correct sector is reached */
    while ((start_sector > file_info->current_start_sector) && (file_info->current_start_sector < end_sector))
    {
        SourceDrop(file_info->src, BYTES_PER_SECTOR);
        file_info->current_start_sector++;   
        MS_DEBUG(("FAT16: src drop %ld\n",file_info->current_start_sector));
    }    
    
    /* send the data in the sectors from start_sector to end_sector */
    while (i <= (end_sector - start_sector))
    {
        uint8 *buffer = 0;
        uint16 sink_slack = 0;
        uint16 source_size;
        uint16 blocks_in_sink;
        uint16 blocks_in_source;
        uint16 blocks_to_read;
        uint32 bytes_to_read;
        uint32 remaining_bytes;
        uint16 bytes_to_copy = 0;          
        
        /* wait for free space in Sink */
        Fat16_WaitAvailable(sink, BYTES_PER_SECTOR);
        
        sink_slack = SinkSlack(sink);
        source_size = SourceSize(file_info->src);
        blocks_in_sink = sink_slack / BYTES_PER_SECTOR;
        
        /* find the maximum sectors that can be sent */
        if ((source_size % BYTES_PER_SECTOR) == 0)
            blocks_in_source = source_size / BYTES_PER_SECTOR;
        else
            blocks_in_source = source_size / BYTES_PER_SECTOR + 1;
        blocks_to_read = blocks_in_sink > blocks_in_source ? blocks_in_source : blocks_in_sink;
        if (blocks_to_read > (end_sector - i + 1))
            blocks_to_read = end_sector - i + 1;
        bytes_to_read = blocks_to_read * BYTES_PER_SECTOR;
        remaining_bytes = file_info->size - (file_info->current_start_sector * BYTES_PER_SECTOR);
        
        MS_DEBUG(("FAT16: info sink_slack:%d source_size:%d blocks_to_read:%d\n",sink_slack,source_size,blocks_to_read));
        
        if (blocks_to_read == 0)
            break;
        
        if (remaining_bytes < bytes_to_read)
            bytes_to_copy = remaining_bytes;
        else
            bytes_to_copy = bytes_to_read;
                             
        if ((buffer = claimSink(sink, bytes_to_read)) != 0)
        {            
            const uint8 *data_ptr = SourceMap(file_info->src);
            bool flush;

            if (bytes_to_copy < bytes_to_read)
                memset(buffer + bytes_to_copy, 0, bytes_to_read - bytes_to_copy); 
            memmove(buffer, data_ptr, bytes_to_copy);            
            SinkConfigure(sink, VM_SINK_USB_TRANSFER_LENGTH, bytes_to_read);
            flush = SinkFlush(sink, bytes_to_read);
            SourceDrop(file_info->src, bytes_to_copy);
            file_info->current_start_sector += blocks_to_read;
            i += blocks_to_read;
            MS_DEBUG(("FAT16: send bytes %d pos %ld i %d flush %d\n",bytes_to_copy,file_info->current_start_sector,i,flush));
        }   
        else
        {
            break;
        }
    }
    
    /* return the next logical address to process */
    return logical_address + end_sector - start_sector + 1;
}