Exemple #1
0
bool CCDDAStream::Load(const WCHAR* fnw)
{
    CString path(fnw);

    int iDriveLetter = path.Find(_T(":\\")) - 1;
    int iTrackIndex = CString(path).MakeLower().Find(_T(".cda")) - 1;
    if (iDriveLetter < 0 || iTrackIndex <= iDriveLetter) {
        return false;
    }

    CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":");
    while (iTrackIndex > 0 && _istdigit(path[iTrackIndex - 1])) {
        iTrackIndex--;
    }
    if (1 != _stscanf_s(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex)) {
        return false;
    }

    if (m_hDrive != INVALID_HANDLE_VALUE) {
        CloseHandle(m_hDrive);
        m_hDrive = INVALID_HANDLE_VALUE;
    }

    m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr,
                          OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr);
    if (m_hDrive == INVALID_HANDLE_VALUE) {
        return false;
    }

    DWORD BytesReturned;
    if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0)
            || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack)) {
        CloseHandle(m_hDrive);
        m_hDrive = INVALID_HANDLE_VALUE;
        return false;
    }

    // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field
    m_TOC.TrackData[iTrackIndex - 1].Control &= 5;
    if (!(m_TOC.TrackData[iTrackIndex - 1].Control == 0 || m_TOC.TrackData[iTrackIndex - 1].Control == 1)) {
        CloseHandle(m_hDrive);
        m_hDrive = INVALID_HANDLE_VALUE;
        return false;
    }

    if (m_TOC.TrackData[iTrackIndex - 1].Control & 8) {
        m_header.frm.pcm.wf.nChannels = 4;
    }

    m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex - 1].Address) - 150;
    m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150;

    m_llLength = LONGLONG(m_nStopSector - m_nStartSector) * RAW_SECTOR_SIZE;

    m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8);
    m_header.data.hdr.chunkSize = (long)(m_llLength);

    // Detect DTS Music Disk
    m_bDTS = false;

    // DCA syncwords
    const DWORD DCA_MARKER_RAW_BE = 0x7FFE8001;
    const DWORD DCA_MARKER_RAW_LE = 0xFE7F0180;
    const DWORD DCA_MARKER_14B_BE = 0x1FFFE800;
    const DWORD DCA_MARKER_14B_LE = 0xFF1F00E8;
    UINT nMarkerFound = 0, nAttempt = 0;
    DWORD marker = DWORD_MAX;

    std::vector<BYTE> data(16384);
    DWORD dwSizeRead = 0;
    while (SUCCEEDED(Read(data.data(), (DWORD)data.size(), TRUE, &dwSizeRead)) && dwSizeRead && nAttempt < (4 + nMarkerFound)) {
        nAttempt++;

        for (DWORD i = 0; i < dwSizeRead; i++) {
            marker = (marker << 8) | data[i];
            if ((marker == DCA_MARKER_14B_LE && (i < dwSizeRead - 2) && (data[i + 1] & 0xF0) == 0xF0 && data[i + 2] == 0x07)
                    || (marker == DCA_MARKER_14B_BE && (i < dwSizeRead - 2) && data[i + 1] == 0x07 && (data[i + 2] & 0xF0) == 0xF0)
                    || marker == DCA_MARKER_RAW_LE || marker == DCA_MARKER_RAW_BE) {
                nMarkerFound++;
            }
        }
        dwSizeRead = 0;

        if (nMarkerFound >= 4) {
            m_bDTS = true;
            break;
        }
    }
    SetPointer(0);

    CDROM_READ_TOC_EX TOCEx;
    ZeroMemory(&TOCEx, sizeof(TOCEx));
    TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT;
    BYTE header[4] = { 0 };
    static_assert(sizeof(header) >= MINIMUM_CDROM_READ_TOC_EX_SIZE, "sizeof(header) must be greater or equal to MINIMUM_CDROM_READ_TOC_EX_SIZE");
    if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), header, sizeof(header), &BytesReturned, 0)) {
        return true;
    }

    DWORD size = 2 + (WORD(header[0]) << 8) + header[1];
    if (size <= 4) { // No cd-text information
        return true;
    }

    CAutoVectorPtr<BYTE> pCDTextData;
    if (!pCDTextData.Allocate(size)) {
        return true;
    }
    ZeroMemory(pCDTextData, size);

    if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0)) {
        return true;
    }

    size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA));
    CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors;

    CStringArray str[16];
    for (int i = 0; i < _countof(str); i++) {
        str[i].SetSize(1 + m_TOC.LastTrack);
    }
    CString last;

    for (int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++) {
        if (pDesc->TrackNumber > m_TOC.LastTrack) {
            continue;
        }

        const int lenU = _countof(pDesc->Text);
        const int lenW = _countof(pDesc->WText);

        CString text = !pDesc->Unicode
                       ? CString(CStringA((CHAR*)pDesc->Text, lenU))
                       : CString(CStringW((WCHAR*)pDesc->WText, lenW));

        int tlen = text.GetLength();
        CString tmp = (tlen < 12 - 1)
                      ? (!pDesc->Unicode
                         ? CString(CStringA((CHAR*)pDesc->Text + tlen + 1, lenU - (tlen + 1)))
                         : CString(CStringW((WCHAR*)pDesc->WText + tlen + 1, lenW - (tlen + 1))))
                      : _T("");

        if (pDesc->PackType < 0x80 || pDesc->PackType >= 0x80 + 0x10) {
            continue;
        }
        pDesc->PackType -= 0x80;

        if (pDesc->CharacterPosition == 0) {
            str[pDesc->PackType][pDesc->TrackNumber] = text;
        } else { // pDesc->CharacterPosition <= 0xf since CharacterPosition is a 4-bit field
            if (pDesc->CharacterPosition < 0xf && !last.IsEmpty()) {
                str[pDesc->PackType][pDesc->TrackNumber] = last + text;
            } else {
                str[pDesc->PackType][pDesc->TrackNumber] += text;
            }
        }

        last = tmp;
    }

    m_discTitle = str[0][0];
    m_trackTitle = str[0][iTrackIndex];
    m_discArtist = str[1][0];
    m_trackArtist = str[1][iTrackIndex];

    return true;
}
bool		CDDAAudioSource::Open(const utfchar* source)
{
	TCHAR drive[32];
	int iTrackIndex;

	StrCpy(	drive, TEXT("\\\\.\\"));
    StrCatN(drive, &source[8], 2);
	StrCat(	drive, TEXT(":"));

	m_hDrive = CreateFile(	drive, 
							GENERIC_READ, 
							FILE_SHARE_READ, 
							NULL, 
							OPEN_EXISTING, 
							FILE_ATTRIBUTE_READONLY|FILE_FLAG_SEQUENTIAL_SCAN, 
							(HANDLE)NULL);

	if(m_hDrive == INVALID_HANDLE_VALUE)
	{
		return(false);
	}

    iTrackIndex = _wtoi(&source[10]);

	DWORD BytesReturned;
	if(!DeviceIoControl(	m_hDrive, 
							IOCTL_CDROM_READ_TOC, 
							NULL, 
							0, 
							&m_TOC, 
							sizeof(m_TOC), 
							&BytesReturned, 
							0)
	|| !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack))
	{
		CloseHandle(m_hDrive);
		m_hDrive = INVALID_HANDLE_VALUE;
		return(false);
	}

	// MMC-3 Draft Revision 10g: Table 222 – Q Sub-channel control field
	m_TOC.TrackData[iTrackIndex-1].Control &= 5;
	if(!(m_TOC.TrackData[iTrackIndex-1].Control == 0 || m_TOC.TrackData[iTrackIndex-1].Control == 1))
	{
		CloseHandle(m_hDrive);
		m_hDrive = INVALID_HANDLE_VALUE;
		return(false);
	}

	m_Channels = 2;
	if(m_TOC.TrackData[iTrackIndex-1].Control&8) 
		m_Channels = 4;

	m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex-1].Address) - 150;//MSF2UINT(m_TOC.TrackData[0].Address);
	m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150;//MSF2UINT(m_TOC.TrackData[0].Address);

	m_llLength = (m_nStopSector-m_nStartSector)*RAW_SECTOR_SIZE;

    this->sourcePath = source;

	return true;
}
bool CCDDAStream::Load(const WCHAR* fnw)
{
    CString path(fnw);

    int iDriveLetter = path.Find(_T(":\\")) - 1;
    int iTrackIndex = CString(path).MakeLower().Find(_T(".cda")) - 1;
    if (iDriveLetter < 0 || iTrackIndex <= iDriveLetter) {
        return false;
    }

    CString drive = CString(_T("\\\\.\\")) + path[iDriveLetter] + _T(":");
    while (iTrackIndex > 0 && _istdigit(path[iTrackIndex - 1])) {
        iTrackIndex--;
    }
    if (1 != _stscanf_s(path.Mid(iTrackIndex), _T("%d"), &iTrackIndex)) {
        return false;
    }

    if (m_hDrive != INVALID_HANDLE_VALUE) {
        CloseHandle(m_hDrive);
        m_hDrive = INVALID_HANDLE_VALUE;
    }

    m_hDrive = CreateFile(drive, GENERIC_READ, FILE_SHARE_READ, nullptr,
                          OPEN_EXISTING, FILE_ATTRIBUTE_READONLY | FILE_FLAG_SEQUENTIAL_SCAN, (HANDLE)nullptr);
    if (m_hDrive == INVALID_HANDLE_VALUE) {
        return false;
    }

    DWORD BytesReturned;
    if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC, nullptr, 0, &m_TOC, sizeof(m_TOC), &BytesReturned, 0)
            || !(m_TOC.FirstTrack <= iTrackIndex && iTrackIndex <= m_TOC.LastTrack)) {
        CloseHandle(m_hDrive);
        m_hDrive = INVALID_HANDLE_VALUE;
        return false;
    }

    // MMC-3 Draft Revision 10g: Table 222 - Q Sub-channel control field
    m_TOC.TrackData[iTrackIndex - 1].Control &= 5;
    if (!(m_TOC.TrackData[iTrackIndex - 1].Control == 0 || m_TOC.TrackData[iTrackIndex - 1].Control == 1)) {
        CloseHandle(m_hDrive);
        m_hDrive = INVALID_HANDLE_VALUE;
        return false;
    }

    if (m_TOC.TrackData[iTrackIndex - 1].Control & 8) {
        m_header.frm.pcm.wf.nChannels = 4;
    }

    m_nStartSector = MSF2UINT(m_TOC.TrackData[iTrackIndex - 1].Address) - 150; //MSF2UINT(m_TOC.TrackData[0].Address);
    m_nStopSector = MSF2UINT(m_TOC.TrackData[iTrackIndex].Address) - 150;//MSF2UINT(m_TOC.TrackData[0].Address);

    m_llLength = LONGLONG(m_nStopSector - m_nStartSector) * RAW_SECTOR_SIZE;

    m_header.riff.hdr.chunkSize = (long)(m_llLength + sizeof(m_header) - 8);
    m_header.data.hdr.chunkSize = (long)(m_llLength);

    do {
        CDROM_READ_TOC_EX TOCEx;
        ZeroMemory(&TOCEx, sizeof(TOCEx));
        TOCEx.Format = CDROM_READ_TOC_EX_FORMAT_CDTEXT;
        TOCEx.SessionTrack = iTrackIndex;
        WORD size = 0;
        ASSERT(MINIMUM_CDROM_READ_TOC_EX_SIZE == sizeof(size));
        if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), &size, sizeof(size), &BytesReturned, 0)) {
            break;
        }

        size = _byteswap_ushort(size) + sizeof(size);

        CAutoVectorPtr<BYTE> pCDTextData;
        if (!pCDTextData.Allocate(size)) {
            break;
        }
        ZeroMemory(pCDTextData, size);

        if (!DeviceIoControl(m_hDrive, IOCTL_CDROM_READ_TOC_EX, &TOCEx, sizeof(TOCEx), pCDTextData, size, &BytesReturned, 0)) {
            break;
        }

        size = (WORD)(BytesReturned - sizeof(CDROM_TOC_CD_TEXT_DATA));
        CDROM_TOC_CD_TEXT_DATA_BLOCK* pDesc = ((CDROM_TOC_CD_TEXT_DATA*)(BYTE*)pCDTextData)->Descriptors;

        CStringArray str[16];
        for (int i = 0; i < _countof(str); i++) {
            str[i].SetSize(1 + m_TOC.LastTrack);
        }
        CString last;

        for (int i = 0; size >= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK); i++, size -= sizeof(CDROM_TOC_CD_TEXT_DATA_BLOCK), pDesc++) {
            if (pDesc->TrackNumber > m_TOC.LastTrack) {
                continue;
            }

            const int lenU = _countof(pDesc->Text);
            const int lenW = _countof(pDesc->WText);

            CString text = !pDesc->Unicode
                           ? CString(CStringA((CHAR*)pDesc->Text, lenU))
                           : CString(CStringW((WCHAR*)pDesc->WText, lenW));

            int tlen = text.GetLength();
            CString tmp = (tlen < 12 - 1)
                          ? (!pDesc->Unicode
                             ? CString(CStringA((CHAR*)pDesc->Text + tlen + 1, lenU - (tlen + 1)))
                             : CString(CStringW((WCHAR*)pDesc->WText + tlen + 1, lenW - (tlen + 1))))
                          : _T("");

            if (pDesc->PackType < 0x80 || pDesc->PackType >= 0x80 + 0x10) {
                continue;
            }
            pDesc->PackType -= 0x80;

            if (pDesc->CharacterPosition == 0) {
                str[pDesc->PackType][pDesc->TrackNumber] = text;
            } else { // pDesc->CharacterPosition <= 0xf since CharacterPosition is a 4-bit field
                if (pDesc->CharacterPosition < 0xf && !last.IsEmpty()) {
                    str[pDesc->PackType][pDesc->TrackNumber] = last + text;
                } else {
                    str[pDesc->PackType][pDesc->TrackNumber] += text;
                }
            }

            last = tmp;
        }

        m_discTitle = str[0][0];
        m_trackTitle = str[0][iTrackIndex];
        m_discArtist = str[1][0];
        m_trackArtist = str[1][iTrackIndex];
    } while (0);


    return true;
}