mirror of
https://github.com/aaru-dps/Aaru.Server.git
synced 2025-12-16 19:24:27 +00:00
2574 lines
105 KiB
C#
2574 lines
105 KiB
C#
// /***************************************************************************
|
|
// The Disc Image Chef
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Filename : Nero.cs
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
//
|
|
// Component : Disc image plugins.
|
|
//
|
|
// --[ Description ] ----------------------------------------------------------
|
|
//
|
|
// Manages Nero Burning ROM disc images.
|
|
//
|
|
// --[ License ] --------------------------------------------------------------
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as
|
|
// published by the Free Software Foundation; either version 2.1 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This library is distributed in the hope that it will be useful, but
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
// Copyright © 2011-2017 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
using System;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using DiscImageChef.Console;
|
|
using DiscImageChef.CommonTypes;
|
|
using DiscImageChef.Filters;
|
|
|
|
namespace DiscImageChef.ImagePlugins
|
|
{
|
|
class Nero : ImagePlugin
|
|
{
|
|
#region Internal structures
|
|
|
|
struct NeroV1Footer
|
|
{
|
|
/// <summary>
|
|
/// "NERO"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Offset of first chunk in file
|
|
/// </summary>
|
|
public uint FirstChunkOffset;
|
|
}
|
|
|
|
struct NeroV2Footer
|
|
{
|
|
/// <summary>
|
|
/// "NER5"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Offset of first chunk in file
|
|
/// </summary>
|
|
public ulong FirstChunkOffset;
|
|
}
|
|
|
|
struct NeroV2CueEntry
|
|
{
|
|
/// <summary>
|
|
/// Track mode. 0x01 for audio, 0x21 for copy-protected audio, 0x41 for data
|
|
/// </summary>
|
|
public byte Mode;
|
|
|
|
/// <summary>
|
|
/// Track number in BCD
|
|
/// </summary>
|
|
public byte TrackNumber;
|
|
|
|
/// <summary>
|
|
/// Index number in BCD
|
|
/// </summary>
|
|
public byte IndexNumber;
|
|
|
|
/// <summary>
|
|
/// Always zero
|
|
/// </summary>
|
|
public byte Dummy;
|
|
|
|
/// <summary>
|
|
/// LBA sector start for this entry
|
|
/// </summary>
|
|
public int LBAStart;
|
|
}
|
|
|
|
struct NeroV2Cuesheet
|
|
{
|
|
/// <summary>
|
|
/// "CUEX"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Cuesheet entries
|
|
/// </summary>
|
|
public List<NeroV2CueEntry> Entries;
|
|
}
|
|
|
|
struct NeroV1CueEntry
|
|
{
|
|
/// <summary>
|
|
/// Track mode. 0x01 for audio, 0x21 for copy-protected audio, 0x41 for data
|
|
/// </summary>
|
|
public byte Mode;
|
|
|
|
/// <summary>
|
|
/// Track number in BCD
|
|
/// </summary>
|
|
public byte TrackNumber;
|
|
|
|
/// <summary>
|
|
/// Index number in BCD
|
|
/// </summary>
|
|
public byte IndexNumber;
|
|
|
|
/// <summary>
|
|
/// Always zero
|
|
/// </summary>
|
|
public ushort Dummy;
|
|
|
|
/// <summary>
|
|
/// MSF start sector's minute for this entry
|
|
/// </summary>
|
|
public byte Minute;
|
|
|
|
/// <summary>
|
|
/// MSF start sector's second for this entry
|
|
/// </summary>
|
|
public byte Second;
|
|
|
|
/// <summary>
|
|
/// MSF start sector's frame for this entry
|
|
/// </summary>
|
|
public byte Frame;
|
|
}
|
|
|
|
struct NeroV1Cuesheet
|
|
{
|
|
/// <summary>
|
|
/// "CUES"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Cuesheet entries
|
|
/// </summary>
|
|
public List<NeroV1CueEntry> Entries;
|
|
}
|
|
|
|
struct NeroV1DAOEntry
|
|
{
|
|
/// <summary>
|
|
/// ISRC (12 bytes)
|
|
/// </summary>
|
|
public byte[] ISRC;
|
|
|
|
/// <summary>
|
|
/// Size of sector inside image (in bytes)
|
|
/// </summary>
|
|
public ushort SectorSize;
|
|
|
|
/// <summary>
|
|
/// Sector mode in image
|
|
/// </summary>
|
|
public ushort Mode;
|
|
|
|
/// <summary>
|
|
/// Unknown
|
|
/// </summary>
|
|
public ushort Unknown;
|
|
|
|
/// <summary>
|
|
/// Index 0 start
|
|
/// </summary>
|
|
public uint Index0;
|
|
|
|
/// <summary>
|
|
/// Index 1 start
|
|
/// </summary>
|
|
public uint Index1;
|
|
|
|
/// <summary>
|
|
/// End of track + 1
|
|
/// </summary>
|
|
public uint EndOfTrack;
|
|
}
|
|
|
|
struct NeroV1DAO
|
|
{
|
|
/// <summary>
|
|
/// "DAOI"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size (big endian)
|
|
/// </summary>
|
|
public uint ChunkSizeBe;
|
|
|
|
/// <summary>
|
|
/// Chunk size (little endian)
|
|
/// </summary>
|
|
public uint ChunkSizeLe;
|
|
|
|
/// <summary>
|
|
/// UPC (14 bytes, null-padded)
|
|
/// </summary>
|
|
public byte[] UPC;
|
|
|
|
/// <summary>
|
|
/// TOC type
|
|
/// </summary>
|
|
public ushort TocType;
|
|
|
|
/// <summary>
|
|
/// First track
|
|
/// </summary>
|
|
public byte FirstTrack;
|
|
|
|
/// <summary>
|
|
/// Last track
|
|
/// </summary>
|
|
public byte LastTrack;
|
|
|
|
/// <summary>
|
|
/// Tracks
|
|
/// </summary>
|
|
public List<NeroV1DAOEntry> Tracks;
|
|
}
|
|
|
|
struct NeroV2DAOEntry
|
|
{
|
|
/// <summary>
|
|
/// ISRC (12 bytes)
|
|
/// </summary>
|
|
public byte[] ISRC;
|
|
|
|
/// <summary>
|
|
/// Size of sector inside image (in bytes)
|
|
/// </summary>
|
|
public ushort SectorSize;
|
|
|
|
/// <summary>
|
|
/// Sector mode in image
|
|
/// </summary>
|
|
public ushort Mode;
|
|
|
|
/// <summary>
|
|
/// Seems to be always 0.
|
|
/// </summary>
|
|
public ushort Unknown;
|
|
|
|
/// <summary>
|
|
/// Index 0 start
|
|
/// </summary>
|
|
public ulong Index0;
|
|
|
|
/// <summary>
|
|
/// Index 1 start
|
|
/// </summary>
|
|
public ulong Index1;
|
|
|
|
/// <summary>
|
|
/// End of track + 1
|
|
/// </summary>
|
|
public ulong EndOfTrack;
|
|
}
|
|
|
|
struct NeroV2DAO
|
|
{
|
|
/// <summary>
|
|
/// "DAOX"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size (big endian)
|
|
/// </summary>
|
|
public uint ChunkSizeBe;
|
|
|
|
/// <summary>
|
|
/// Chunk size (little endian)
|
|
/// </summary>
|
|
public uint ChunkSizeLe;
|
|
|
|
/// <summary>
|
|
/// UPC (14 bytes, null-padded)
|
|
/// </summary>
|
|
public byte[] UPC;
|
|
|
|
/// <summary>
|
|
/// TOC type
|
|
/// </summary>
|
|
public ushort TocType;
|
|
|
|
/// <summary>
|
|
/// First track
|
|
/// </summary>
|
|
public byte FirstTrack;
|
|
|
|
/// <summary>
|
|
/// Last track
|
|
/// </summary>
|
|
public byte LastTrack;
|
|
|
|
/// <summary>
|
|
/// Tracks
|
|
/// </summary>
|
|
public List<NeroV2DAOEntry> Tracks;
|
|
}
|
|
|
|
struct NeroCDTextPack
|
|
{
|
|
/// <summary>
|
|
/// Pack type
|
|
/// </summary>
|
|
public byte PackType;
|
|
|
|
/// <summary>
|
|
/// Track number
|
|
/// </summary>
|
|
public byte TrackNumber;
|
|
|
|
/// <summary>
|
|
/// Pack number in block
|
|
/// </summary>
|
|
public byte PackNumber;
|
|
|
|
/// <summary>
|
|
/// Block number
|
|
/// </summary>
|
|
public byte BlockNumber;
|
|
|
|
/// <summary>
|
|
/// 12 bytes of data
|
|
/// </summary>
|
|
public byte[] Text;
|
|
|
|
/// <summary>
|
|
/// CRC
|
|
/// </summary>
|
|
public ushort CRC;
|
|
}
|
|
|
|
struct NeroCDText
|
|
{
|
|
/// <summary>
|
|
/// "CDTX"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// CD-TEXT packs
|
|
/// </summary>
|
|
public List<NeroCDTextPack> Packs;
|
|
}
|
|
|
|
struct NeroV1TAOEntry
|
|
{
|
|
/// <summary>
|
|
/// Offset of track on image
|
|
/// </summary>
|
|
public uint Offset;
|
|
|
|
/// <summary>
|
|
/// Length of track in bytes
|
|
/// </summary>
|
|
public uint Length;
|
|
|
|
/// <summary>
|
|
/// Track mode
|
|
/// </summary>
|
|
public uint Mode;
|
|
|
|
/// <summary>
|
|
/// LBA track start (plus 150 lead in sectors)
|
|
/// </summary>
|
|
public uint StartLBA;
|
|
|
|
/// <summary>
|
|
/// Unknown
|
|
/// </summary>
|
|
public uint Unknown;
|
|
}
|
|
|
|
struct NeroV1TAO
|
|
{
|
|
/// <summary>
|
|
/// "ETNF"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// CD-TEXT packs
|
|
/// </summary>
|
|
public List<NeroV1TAOEntry> Tracks;
|
|
}
|
|
|
|
struct NeroV2TAOEntry
|
|
{
|
|
/// <summary>
|
|
/// Offset of track on image
|
|
/// </summary>
|
|
public ulong Offset;
|
|
|
|
/// <summary>
|
|
/// Length of track in bytes
|
|
/// </summary>
|
|
public ulong Length;
|
|
|
|
/// <summary>
|
|
/// Track mode
|
|
/// </summary>
|
|
public uint Mode;
|
|
|
|
/// <summary>
|
|
/// LBA track start (plus 150 lead in sectors)
|
|
/// </summary>
|
|
public uint StartLBA;
|
|
|
|
/// <summary>
|
|
/// Unknown
|
|
/// </summary>
|
|
public uint Unknown;
|
|
|
|
/// <summary>
|
|
/// Track length in sectors
|
|
/// </summary>
|
|
public uint Sectors;
|
|
}
|
|
|
|
struct NeroV2TAO
|
|
{
|
|
/// <summary>
|
|
/// "ETN2"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// CD-TEXT packs
|
|
/// </summary>
|
|
public List<NeroV2TAOEntry> Tracks;
|
|
}
|
|
|
|
struct NeroSession
|
|
{
|
|
/// <summary>
|
|
/// "SINF"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Tracks in session
|
|
/// </summary>
|
|
public uint Tracks;
|
|
}
|
|
|
|
struct NeroMediaType
|
|
{
|
|
/// <summary>
|
|
/// "MTYP"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Media type
|
|
/// </summary>
|
|
public uint Type;
|
|
}
|
|
|
|
struct NeroDiscInformation
|
|
{
|
|
/// <summary>
|
|
/// "DINF"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Unknown
|
|
/// </summary>
|
|
public uint Unknown;
|
|
}
|
|
|
|
struct NeroTOCChunk
|
|
{
|
|
/// <summary>
|
|
/// "TOCT"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Unknown
|
|
/// </summary>
|
|
public ushort Unknown;
|
|
}
|
|
|
|
struct NeroRELOChunk
|
|
{
|
|
/// <summary>
|
|
/// "RELO"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
|
|
/// <summary>
|
|
/// Unknown
|
|
/// </summary>
|
|
public uint Unknown;
|
|
}
|
|
|
|
struct NeroEndOfChunkChain
|
|
{
|
|
/// <summary>
|
|
/// "END!"
|
|
/// </summary>
|
|
public uint ChunkID;
|
|
|
|
/// <summary>
|
|
/// Chunk size
|
|
/// </summary>
|
|
public uint ChunkSize;
|
|
}
|
|
|
|
// Internal use only
|
|
struct NeroTrack
|
|
{
|
|
public byte[] ISRC;
|
|
public ushort SectorSize;
|
|
public ulong Offset;
|
|
public ulong Length;
|
|
public ulong EndOfTrack;
|
|
public uint Mode;
|
|
public ulong StartLBA;
|
|
public ulong Sectors;
|
|
public ulong Index0;
|
|
public ulong Index1;
|
|
public uint Sequence;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Internal consts
|
|
|
|
// "NERO"
|
|
public const uint NeroV1FooterID = 0x4E45524F;
|
|
|
|
// "NER5"
|
|
public const uint NeroV2FooterID = 0x4E455235;
|
|
|
|
// "CUES"
|
|
public const uint NeroV1CUEID = 0x43554553;
|
|
|
|
// "CUEX"
|
|
public const uint NeroV2CUEID = 0x43554558;
|
|
|
|
// "ETNF"
|
|
public const uint NeroV1TAOID = 0x45544E46;
|
|
|
|
// "ETN2"
|
|
public const uint NeroV2TAOID = 0x45544E32;
|
|
|
|
// "DAOI"
|
|
public const uint NeroV1DAOID = 0x44414F49;
|
|
|
|
// "DAOX"
|
|
public const uint NeroV2DAOID = 0x44414F58;
|
|
|
|
// "CDTX"
|
|
public const uint NeroCDTextID = 0x43445458;
|
|
|
|
// "SINF"
|
|
public const uint NeroSessionID = 0x53494E46;
|
|
|
|
// "MTYP"
|
|
public const uint NeroDiskTypeID = 0x4D545950;
|
|
|
|
// "DINF"
|
|
public const uint NeroDiscInfoID = 0x44494E46;
|
|
|
|
// "TOCT"
|
|
public const uint NeroTOCID = 0x544F4354;
|
|
|
|
// "RELO"
|
|
public const uint NeroReloID = 0x52454C4F;
|
|
|
|
// "END!"
|
|
public const uint NeroEndID = 0x454E4421;
|
|
|
|
public enum DAOMode : ushort
|
|
{
|
|
Data = 0x0000,
|
|
DataM2F1 = 0x0002,
|
|
DataM2F2 = 0x0003,
|
|
DataRaw = 0x0005,
|
|
DataM2Raw = 0x0006,
|
|
Audio = 0x0007,
|
|
DataRawSub = 0x000F,
|
|
AudioSub = 0x0010,
|
|
DataM2RawSub = 0x0011
|
|
}
|
|
|
|
[Flags]
|
|
public enum NeroMediaTypes : uint
|
|
{
|
|
/// <summary>
|
|
/// No media
|
|
/// </summary>
|
|
NERO_MTYP_NONE = 0x00000,
|
|
/// <summary>
|
|
/// CD-R/RW
|
|
/// </summary>
|
|
NERO_MTYP_CD = 0x00001,
|
|
/// <summary>
|
|
/// DDCD-R/RW
|
|
/// </summary>
|
|
NERO_MTYP_DDCD = 0x00002,
|
|
/// <summary>
|
|
/// DVD-R/RW
|
|
/// </summary>
|
|
NERO_MTYP_DVD_M = 0x00004,
|
|
/// <summary>
|
|
/// DVD+RW
|
|
/// </summary>
|
|
NERO_MTYP_DVD_P = 0x00008,
|
|
/// <summary>
|
|
/// DVD-RAM
|
|
/// </summary>
|
|
NERO_MTYP_DVD_RAM = 0x00010,
|
|
/// <summary>
|
|
/// Multi-level disc
|
|
/// </summary>
|
|
NERO_MTYP_ML = 0x00020,
|
|
/// <summary>
|
|
/// Mount Rainier
|
|
/// </summary>
|
|
NERO_MTYP_MRW = 0x00040,
|
|
/// <summary>
|
|
/// Exclude CD-R
|
|
/// </summary>
|
|
NERO_MTYP_NO_CDR = 0x00080,
|
|
/// <summary>
|
|
/// Exclude CD-RW
|
|
/// </summary>
|
|
NERO_MTYP_NO_CDRW = 0x00100,
|
|
/// <summary>
|
|
/// CD-RW
|
|
/// </summary>
|
|
NERO_MTYP_CDRW = NERO_MTYP_CD | NERO_MTYP_NO_CDR,
|
|
/// <summary>
|
|
/// CD-R
|
|
/// </summary>
|
|
NERO_MTYP_CDR = NERO_MTYP_CD | NERO_MTYP_NO_CDRW,
|
|
/// <summary>
|
|
/// DVD-ROM
|
|
/// </summary>
|
|
NERO_MTYP_DVD_ROM = 0x00200,
|
|
/// <summary>
|
|
/// CD-ROM
|
|
/// </summary>
|
|
NERO_MTYP_CDROM = 0x00400,
|
|
/// <summary>
|
|
/// Exclude DVD-RW
|
|
/// </summary>
|
|
NERO_MTYP_NO_DVD_M_RW = 0x00800,
|
|
/// <summary>
|
|
/// Exclude DVD-R
|
|
/// </summary>
|
|
NERO_MTYP_NO_DVD_M_R = 0x01000,
|
|
/// <summary>
|
|
/// Exclude DVD+RW
|
|
/// </summary>
|
|
NERO_MTYP_NO_DVD_P_RW = 0x02000,
|
|
/// <summary>
|
|
/// Exclude DVD+R
|
|
/// </summary>
|
|
NERO_MTYP_NO_DVD_P_R = 0x04000,
|
|
/// <summary>
|
|
/// DVD-R
|
|
/// </summary>
|
|
NERO_MTYP_DVD_M_R = NERO_MTYP_DVD_M | NERO_MTYP_NO_DVD_M_RW,
|
|
/// <summary>
|
|
/// DVD-RW
|
|
/// </summary>
|
|
NERO_MTYP_DVD_M_RW = NERO_MTYP_DVD_M | NERO_MTYP_NO_DVD_M_R,
|
|
/// <summary>
|
|
/// DVD+R
|
|
/// </summary>
|
|
NERO_MTYP_DVD_P_R = NERO_MTYP_DVD_P | NERO_MTYP_NO_DVD_P_RW,
|
|
/// <summary>
|
|
/// DVD+RW
|
|
/// </summary>
|
|
NERO_MTYP_DVD_P_RW = NERO_MTYP_DVD_P | NERO_MTYP_NO_DVD_P_R,
|
|
/// <summary>
|
|
/// Packet-writing (fixed)
|
|
/// </summary>
|
|
NERO_MTYP_FPACKET = 0x08000,
|
|
/// <summary>
|
|
/// Packet-writing (variable)
|
|
/// </summary>
|
|
NERO_MTYP_VPACKET = 0x10000,
|
|
/// <summary>
|
|
/// Packet-writing (any)
|
|
/// </summary>
|
|
NERO_MTYP_PACKETW = NERO_MTYP_MRW | NERO_MTYP_FPACKET | NERO_MTYP_VPACKET,
|
|
/// <summary>
|
|
/// HD-Burn
|
|
/// </summary>
|
|
NERO_MTYP_HDB = 0x20000,
|
|
/// <summary>
|
|
/// DVD+R DL
|
|
/// </summary>
|
|
NERO_MTYP_DVD_P_R9 = 0x40000,
|
|
/// <summary>
|
|
/// DVD-R DL
|
|
/// </summary>
|
|
NERO_MTYP_DVD_M_R9 = 0x80000,
|
|
/// <summary>
|
|
/// Any DVD double-layer
|
|
/// </summary>
|
|
NERO_MTYP_DVD_ANY_R9 = NERO_MTYP_DVD_P_R9 | NERO_MTYP_DVD_M_R9,
|
|
/// <summary>
|
|
/// Any DVD
|
|
/// </summary>
|
|
NERO_MTYP_DVD_ANY = NERO_MTYP_DVD_M | NERO_MTYP_DVD_P | NERO_MTYP_DVD_RAM | NERO_MTYP_DVD_ANY_R9,
|
|
/// <summary>
|
|
/// BD-ROM
|
|
/// </summary>
|
|
NERO_MTYP_BD_ROM = 0x100000,
|
|
/// <summary>
|
|
/// BD-R
|
|
/// </summary>
|
|
NERO_MTYP_BD_R = 0x200000,
|
|
/// <summary>
|
|
/// BD-RE
|
|
/// </summary>
|
|
NERO_MTYP_BD_RE = 0x400000,
|
|
/// <summary>
|
|
/// BD-R/RE
|
|
/// </summary>
|
|
NERO_MTYP_BD = NERO_MTYP_BD_R | NERO_MTYP_BD_RE,
|
|
/// <summary>
|
|
/// Any BD
|
|
/// </summary>
|
|
NERO_MTYP_BD_ANY = NERO_MTYP_BD | NERO_MTYP_BD_ROM,
|
|
/// <summary>
|
|
/// HD DVD-ROM
|
|
/// </summary>
|
|
NERO_MTYP_HD_DVD_ROM = 0x0800000,
|
|
/// <summary>
|
|
/// HD DVD-R
|
|
/// </summary>
|
|
NERO_MTYP_HD_DVD_R = 0x1000000,
|
|
/// <summary>
|
|
/// HD DVD-RW
|
|
/// </summary>
|
|
NERO_MTYP_HD_DVD_RW = 0x2000000,
|
|
/// <summary>
|
|
/// HD DVD-R/RW
|
|
/// </summary>
|
|
NERO_MTYP_HD_DVD = NERO_MTYP_HD_DVD_R | NERO_MTYP_HD_DVD_RW,
|
|
/// <summary>
|
|
/// Any HD DVD
|
|
/// </summary>
|
|
NERO_MTYP_HD_DVD_ANY = NERO_MTYP_HD_DVD | NERO_MTYP_HD_DVD_ROM,
|
|
/// <summary>
|
|
/// Any DVD, old
|
|
/// </summary>
|
|
NERO_MTYP_DVD_ANY_OLD = NERO_MTYP_DVD_M | NERO_MTYP_DVD_P | NERO_MTYP_DVD_RAM,
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Internal variables
|
|
|
|
Filter _imageFilter;
|
|
Stream imageStream;
|
|
bool imageNewFormat;
|
|
Dictionary<ushort, uint> neroSessions;
|
|
NeroV1Cuesheet neroCuesheetV1;
|
|
NeroV2Cuesheet neroCuesheetV2;
|
|
NeroV1DAO neroDAOV1;
|
|
NeroV2DAO neroDAOV2;
|
|
NeroCDText neroCDTXT;
|
|
NeroV1TAO neroTAOV1;
|
|
NeroV2TAO neroTAOV2;
|
|
NeroMediaType neroMediaTyp;
|
|
NeroDiscInformation neroDiscInfo;
|
|
NeroTOCChunk neroTOC;
|
|
NeroRELOChunk neroRELO;
|
|
|
|
List<Track> imageTracks;
|
|
Dictionary<uint, byte[]> TrackISRCs;
|
|
byte[] UPC;
|
|
Dictionary<uint, NeroTrack> neroTracks;
|
|
Dictionary<uint, ulong> offsetmap;
|
|
List<Session> imageSessions;
|
|
List<Partition> ImagePartitions;
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
public Nero()
|
|
{
|
|
Name = "Nero Burning ROM image";
|
|
PluginUUID = new Guid("D160F9FF-5941-43FC-B037-AD81DD141F05");
|
|
imageNewFormat = false;
|
|
ImageInfo = new ImageInfo();
|
|
ImageInfo.readableSectorTags = new List<SectorTagType>();
|
|
ImageInfo.readableMediaTags = new List<MediaTagType>();
|
|
neroSessions = new Dictionary<ushort, uint>();
|
|
neroTracks = new Dictionary<uint, NeroTrack>();
|
|
offsetmap = new Dictionary<uint, ulong>();
|
|
imageSessions = new List<Session>();
|
|
ImagePartitions = new List<Partition>();
|
|
}
|
|
|
|
// Due to .cue format, this method must parse whole file, ignoring errors (those will be thrown by OpenImage()).
|
|
public override bool IdentifyImage(Filter imageFilter)
|
|
{
|
|
imageStream = imageFilter.GetDataForkStream();
|
|
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
|
|
|
byte[] buffer;
|
|
NeroV1Footer footerV1 = new NeroV1Footer();
|
|
NeroV2Footer footerV2 = new NeroV2Footer();
|
|
|
|
imageStream.Seek(-8, SeekOrigin.End);
|
|
buffer = new byte[8];
|
|
imageStream.Read(buffer, 0, 8);
|
|
footerV1.ChunkID = BigEndianBitConverter.ToUInt32(buffer, 0);
|
|
footerV1.FirstChunkOffset = BigEndianBitConverter.ToUInt32(buffer, 4);
|
|
|
|
imageStream.Seek(-12, SeekOrigin.End);
|
|
buffer = new byte[12];
|
|
imageStream.Read(buffer, 0, 12);
|
|
footerV2.ChunkID = BigEndianBitConverter.ToUInt32(buffer, 0);
|
|
footerV2.FirstChunkOffset = BigEndianBitConverter.ToUInt64(buffer, 4);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "imageStream.Length = {0}", imageStream.Length);
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV1.ChunkID = 0x{0:X8}", footerV1.ChunkID);
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV1.FirstChunkOffset = {0}", footerV1.FirstChunkOffset);
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV2.ChunkID = 0x{0:X8}", footerV2.ChunkID);
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV2.FirstChunkOffset = {0}", footerV2.FirstChunkOffset);
|
|
|
|
if(footerV2.ChunkID == NeroV2FooterID && footerV2.FirstChunkOffset < (ulong)imageStream.Length)
|
|
{
|
|
return true;
|
|
}
|
|
if(footerV1.ChunkID == NeroV1FooterID && footerV1.FirstChunkOffset < (ulong)imageStream.Length)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public override bool OpenImage(Filter imageFilter)
|
|
{
|
|
try
|
|
{
|
|
imageStream = imageFilter.GetDataForkStream();
|
|
BigEndianBitConverter.IsLittleEndian = BitConverter.IsLittleEndian;
|
|
|
|
byte[] buffer;
|
|
NeroV1Footer footerV1 = new NeroV1Footer();
|
|
NeroV2Footer footerV2 = new NeroV2Footer();
|
|
|
|
imageStream.Seek(-8, SeekOrigin.End);
|
|
buffer = new byte[8];
|
|
imageStream.Read(buffer, 0, 8);
|
|
footerV1.ChunkID = BigEndianBitConverter.ToUInt32(buffer, 0);
|
|
footerV1.FirstChunkOffset = BigEndianBitConverter.ToUInt32(buffer, 4);
|
|
|
|
imageStream.Seek(-12, SeekOrigin.End);
|
|
buffer = new byte[12];
|
|
imageStream.Read(buffer, 0, 12);
|
|
footerV2.ChunkID = BigEndianBitConverter.ToUInt32(buffer, 0);
|
|
footerV2.FirstChunkOffset = BigEndianBitConverter.ToUInt64(buffer, 4);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "imageStream.Length = {0}", imageStream.Length);
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV1.ChunkID = 0x{0:X8} (\"{1}\")", footerV1.ChunkID, System.Text.Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(footerV1.ChunkID)));
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV1.FirstChunkOffset = {0}", footerV1.FirstChunkOffset);
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV2.ChunkID = 0x{0:X8} (\"{1}\")", footerV2.ChunkID, System.Text.Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(footerV2.ChunkID)));
|
|
DicConsole.DebugWriteLine("Nero plugin", "footerV2.FirstChunkOffset = {0}", footerV2.FirstChunkOffset);
|
|
|
|
if(footerV1.ChunkID == NeroV1FooterID && footerV1.FirstChunkOffset < (ulong)imageStream.Length)
|
|
imageNewFormat = false;
|
|
else if(footerV2.ChunkID == NeroV2FooterID && footerV2.FirstChunkOffset < (ulong)imageStream.Length)
|
|
imageNewFormat = true;
|
|
else
|
|
return false;
|
|
|
|
if(imageNewFormat)
|
|
imageStream.Seek((long)footerV2.FirstChunkOffset, SeekOrigin.Begin);
|
|
else
|
|
imageStream.Seek(footerV1.FirstChunkOffset, SeekOrigin.Begin);
|
|
|
|
bool parsing = true;
|
|
ushort currentsession = 1;
|
|
uint currenttrack = 1;
|
|
|
|
imageTracks = new List<Track>();
|
|
TrackISRCs = new Dictionary<uint, byte[]>();
|
|
|
|
ImageInfo.mediaType = MediaType.CD;
|
|
ImageInfo.sectors = 0;
|
|
ImageInfo.sectorSize = 0;
|
|
|
|
while(parsing)
|
|
{
|
|
byte[] ChunkHeaderBuffer = new byte[8];
|
|
uint ChunkID;
|
|
uint ChunkLength;
|
|
|
|
imageStream.Read(ChunkHeaderBuffer, 0, 8);
|
|
ChunkID = BigEndianBitConverter.ToUInt32(ChunkHeaderBuffer, 0);
|
|
ChunkLength = BigEndianBitConverter.ToUInt32(ChunkHeaderBuffer, 4);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "ChunkID = 0x{0:X8} (\"{1}\")", ChunkID, System.Text.Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(ChunkID)));
|
|
DicConsole.DebugWriteLine("Nero plugin", "ChunkLength = {0}", ChunkLength);
|
|
|
|
switch(ChunkID)
|
|
{
|
|
case NeroV1CUEID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"CUES\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroCuesheetV1 = new NeroV1Cuesheet();
|
|
neroCuesheetV1.ChunkID = ChunkID;
|
|
neroCuesheetV1.ChunkSize = ChunkLength;
|
|
neroCuesheetV1.Entries = new List<NeroV1CueEntry>();
|
|
|
|
byte[] tmpbuffer = new byte[8];
|
|
for(int i = 0; i < neroCuesheetV1.ChunkSize; i += 8)
|
|
{
|
|
NeroV1CueEntry _entry = new NeroV1CueEntry();
|
|
imageStream.Read(tmpbuffer, 0, 8);
|
|
_entry.Mode = tmpbuffer[0];
|
|
_entry.TrackNumber = tmpbuffer[1];
|
|
_entry.IndexNumber = tmpbuffer[2];
|
|
_entry.Dummy = BigEndianBitConverter.ToUInt16(tmpbuffer, 3);
|
|
_entry.Minute = tmpbuffer[5];
|
|
_entry.Second = tmpbuffer[6];
|
|
_entry.Frame = tmpbuffer[7];
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Cuesheet entry {0}", (i / 8) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1:X2}", (i / 8) + 1, _entry.Mode);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].TrackNumber = {1:X2}", (i / 8) + 1, _entry.TrackNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].IndexNumber = {1:X2}", (i / 8) + 1, _entry.IndexNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Dummy = {1:X4}", (i / 8) + 1, _entry.Dummy);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Minute = {1:X2}", (i / 8) + 1, _entry.Minute);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Second = {1:X2}", (i / 8) + 1, _entry.Second);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Frame = {1:X2}", (i / 8) + 1, _entry.Frame);
|
|
|
|
neroCuesheetV1.Entries.Add(_entry);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroV2CUEID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"CUEX\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroCuesheetV2 = new NeroV2Cuesheet();
|
|
neroCuesheetV2.ChunkID = ChunkID;
|
|
neroCuesheetV2.ChunkSize = ChunkLength;
|
|
neroCuesheetV2.Entries = new List<NeroV2CueEntry>();
|
|
|
|
byte[] tmpbuffer = new byte[8];
|
|
for(int i = 0; i < neroCuesheetV2.ChunkSize; i += 8)
|
|
{
|
|
NeroV2CueEntry _entry = new NeroV2CueEntry();
|
|
imageStream.Read(tmpbuffer, 0, 8);
|
|
_entry.Mode = tmpbuffer[0];
|
|
_entry.TrackNumber = tmpbuffer[1];
|
|
_entry.IndexNumber = tmpbuffer[2];
|
|
_entry.Dummy = tmpbuffer[3];
|
|
_entry.LBAStart = BigEndianBitConverter.ToInt32(tmpbuffer, 4);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Cuesheet entry {0}", (i / 8) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = 0x{1:X2}", (i / 8) + 1, _entry.Mode);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].TrackNumber = {1:X2}", (i / 8) + 1, _entry.TrackNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].IndexNumber = {1:X2}", (i / 8) + 1, _entry.IndexNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Dummy = {1:X2}", (i / 8) + 1, _entry.Dummy);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].LBAStart = {1}", (i / 8) + 1, _entry.LBAStart);
|
|
|
|
neroCuesheetV2.Entries.Add(_entry);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroV1DAOID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"DAOI\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroDAOV1 = new NeroV1DAO();
|
|
neroDAOV1.ChunkID = ChunkID;
|
|
neroDAOV1.ChunkSizeBe = ChunkLength;
|
|
|
|
byte[] tmpbuffer = new byte[22];
|
|
imageStream.Read(tmpbuffer, 0, 22);
|
|
neroDAOV1.ChunkSizeLe = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
neroDAOV1.UPC = new byte[14];
|
|
Array.Copy(tmpbuffer, 4, neroDAOV1.UPC, 0, 14);
|
|
neroDAOV1.TocType = BigEndianBitConverter.ToUInt16(tmpbuffer, 18);
|
|
neroDAOV1.FirstTrack = tmpbuffer[20];
|
|
neroDAOV1.LastTrack = tmpbuffer[21];
|
|
neroDAOV1.Tracks = new List<NeroV1DAOEntry>();
|
|
|
|
if(!ImageInfo.readableMediaTags.Contains(MediaTagType.CD_MCN))
|
|
ImageInfo.readableMediaTags.Add(MediaTagType.CD_MCN);
|
|
|
|
if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDTrackISRC))
|
|
ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackISRC);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV1.ChunkSizeLe = {0} bytes", neroDAOV1.ChunkSizeLe);
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV1.UPC = \"{0}\"", StringHandlers.CToString(neroDAOV1.UPC));
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV1.TocType = 0x{0:X4}", neroDAOV1.TocType);
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV1.FirstTrack = {0}", neroDAOV1.FirstTrack);
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV1.LastTrack = {0}", neroDAOV1.LastTrack);
|
|
|
|
UPC = neroDAOV1.UPC;
|
|
|
|
tmpbuffer = new byte[30];
|
|
for(int i = 0; i < (neroDAOV1.ChunkSizeBe - 22); i += 30)
|
|
{
|
|
NeroV1DAOEntry _entry = new NeroV1DAOEntry();
|
|
imageStream.Read(tmpbuffer, 0, 30);
|
|
_entry.ISRC = new byte[12];
|
|
Array.Copy(tmpbuffer, 4, _entry.ISRC, 0, 12);
|
|
_entry.SectorSize = BigEndianBitConverter.ToUInt16(tmpbuffer, 12);
|
|
_entry.Mode = BitConverter.ToUInt16(tmpbuffer, 14);
|
|
_entry.Unknown = BigEndianBitConverter.ToUInt16(tmpbuffer, 16);
|
|
_entry.Index0 = BigEndianBitConverter.ToUInt32(tmpbuffer, 18);
|
|
_entry.Index1 = BigEndianBitConverter.ToUInt32(tmpbuffer, 22);
|
|
_entry.EndOfTrack = BigEndianBitConverter.ToUInt32(tmpbuffer, 26);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Disc-At-Once entry {0}", (i / 32) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].ISRC = \"{1}\"", (i / 32) + 1, StringHandlers.CToString(_entry.ISRC));
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].SectorSize = {1}", (i / 32) + 1, _entry.SectorSize);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1} (0x{2:X4})", (i / 32) + 1, (DAOMode)_entry.Mode, _entry.Mode);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = 0x{1:X4}", (i / 32) + 1, _entry.Unknown);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index0 = {1}", (i / 32) + 1, _entry.Index0);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index1 = {1}", (i / 32) + 1, _entry.Index1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].EndOfTrack = {1}", (i / 32) + 1, _entry.EndOfTrack);
|
|
|
|
neroDAOV1.Tracks.Add(_entry);
|
|
|
|
if(_entry.SectorSize > ImageInfo.sectorSize)
|
|
ImageInfo.sectorSize = _entry.SectorSize;
|
|
|
|
TrackISRCs.Add(currenttrack, _entry.ISRC);
|
|
if(currenttrack == 1)
|
|
_entry.Index0 = _entry.Index1;
|
|
|
|
NeroTrack _neroTrack = new NeroTrack();
|
|
_neroTrack.EndOfTrack = _entry.EndOfTrack;
|
|
_neroTrack.ISRC = _entry.ISRC;
|
|
_neroTrack.Length = _entry.EndOfTrack - _entry.Index0;
|
|
_neroTrack.Mode = _entry.Mode;
|
|
_neroTrack.Offset = _entry.Index0;
|
|
_neroTrack.Sectors = _neroTrack.Length / _entry.SectorSize;
|
|
_neroTrack.SectorSize = _entry.SectorSize;
|
|
_neroTrack.StartLBA = ImageInfo.sectors;
|
|
_neroTrack.Index0 = _entry.Index0;
|
|
_neroTrack.Index1 = _entry.Index1;
|
|
_neroTrack.Sequence = currenttrack;
|
|
neroTracks.Add(currenttrack, _neroTrack);
|
|
|
|
ImageInfo.sectors += _neroTrack.Sectors;
|
|
|
|
currenttrack++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroV2DAOID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"DAOX\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroDAOV2 = new NeroV2DAO();
|
|
neroDAOV2.ChunkID = ChunkID;
|
|
neroDAOV2.ChunkSizeBe = ChunkLength;
|
|
|
|
byte[] tmpbuffer = new byte[22];
|
|
imageStream.Read(tmpbuffer, 0, 22);
|
|
neroDAOV2.ChunkSizeLe = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
neroDAOV2.UPC = new byte[14];
|
|
Array.Copy(tmpbuffer, 4, neroDAOV2.UPC, 0, 14);
|
|
neroDAOV2.TocType = BigEndianBitConverter.ToUInt16(tmpbuffer, 18);
|
|
neroDAOV1.FirstTrack = tmpbuffer[20];
|
|
neroDAOV2.LastTrack = tmpbuffer[21];
|
|
neroDAOV2.Tracks = new List<NeroV2DAOEntry>();
|
|
|
|
if(!ImageInfo.readableMediaTags.Contains(MediaTagType.CD_MCN))
|
|
ImageInfo.readableMediaTags.Add(MediaTagType.CD_MCN);
|
|
|
|
if(!ImageInfo.readableSectorTags.Contains(SectorTagType.CDTrackISRC))
|
|
ImageInfo.readableSectorTags.Add(SectorTagType.CDTrackISRC);
|
|
|
|
UPC = neroDAOV2.UPC;
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV2.ChunkSizeLe = {0} bytes", neroDAOV2.ChunkSizeLe);
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV2.UPC = \"{0}\"", StringHandlers.CToString(neroDAOV2.UPC));
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV2.TocType = 0x{0:X4}", neroDAOV2.TocType);
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV2.FirstTrack = {0}", neroDAOV2.FirstTrack);
|
|
DicConsole.DebugWriteLine("Nero plugin", "neroDAOV2.LastTrack = {0}", neroDAOV2.LastTrack);
|
|
|
|
tmpbuffer = new byte[42];
|
|
for(int i = 0; i < (neroDAOV2.ChunkSizeBe - 22); i += 42)
|
|
{
|
|
NeroV2DAOEntry _entry = new NeroV2DAOEntry();
|
|
imageStream.Read(tmpbuffer, 0, 42);
|
|
_entry.ISRC = new byte[12];
|
|
Array.Copy(tmpbuffer, 4, _entry.ISRC, 0, 12);
|
|
_entry.SectorSize = BigEndianBitConverter.ToUInt16(tmpbuffer, 12);
|
|
_entry.Mode = BitConverter.ToUInt16(tmpbuffer, 14);
|
|
_entry.Unknown = BigEndianBitConverter.ToUInt16(tmpbuffer, 16);
|
|
_entry.Index0 = BigEndianBitConverter.ToUInt64(tmpbuffer, 18);
|
|
_entry.Index1 = BigEndianBitConverter.ToUInt64(tmpbuffer, 26);
|
|
_entry.EndOfTrack = BigEndianBitConverter.ToUInt64(tmpbuffer, 34);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Disc-At-Once entry {0}", (i / 32) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].ISRC = \"{1}\"", (i / 32) + 1, StringHandlers.CToString(_entry.ISRC));
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].SectorSize = {1}", (i / 32) + 1, _entry.SectorSize);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1} (0x{2:X4})", (i / 32) + 1, (DAOMode)_entry.Mode, _entry.Mode);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = {1:X2}", (i / 32) + 1, _entry.Unknown);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index0 = {1}", (i / 32) + 1, _entry.Index0);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Index1 = {1}", (i / 32) + 1, _entry.Index1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].EndOfTrack = {1}", (i / 32) + 1, _entry.EndOfTrack);
|
|
|
|
neroDAOV2.Tracks.Add(_entry);
|
|
|
|
if(_entry.SectorSize > ImageInfo.sectorSize)
|
|
ImageInfo.sectorSize = _entry.SectorSize;
|
|
|
|
TrackISRCs.Add(currenttrack, _entry.ISRC);
|
|
|
|
if(currenttrack == 1)
|
|
_entry.Index0 = _entry.Index1;
|
|
|
|
NeroTrack _neroTrack = new NeroTrack();
|
|
_neroTrack.EndOfTrack = _entry.EndOfTrack;
|
|
_neroTrack.ISRC = _entry.ISRC;
|
|
_neroTrack.Length = _entry.EndOfTrack - _entry.Index0;
|
|
_neroTrack.Mode = _entry.Mode;
|
|
_neroTrack.Offset = _entry.Index0;
|
|
_neroTrack.Sectors = _neroTrack.Length / _entry.SectorSize;
|
|
_neroTrack.SectorSize = _entry.SectorSize;
|
|
_neroTrack.StartLBA = ImageInfo.sectors;
|
|
_neroTrack.Index0 = _entry.Index0;
|
|
_neroTrack.Index1 = _entry.Index1;
|
|
_neroTrack.Sequence = currenttrack;
|
|
neroTracks.Add(currenttrack, _neroTrack);
|
|
|
|
ImageInfo.sectors += _neroTrack.Sectors;
|
|
|
|
currenttrack++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroCDTextID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"CDTX\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroCDTXT = new NeroCDText();
|
|
neroCDTXT.ChunkID = ChunkID;
|
|
neroCDTXT.ChunkSize = ChunkLength;
|
|
neroCDTXT.Packs = new List<NeroCDTextPack>();
|
|
|
|
byte[] tmpbuffer = new byte[18];
|
|
for(int i = 0; i < (neroCDTXT.ChunkSize); i += 18)
|
|
{
|
|
NeroCDTextPack _entry = new NeroCDTextPack();
|
|
imageStream.Read(tmpbuffer, 0, 18);
|
|
|
|
_entry.PackType = tmpbuffer[0];
|
|
_entry.TrackNumber = tmpbuffer[1];
|
|
_entry.PackNumber = tmpbuffer[2];
|
|
_entry.BlockNumber = tmpbuffer[3];
|
|
_entry.Text = new byte[12];
|
|
Array.Copy(tmpbuffer, 4, _entry.Text, 0, 12);
|
|
_entry.CRC = BigEndianBitConverter.ToUInt16(tmpbuffer, 16);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "CD-TEXT entry {0}", (i / 18) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].PackType = 0x{1:X2}", (i / 18) + 1, _entry.PackType);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].TrackNumber = 0x{1:X2}", (i / 18) + 1, _entry.TrackNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].PackNumber = 0x{1:X2}", (i / 18) + 1, _entry.PackNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].BlockNumber = 0x{1:X2}", (i / 18) + 1, _entry.BlockNumber);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Text = \"{1}\"", (i / 18) + 1, StringHandlers.CToString(_entry.Text));
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].CRC = 0x{1:X4}", (i / 18) + 1, _entry.CRC);
|
|
|
|
neroCDTXT.Packs.Add(_entry);
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroV1TAOID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"ETNF\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroTAOV1 = new NeroV1TAO();
|
|
neroTAOV1.ChunkID = ChunkID;
|
|
neroTAOV1.ChunkSize = ChunkLength;
|
|
neroTAOV1.Tracks = new List<NeroV1TAOEntry>();
|
|
|
|
byte[] tmpbuffer = new byte[20];
|
|
for(int i = 0; i < (neroTAOV1.ChunkSize); i += 20)
|
|
{
|
|
NeroV1TAOEntry _entry = new NeroV1TAOEntry();
|
|
imageStream.Read(tmpbuffer, 0, 20);
|
|
|
|
_entry.Offset = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
_entry.Length = BigEndianBitConverter.ToUInt32(tmpbuffer, 4);
|
|
_entry.Mode = BigEndianBitConverter.ToUInt32(tmpbuffer, 8);
|
|
_entry.StartLBA = BigEndianBitConverter.ToUInt32(tmpbuffer, 12);
|
|
_entry.Unknown = BigEndianBitConverter.ToUInt32(tmpbuffer, 16);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Track-at-Once entry {0}", (i / 20) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Offset = {1}", (i / 20) + 1, _entry.Offset);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Length = {1} bytes", (i / 20) + 1, _entry.Length);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1} (0x{2:X4})", (i / 20) + 1, (DAOMode)_entry.Mode, _entry.Mode);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].StartLBA = {1}", (i / 20) + 1, _entry.StartLBA);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = 0x{1:X4}", (i / 20) + 1, _entry.Unknown);
|
|
|
|
neroTAOV1.Tracks.Add(_entry);
|
|
|
|
if(NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode) > ImageInfo.sectorSize)
|
|
ImageInfo.sectorSize = NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode);
|
|
|
|
NeroTrack _neroTrack = new NeroTrack();
|
|
_neroTrack.EndOfTrack = _entry.Offset + _entry.Length;
|
|
_neroTrack.ISRC = new byte[12];
|
|
_neroTrack.Length = _entry.Length;
|
|
_neroTrack.Mode = _entry.Mode;
|
|
_neroTrack.Offset = _entry.Offset;
|
|
_neroTrack.Sectors = _neroTrack.Length / NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode);
|
|
_neroTrack.SectorSize = NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode);
|
|
_neroTrack.StartLBA = ImageInfo.sectors;
|
|
_neroTrack.Index0 = _entry.Offset;
|
|
_neroTrack.Index1 = _entry.Offset;
|
|
_neroTrack.Sequence = currenttrack;
|
|
neroTracks.Add(currenttrack, _neroTrack);
|
|
|
|
ImageInfo.sectors += _neroTrack.Sectors;
|
|
|
|
currenttrack++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroV2TAOID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"ETN2\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroTAOV2 = new NeroV2TAO();
|
|
neroTAOV2.ChunkID = ChunkID;
|
|
neroTAOV2.ChunkSize = ChunkLength;
|
|
neroTAOV2.Tracks = new List<NeroV2TAOEntry>();
|
|
|
|
byte[] tmpbuffer = new byte[32];
|
|
for(int i = 0; i < (neroTAOV2.ChunkSize); i += 32)
|
|
{
|
|
NeroV2TAOEntry _entry = new NeroV2TAOEntry();
|
|
imageStream.Read(tmpbuffer, 0, 32);
|
|
|
|
_entry.Offset = BigEndianBitConverter.ToUInt64(tmpbuffer, 0);
|
|
_entry.Length = BigEndianBitConverter.ToUInt64(tmpbuffer, 8);
|
|
_entry.Mode = BigEndianBitConverter.ToUInt32(tmpbuffer, 16);
|
|
_entry.StartLBA = BigEndianBitConverter.ToUInt32(tmpbuffer, 20);
|
|
_entry.Unknown = BigEndianBitConverter.ToUInt32(tmpbuffer, 24);
|
|
_entry.Sectors = BigEndianBitConverter.ToUInt32(tmpbuffer, 28);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Track-at-Once entry {0}", (i / 32) + 1);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Offset = {1}", (i / 32) + 1, _entry.Offset);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Length = {1} bytes", (i / 32) + 1, _entry.Length);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Mode = {1} (0x{2:X4})", (i / 32) + 1, (DAOMode)_entry.Mode, _entry.Mode);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].StartLBA = {1}", (i / 32) + 1, _entry.StartLBA);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Unknown = 0x{1:X4}", (i / 32) + 1, _entry.Unknown);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t _entry[{0}].Sectors = {1}", (i / 32) + 1, _entry.Sectors);
|
|
|
|
neroTAOV2.Tracks.Add(_entry);
|
|
|
|
if(NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode) > ImageInfo.sectorSize)
|
|
ImageInfo.sectorSize = NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode);
|
|
|
|
NeroTrack _neroTrack = new NeroTrack();
|
|
_neroTrack.EndOfTrack = _entry.Offset + _entry.Length;
|
|
_neroTrack.ISRC = new byte[12];
|
|
_neroTrack.Length = _entry.Length;
|
|
_neroTrack.Mode = _entry.Mode;
|
|
_neroTrack.Offset = _entry.Offset;
|
|
_neroTrack.Sectors = _neroTrack.Length / NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode);
|
|
_neroTrack.SectorSize = NeroTrackModeToBytesPerSector((DAOMode)_entry.Mode);
|
|
_neroTrack.StartLBA = ImageInfo.sectors;
|
|
_neroTrack.Index0 = _entry.Offset;
|
|
_neroTrack.Index1 = _entry.Offset;
|
|
_neroTrack.Sequence = currenttrack;
|
|
neroTracks.Add(currenttrack, _neroTrack);
|
|
|
|
ImageInfo.sectors += _neroTrack.Sectors;
|
|
|
|
currenttrack++;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case NeroSessionID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"SINF\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
uint sessionTracks;
|
|
byte[] tmpbuffer = new byte[4];
|
|
imageStream.Read(tmpbuffer, 0, 4);
|
|
sessionTracks = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
neroSessions.Add(currentsession, sessionTracks);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tSession {0} has {1} tracks", currentsession, sessionTracks);
|
|
|
|
currentsession++;
|
|
break;
|
|
}
|
|
case NeroDiskTypeID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"MTYP\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroMediaTyp = new NeroMediaType();
|
|
|
|
neroMediaTyp.ChunkID = ChunkID;
|
|
neroMediaTyp.ChunkSize = ChunkLength;
|
|
|
|
byte[] tmpbuffer = new byte[4];
|
|
imageStream.Read(tmpbuffer, 0, 4);
|
|
neroMediaTyp.Type = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tMedia type is {0} ({1})", (NeroMediaTypes)neroMediaTyp.Type, neroMediaTyp.Type);
|
|
|
|
ImageInfo.mediaType = NeroMediaTypeToMediaType((NeroMediaTypes)neroMediaTyp.Type);
|
|
|
|
break;
|
|
}
|
|
case NeroDiscInfoID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"DINF\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroDiscInfo = new NeroDiscInformation();
|
|
neroDiscInfo.ChunkID = ChunkID;
|
|
neroDiscInfo.ChunkSize = ChunkLength;
|
|
byte[] tmpbuffer = new byte[4];
|
|
imageStream.Read(tmpbuffer, 0, 4);
|
|
neroDiscInfo.Unknown = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tneroDiscInfo.Unknown = 0x{0:X4} ({0})", neroDiscInfo.Unknown);
|
|
|
|
break;
|
|
}
|
|
case NeroReloID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"RELO\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroRELO = new NeroRELOChunk();
|
|
neroRELO.ChunkID = ChunkID;
|
|
neroRELO.ChunkSize = ChunkLength;
|
|
byte[] tmpbuffer = new byte[4];
|
|
imageStream.Read(tmpbuffer, 0, 4);
|
|
neroRELO.Unknown = BigEndianBitConverter.ToUInt32(tmpbuffer, 0);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tneroRELO.Unknown = 0x{0:X4} ({0})", neroRELO.Unknown);
|
|
|
|
break;
|
|
}
|
|
case NeroTOCID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"TOCT\" chunk, parsing {0} bytes", ChunkLength);
|
|
|
|
neroTOC = new NeroTOCChunk();
|
|
neroTOC.ChunkID = ChunkID;
|
|
neroTOC.ChunkSize = ChunkLength;
|
|
byte[] tmpbuffer = new byte[2];
|
|
imageStream.Read(tmpbuffer, 0, 2);
|
|
neroTOC.Unknown = BigEndianBitConverter.ToUInt16(tmpbuffer, 0);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tneroTOC.Unknown = 0x{0:X4} ({0})", neroTOC.Unknown);
|
|
|
|
break;
|
|
}
|
|
case NeroEndID:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Found \"END!\" chunk, finishing parse");
|
|
parsing = false;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "Unknown chunk ID \"{0}\", skipping...", System.Text.Encoding.ASCII.GetString(BigEndianBitConverter.GetBytes(ChunkID)));
|
|
imageStream.Seek(ChunkLength, SeekOrigin.Current);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ImageInfo.imageHasPartitions = true;
|
|
ImageInfo.imageHasSessions = true;
|
|
ImageInfo.imageCreator = null;
|
|
ImageInfo.imageCreationTime = imageFilter.GetCreationTime();
|
|
ImageInfo.imageLastModificationTime = imageFilter.GetLastWriteTime();
|
|
ImageInfo.imageName = Path.GetFileNameWithoutExtension(imageFilter.GetFilename());
|
|
ImageInfo.imageComments = null;
|
|
ImageInfo.mediaManufacturer = null;
|
|
ImageInfo.mediaModel = null;
|
|
ImageInfo.mediaSerialNumber = null;
|
|
ImageInfo.mediaBarcode = null;
|
|
ImageInfo.mediaPartNumber = null;
|
|
ImageInfo.driveManufacturer = null;
|
|
ImageInfo.driveModel = null;
|
|
ImageInfo.driveSerialNumber = null;
|
|
ImageInfo.driveFirmwareRevision = null;
|
|
ImageInfo.mediaSequence = 0;
|
|
ImageInfo.lastMediaSequence = 0;
|
|
if(imageNewFormat)
|
|
{
|
|
ImageInfo.imageSize = footerV2.FirstChunkOffset;
|
|
ImageInfo.imageVersion = "Nero Burning ROM >= 5.5";
|
|
ImageInfo.imageApplication = "Nero Burning ROM";
|
|
ImageInfo.imageApplicationVersion = ">= 5.5";
|
|
}
|
|
else
|
|
{
|
|
ImageInfo.imageSize = footerV1.FirstChunkOffset;
|
|
ImageInfo.imageVersion = "Nero Burning ROM <= 5.0";
|
|
ImageInfo.imageApplication = "Nero Burning ROM";
|
|
ImageInfo.imageApplicationVersion = "<= 5.0";
|
|
}
|
|
|
|
if(neroSessions.Count == 0)
|
|
neroSessions.Add(1, currenttrack);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "Building offset, track and session maps");
|
|
|
|
currentsession = 1;
|
|
uint currentsessionmaxtrack;
|
|
neroSessions.TryGetValue(1, out currentsessionmaxtrack);
|
|
uint currentsessioncurrenttrack = 1;
|
|
Session currentsessionstruct = new Session();
|
|
ulong PartitionSequence = 0;
|
|
ulong partitionStartByte = 0;
|
|
for(uint i = 1; i <= neroTracks.Count; i++)
|
|
{
|
|
NeroTrack _neroTrack;
|
|
if(neroTracks.TryGetValue(i, out _neroTrack))
|
|
{
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsession = {0}", currentsession);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsessionmaxtrack = {0}", currentsessionmaxtrack);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\tcurrentsessioncurrenttrack = {0}", currentsessioncurrenttrack);
|
|
|
|
Track _track = new Track();
|
|
if(_neroTrack.Sequence == 1)
|
|
_neroTrack.Index0 = _neroTrack.Index1;
|
|
|
|
_track.Indexes = new Dictionary<int, ulong>();
|
|
if(_neroTrack.Index0 < _neroTrack.Index1)
|
|
_track.Indexes.Add(0, _neroTrack.Index0 / _neroTrack.SectorSize);
|
|
_track.Indexes.Add(1, _neroTrack.Index1 / _neroTrack.SectorSize);
|
|
_track.TrackDescription = StringHandlers.CToString(_neroTrack.ISRC);
|
|
_track.TrackEndSector = (_neroTrack.Length / _neroTrack.SectorSize) + _neroTrack.StartLBA - 1;
|
|
_track.TrackPregap = (_neroTrack.Index1 - _neroTrack.Index0) / _neroTrack.SectorSize;
|
|
_track.TrackSequence = _neroTrack.Sequence;
|
|
_track.TrackSession = currentsession;
|
|
_track.TrackStartSector = _neroTrack.StartLBA;
|
|
_track.TrackType = NeroTrackModeToTrackType((DAOMode)_neroTrack.Mode);
|
|
_track.TrackFile = imageFilter.GetFilename();
|
|
_track.TrackFilter = imageFilter;
|
|
_track.TrackFileOffset = _neroTrack.Offset;
|
|
_track.TrackFileType = "BINARY";
|
|
_track.TrackSubchannelType = TrackSubchannelType.None;
|
|
switch((DAOMode)_neroTrack.Mode)
|
|
{
|
|
case DAOMode.Audio:
|
|
_track.TrackBytesPerSector = 2352;
|
|
_track.TrackRawBytesPerSector = 2352;
|
|
break;
|
|
case DAOMode.AudioSub:
|
|
_track.TrackBytesPerSector = 2352;
|
|
_track.TrackRawBytesPerSector = 2448;
|
|
_track.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
|
|
break;
|
|
case DAOMode.Data:
|
|
case DAOMode.DataM2F1:
|
|
_track.TrackBytesPerSector = 2048;
|
|
_track.TrackRawBytesPerSector = 2048;
|
|
break;
|
|
case DAOMode.DataM2F2:
|
|
_track.TrackBytesPerSector = 2336;
|
|
_track.TrackRawBytesPerSector = 2336;
|
|
break;
|
|
case DAOMode.DataM2Raw:
|
|
_track.TrackBytesPerSector = 2352;
|
|
_track.TrackRawBytesPerSector = 2352;
|
|
break;
|
|
case DAOMode.DataM2RawSub:
|
|
_track.TrackBytesPerSector = 2352;
|
|
_track.TrackRawBytesPerSector = 2448;
|
|
_track.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
|
|
break;
|
|
case DAOMode.DataRaw:
|
|
_track.TrackBytesPerSector = 2048;
|
|
_track.TrackRawBytesPerSector = 2352;
|
|
break;
|
|
case DAOMode.DataRawSub:
|
|
_track.TrackBytesPerSector = 2048;
|
|
_track.TrackRawBytesPerSector = 2448;
|
|
_track.TrackSubchannelType = TrackSubchannelType.RawInterleaved;
|
|
break;
|
|
}
|
|
|
|
if(_track.TrackSubchannelType == TrackSubchannelType.RawInterleaved)
|
|
{
|
|
_track.TrackSubchannelFilter = imageFilter;
|
|
_track.TrackSubchannelFile = imageFilter.GetFilename();
|
|
_track.TrackSubchannelOffset = _neroTrack.Offset;
|
|
}
|
|
|
|
imageTracks.Add(_track);
|
|
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackDescription = {0}", _track.TrackDescription);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackEndSector = {0}", _track.TrackEndSector);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackPregap = {0}", _track.TrackPregap);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackSequence = {0}", _track.TrackSequence);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackSession = {0}", _track.TrackSession);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackStartSector = {0}", _track.TrackStartSector);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t _track.TrackType = {0}", _track.TrackType);
|
|
|
|
if(currentsessioncurrenttrack == 1)
|
|
{
|
|
currentsessionstruct = new Session();
|
|
currentsessionstruct.SessionSequence = currentsession;
|
|
currentsessionstruct.StartSector = _track.TrackStartSector;
|
|
currentsessionstruct.StartTrack = _track.TrackSequence;
|
|
}
|
|
currentsessioncurrenttrack++;
|
|
if(currentsessioncurrenttrack > currentsessionmaxtrack)
|
|
{
|
|
currentsession++;
|
|
neroSessions.TryGetValue(currentsession, out currentsessionmaxtrack);
|
|
currentsessioncurrenttrack = 1;
|
|
currentsessionstruct.EndTrack = _track.TrackSequence;
|
|
currentsessionstruct.EndSector = _track.TrackEndSector;
|
|
imageSessions.Add(currentsessionstruct);
|
|
}
|
|
|
|
if(i == neroTracks.Count)
|
|
{
|
|
neroSessions.TryGetValue(currentsession, out currentsessionmaxtrack);
|
|
currentsessioncurrenttrack = 1;
|
|
currentsessionstruct.EndTrack = _track.TrackSequence;
|
|
currentsessionstruct.EndSector = _track.TrackEndSector;
|
|
imageSessions.Add(currentsessionstruct);
|
|
}
|
|
|
|
offsetmap.Add(_track.TrackSequence, _track.TrackStartSector);
|
|
DicConsole.DebugWriteLine("Nero plugin", "\t\t Offset[{0}]: {1}", _track.TrackSequence, _track.TrackStartSector);
|
|
|
|
Partition partition;
|
|
|
|
/*if(_neroTrack.Index0 < _neroTrack.Index1)
|
|
{
|
|
partition = new Partition();
|
|
partition.PartitionDescription = string.Format("Track {0} Index 0", _track.TrackSequence);
|
|
partition.PartitionLength = (_neroTrack.Index1 - _neroTrack.Index0);
|
|
partition.PartitionName = StringHandlers.CToString(_neroTrack.ISRC);
|
|
partition.PartitionSectors = partition.PartitionLength / _neroTrack.SectorSize;
|
|
partition.PartitionSequence = PartitionSequence;
|
|
partition.PartitionStart = _neroTrack.Index0;
|
|
partition.PartitionStartSector = _neroTrack.StartLBA;
|
|
partition.PartitionType = NeroTrackModeToTrackType((DAOMode)_neroTrack.Mode).ToString();
|
|
ImagePartitions.Add(partition);
|
|
PartitionSequence++;
|
|
}*/
|
|
|
|
partition = new Partition();
|
|
partition.PartitionDescription = string.Format("Track {0} Index 1", _track.TrackSequence);
|
|
partition.PartitionLength = (_neroTrack.EndOfTrack - _neroTrack.Index1);
|
|
partition.PartitionName = StringHandlers.CToString(_neroTrack.ISRC);
|
|
partition.PartitionSectors = partition.PartitionLength / _neroTrack.SectorSize;
|
|
partition.PartitionSequence = PartitionSequence;
|
|
partition.PartitionStart = partitionStartByte;
|
|
partition.PartitionStartSector = _neroTrack.StartLBA + ((_neroTrack.Index1 - _neroTrack.Index0) / _neroTrack.SectorSize);
|
|
partition.PartitionType = NeroTrackModeToTrackType((DAOMode)_neroTrack.Mode).ToString();
|
|
ImagePartitions.Add(partition);
|
|
PartitionSequence++;
|
|
partitionStartByte += partition.PartitionLength;
|
|
}
|
|
}
|
|
|
|
_imageFilter = imageFilter;
|
|
|
|
if(ImageInfo.mediaType == MediaType.Unknown || ImageInfo.mediaType == MediaType.CD)
|
|
{
|
|
bool data = false;
|
|
bool mode2 = false;
|
|
bool firstaudio = false;
|
|
bool firstdata = false;
|
|
bool audio = false;
|
|
|
|
for(uint i = 0; i < neroTracks.Count; i++)
|
|
{
|
|
// First track is audio
|
|
firstaudio |= i == 0 && ((DAOMode)neroTracks[i].Mode == DAOMode.Audio || (DAOMode)neroTracks[i].Mode == DAOMode.AudioSub);
|
|
|
|
// First track is data
|
|
firstdata |= i == 0 && ((DAOMode)neroTracks[i].Mode != DAOMode.Audio && (DAOMode)neroTracks[i].Mode != DAOMode.AudioSub);
|
|
|
|
// Any non first track is data
|
|
data |= i != 0 && ((DAOMode)neroTracks[i].Mode != DAOMode.Audio && (DAOMode)neroTracks[i].Mode != DAOMode.AudioSub);
|
|
|
|
// Any non first track is audio
|
|
audio |= i != 0 && ((DAOMode)neroTracks[i].Mode == DAOMode.Audio || (DAOMode)neroTracks[i].Mode == DAOMode.AudioSub);
|
|
|
|
switch((DAOMode)neroTracks[i].Mode)
|
|
{
|
|
case DAOMode.DataM2F1:
|
|
case DAOMode.DataM2F2:
|
|
case DAOMode.DataM2Raw:
|
|
case DAOMode.DataM2RawSub:
|
|
mode2 = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!data && !firstdata)
|
|
ImageInfo.mediaType = MediaType.CDDA;
|
|
else if(firstaudio && data && imageSessions.Count > 1 && mode2)
|
|
ImageInfo.mediaType = MediaType.CDPLUS;
|
|
else if((firstdata && audio) || mode2)
|
|
ImageInfo.mediaType = MediaType.CDROMXA;
|
|
else if(!audio)
|
|
ImageInfo.mediaType = MediaType.CDROM;
|
|
else
|
|
ImageInfo.mediaType = MediaType.CD;
|
|
}
|
|
|
|
|
|
ImageInfo.xmlMediaType = XmlMediaType.OpticalDisc;
|
|
DicConsole.VerboseWriteLine("Nero image contains a disc of type {0}", ImageInfo.mediaType);
|
|
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public override bool ImageHasPartitions()
|
|
{
|
|
// Even if they only have 1 track, there is a partition (track 1)
|
|
return true;
|
|
}
|
|
|
|
public override ulong GetImageSize()
|
|
{
|
|
return ImageInfo.imageSize;
|
|
}
|
|
|
|
public override ulong GetSectors()
|
|
{
|
|
return ImageInfo.sectors;
|
|
}
|
|
|
|
public override uint GetSectorSize()
|
|
{
|
|
return ImageInfo.sectorSize;
|
|
}
|
|
|
|
public override byte[] ReadDiskTag(MediaTagType tag)
|
|
{
|
|
switch(tag)
|
|
{
|
|
case MediaTagType.CD_MCN:
|
|
return UPC;
|
|
case MediaTagType.CD_TEXT:
|
|
throw new NotImplementedException("Not yet implemented");
|
|
default:
|
|
throw new FeaturedNotSupportedByDiscImageException("Requested disk tag not supported by image");
|
|
}
|
|
}
|
|
|
|
public override byte[] ReadSector(ulong sectorAddress)
|
|
{
|
|
return ReadSectors(sectorAddress, 1);
|
|
}
|
|
|
|
public override byte[] ReadSectorTag(ulong sectorAddress, SectorTagType tag)
|
|
{
|
|
return ReadSectorsTag(sectorAddress, 1, tag);
|
|
}
|
|
|
|
public override byte[] ReadSector(ulong sectorAddress, uint track)
|
|
{
|
|
return ReadSectors(sectorAddress, 1, track);
|
|
}
|
|
|
|
public override byte[] ReadSectorTag(ulong sectorAddress, uint track, SectorTagType tag)
|
|
{
|
|
return ReadSectorsTag(sectorAddress, 1, track, tag);
|
|
}
|
|
|
|
public override byte[] ReadSectors(ulong sectorAddress, uint length)
|
|
{
|
|
foreach(KeyValuePair<uint, ulong> kvp in offsetmap)
|
|
{
|
|
if(sectorAddress >= kvp.Value)
|
|
{
|
|
foreach(Track _track in imageTracks)
|
|
{
|
|
if(_track.TrackSequence == kvp.Key)
|
|
{
|
|
if((sectorAddress - kvp.Value) < (_track.TrackEndSector - _track.TrackStartSector))
|
|
return ReadSectors((sectorAddress - kvp.Value), length, kvp.Key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress));
|
|
}
|
|
|
|
public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, SectorTagType tag)
|
|
{
|
|
foreach(KeyValuePair<uint, ulong> kvp in offsetmap)
|
|
{
|
|
if(sectorAddress >= kvp.Value)
|
|
{
|
|
foreach(Track _track in imageTracks)
|
|
{
|
|
if(_track.TrackSequence == kvp.Key)
|
|
{
|
|
if((sectorAddress - kvp.Value) < (_track.TrackEndSector - _track.TrackStartSector))
|
|
return ReadSectorsTag((sectorAddress - kvp.Value), length, kvp.Key, tag);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress));
|
|
}
|
|
|
|
public override byte[] ReadSectors(ulong sectorAddress, uint length, uint track)
|
|
{
|
|
NeroTrack _track;
|
|
|
|
if(!neroTracks.TryGetValue(track, out _track))
|
|
throw new ArgumentOutOfRangeException(nameof(track), "Track not found");
|
|
|
|
if(length > _track.Sectors)
|
|
throw new ArgumentOutOfRangeException(nameof(length), string.Format("Requested more sectors ({0}) than present in track ({1}), won't cross tracks", length, _track.Sectors));
|
|
|
|
uint sector_offset;
|
|
uint sector_size;
|
|
uint sector_skip;
|
|
|
|
switch((DAOMode)_track.Mode)
|
|
{
|
|
case DAOMode.Data:
|
|
case DAOMode.DataM2F1:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2048;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case DAOMode.DataM2F2:
|
|
{
|
|
sector_offset = 8;
|
|
sector_size = 2324;
|
|
sector_skip = 4;
|
|
break;
|
|
}
|
|
case DAOMode.Audio:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2352;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case DAOMode.DataRaw:
|
|
{
|
|
sector_offset = 16;
|
|
sector_size = 2048;
|
|
sector_skip = 288;
|
|
break;
|
|
}
|
|
case DAOMode.DataM2Raw:
|
|
{
|
|
sector_offset = 16;
|
|
sector_size = 2336;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
// TODO: Supposing Nero suffixes the subchannel to the channel
|
|
case DAOMode.DataRawSub:
|
|
{
|
|
sector_offset = 16;
|
|
sector_size = 2048;
|
|
sector_skip = 288 + 96;
|
|
break;
|
|
}
|
|
case DAOMode.DataM2RawSub:
|
|
{
|
|
sector_offset = 16;
|
|
sector_size = 2336;
|
|
sector_skip = 96;
|
|
break;
|
|
}
|
|
case DAOMode.AudioSub:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2352;
|
|
sector_skip = 96;
|
|
break;
|
|
}
|
|
default:
|
|
throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
|
|
}
|
|
|
|
byte[] buffer = new byte[sector_size * length];
|
|
|
|
imageStream = _imageFilter.GetDataForkStream();
|
|
BinaryReader br = new BinaryReader(imageStream);
|
|
br.BaseStream.Seek((long)_track.Offset + (long)(sectorAddress * (sector_offset + sector_size + sector_skip)), SeekOrigin.Begin);
|
|
if(sector_offset == 0 && sector_skip == 0)
|
|
buffer = br.ReadBytes((int)(sector_size * length));
|
|
else
|
|
{
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
byte[] sector;
|
|
br.BaseStream.Seek(sector_offset, SeekOrigin.Current);
|
|
sector = br.ReadBytes((int)sector_size);
|
|
br.BaseStream.Seek(sector_skip, SeekOrigin.Current);
|
|
Array.Copy(sector, 0, buffer, i * sector_size, sector_size);
|
|
}
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
public override byte[] ReadSectorsTag(ulong sectorAddress, uint length, uint track, SectorTagType tag)
|
|
{
|
|
NeroTrack _track;
|
|
|
|
if(!neroTracks.TryGetValue(track, out _track))
|
|
throw new ArgumentOutOfRangeException(nameof(track), "Track not found");
|
|
|
|
if(length > _track.Sectors)
|
|
throw new ArgumentOutOfRangeException(nameof(length), string.Format("Requested more sectors ({0}) than present in track ({1}), won't cross tracks", length, _track.Sectors));
|
|
|
|
uint sector_offset;
|
|
uint sector_size;
|
|
uint sector_skip;
|
|
|
|
switch(tag)
|
|
{
|
|
case SectorTagType.CDSectorECC:
|
|
case SectorTagType.CDSectorECC_P:
|
|
case SectorTagType.CDSectorECC_Q:
|
|
case SectorTagType.CDSectorEDC:
|
|
case SectorTagType.CDSectorHeader:
|
|
case SectorTagType.CDSectorSubchannel:
|
|
case SectorTagType.CDSectorSubHeader:
|
|
case SectorTagType.CDSectorSync:
|
|
break;
|
|
case SectorTagType.CDTrackFlags:
|
|
{
|
|
byte[] flags = new byte[1];
|
|
flags[0] = 0x00;
|
|
|
|
if((DAOMode)_track.Mode != DAOMode.Audio && (DAOMode)_track.Mode != DAOMode.AudioSub)
|
|
flags[0] += 0x40;
|
|
|
|
return flags;
|
|
}
|
|
case SectorTagType.CDTrackISRC:
|
|
return _track.ISRC;
|
|
case SectorTagType.CDTrackText:
|
|
throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented");
|
|
default:
|
|
throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
}
|
|
|
|
switch((DAOMode)_track.Mode)
|
|
{
|
|
case DAOMode.Data:
|
|
case DAOMode.DataM2F1:
|
|
throw new ArgumentException("No tags in image for requested track", nameof(tag));
|
|
case DAOMode.DataM2F2:
|
|
{
|
|
switch(tag)
|
|
{
|
|
case SectorTagType.CDSectorSync:
|
|
case SectorTagType.CDSectorHeader:
|
|
case SectorTagType.CDSectorSubchannel:
|
|
case SectorTagType.CDSectorECC:
|
|
case SectorTagType.CDSectorECC_P:
|
|
case SectorTagType.CDSectorECC_Q:
|
|
throw new ArgumentException("Unsupported tag requested for this track", nameof(tag));
|
|
case SectorTagType.CDSectorSubHeader:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 8;
|
|
sector_skip = 2328;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorEDC:
|
|
{
|
|
sector_offset = 2332;
|
|
sector_size = 4;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
default:
|
|
throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
}
|
|
break;
|
|
}
|
|
case DAOMode.Audio:
|
|
throw new ArgumentException("There are no tags on audio tracks", nameof(tag));
|
|
case DAOMode.DataRaw:
|
|
{
|
|
switch(tag)
|
|
{
|
|
case SectorTagType.CDSectorSync:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 12;
|
|
sector_skip = 2340;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorHeader:
|
|
{
|
|
sector_offset = 12;
|
|
sector_size = 4;
|
|
sector_skip = 2336;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorSubchannel:
|
|
case SectorTagType.CDSectorSubHeader:
|
|
throw new ArgumentException("Unsupported tag requested for this track", nameof(tag));
|
|
case SectorTagType.CDSectorECC:
|
|
{
|
|
sector_offset = 2076;
|
|
sector_size = 276;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorECC_P:
|
|
{
|
|
sector_offset = 2076;
|
|
sector_size = 172;
|
|
sector_skip = 104;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorECC_Q:
|
|
{
|
|
sector_offset = 2248;
|
|
sector_size = 104;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorEDC:
|
|
{
|
|
sector_offset = 2064;
|
|
sector_size = 4;
|
|
sector_skip = 284;
|
|
break;
|
|
}
|
|
default:
|
|
throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
}
|
|
break;
|
|
}
|
|
// TODO
|
|
case DAOMode.DataM2RawSub:
|
|
throw new FeatureSupportedButNotImplementedImageException("Feature not yet implemented");
|
|
case DAOMode.DataRawSub:
|
|
{
|
|
switch(tag)
|
|
{
|
|
case SectorTagType.CDSectorSync:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 12;
|
|
sector_skip = 2340 + 96;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorHeader:
|
|
{
|
|
sector_offset = 12;
|
|
sector_size = 4;
|
|
sector_skip = 2336 + 96;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorSubchannel:
|
|
{
|
|
sector_offset = 2352;
|
|
sector_size = 96;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorSubHeader:
|
|
throw new ArgumentException("Unsupported tag requested for this track", nameof(tag));
|
|
case SectorTagType.CDSectorECC:
|
|
{
|
|
sector_offset = 2076;
|
|
sector_size = 276;
|
|
sector_skip = 0 + 96;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorECC_P:
|
|
{
|
|
sector_offset = 2076;
|
|
sector_size = 172;
|
|
sector_skip = 104 + 96;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorECC_Q:
|
|
{
|
|
sector_offset = 2248;
|
|
sector_size = 104;
|
|
sector_skip = 0 + 96;
|
|
break;
|
|
}
|
|
case SectorTagType.CDSectorEDC:
|
|
{
|
|
sector_offset = 2064;
|
|
sector_size = 4;
|
|
sector_skip = 284 + 96;
|
|
break;
|
|
}
|
|
default:
|
|
throw new ArgumentException("Unsupported tag requested", nameof(tag));
|
|
}
|
|
break;
|
|
}
|
|
case DAOMode.AudioSub:
|
|
{
|
|
if(tag != SectorTagType.CDSectorSubchannel)
|
|
throw new ArgumentException("Unsupported tag requested for this track", nameof(tag));
|
|
|
|
sector_offset = 2352;
|
|
sector_size = 96;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
default:
|
|
throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
|
|
}
|
|
|
|
byte[] buffer = new byte[sector_size * length];
|
|
|
|
imageStream = _imageFilter.GetDataForkStream();
|
|
BinaryReader br = new BinaryReader(imageStream);
|
|
br.BaseStream.Seek((long)_track.Offset + (long)(sectorAddress * (sector_offset + sector_size + sector_skip)), SeekOrigin.Begin);
|
|
if(sector_offset == 0 && sector_skip == 0)
|
|
buffer = br.ReadBytes((int)(sector_size * length));
|
|
else
|
|
{
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
byte[] sector;
|
|
br.BaseStream.Seek(sector_offset, SeekOrigin.Current);
|
|
sector = br.ReadBytes((int)sector_size);
|
|
br.BaseStream.Seek(sector_skip, SeekOrigin.Current);
|
|
Array.Copy(sector, 0, buffer, i * sector_size, sector_size);
|
|
}
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
public override byte[] ReadSectorLong(ulong sectorAddress)
|
|
{
|
|
return ReadSectorsLong(sectorAddress, 1);
|
|
}
|
|
|
|
public override byte[] ReadSectorLong(ulong sectorAddress, uint track)
|
|
{
|
|
return ReadSectorsLong(sectorAddress, 1, track);
|
|
}
|
|
|
|
public override byte[] ReadSectorsLong(ulong sectorAddress, uint length)
|
|
{
|
|
foreach(KeyValuePair<uint, ulong> kvp in offsetmap)
|
|
{
|
|
if(sectorAddress >= kvp.Value)
|
|
{
|
|
foreach(Track _track in imageTracks)
|
|
{
|
|
if(_track.TrackSequence == kvp.Key)
|
|
{
|
|
if((sectorAddress - kvp.Value) < (_track.TrackEndSector - _track.TrackStartSector))
|
|
return ReadSectorsLong((sectorAddress - kvp.Value), length, kvp.Key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress));
|
|
}
|
|
|
|
public override byte[] ReadSectorsLong(ulong sectorAddress, uint length, uint track)
|
|
{
|
|
NeroTrack _track;
|
|
|
|
if(!neroTracks.TryGetValue(track, out _track))
|
|
throw new ArgumentOutOfRangeException(nameof(track), "Track not found");
|
|
|
|
if(length > _track.Sectors)
|
|
throw new ArgumentOutOfRangeException(nameof(length), string.Format("Requested more sectors ({0}) than present in track ({1}), won't cross tracks", length, _track.Sectors));
|
|
|
|
uint sector_offset;
|
|
uint sector_size;
|
|
uint sector_skip;
|
|
|
|
switch((DAOMode)_track.Mode)
|
|
{
|
|
case DAOMode.Data:
|
|
case DAOMode.DataM2F1:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2048;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case DAOMode.DataM2F2:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2336;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case DAOMode.DataRaw:
|
|
case DAOMode.DataM2Raw:
|
|
case DAOMode.Audio:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2352;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
case DAOMode.DataRawSub:
|
|
case DAOMode.DataM2RawSub:
|
|
case DAOMode.AudioSub:
|
|
{
|
|
sector_offset = 0;
|
|
sector_size = 2448;
|
|
sector_skip = 0;
|
|
break;
|
|
}
|
|
default:
|
|
throw new FeatureSupportedButNotImplementedImageException("Unsupported track type");
|
|
}
|
|
|
|
byte[] buffer = new byte[sector_size * length];
|
|
|
|
imageStream = _imageFilter.GetDataForkStream();
|
|
BinaryReader br = new BinaryReader(imageStream);
|
|
|
|
br.BaseStream.Seek((long)_track.Offset + (long)(sectorAddress * (sector_offset + sector_size + sector_skip)), SeekOrigin.Begin);
|
|
|
|
if(sector_offset == 0 && sector_skip == 0)
|
|
buffer = br.ReadBytes((int)(sector_size * length));
|
|
else
|
|
{
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
byte[] sector;
|
|
br.BaseStream.Seek(sector_offset, SeekOrigin.Current);
|
|
sector = br.ReadBytes((int)sector_size);
|
|
br.BaseStream.Seek(sector_skip, SeekOrigin.Current);
|
|
|
|
Array.Copy(sector, 0, buffer, i * sector_size, sector_size);
|
|
}
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
public override string GetImageFormat()
|
|
{
|
|
return "Nero Burning ROM";
|
|
}
|
|
|
|
public override string GetImageVersion()
|
|
{
|
|
return ImageInfo.imageVersion;
|
|
}
|
|
|
|
public override string GetImageApplication()
|
|
{
|
|
return ImageInfo.imageApplication;
|
|
}
|
|
|
|
public override string GetImageApplicationVersion()
|
|
{
|
|
return ImageInfo.imageApplicationVersion;
|
|
}
|
|
|
|
public override DateTime GetImageCreationTime()
|
|
{
|
|
return ImageInfo.imageCreationTime;
|
|
}
|
|
|
|
public override DateTime GetImageLastModificationTime()
|
|
{
|
|
return ImageInfo.imageLastModificationTime;
|
|
}
|
|
|
|
public override string GetMediaBarcode()
|
|
{
|
|
return ImageInfo.mediaBarcode;
|
|
}
|
|
|
|
public override MediaType GetMediaType()
|
|
{
|
|
return ImageInfo.mediaType;
|
|
}
|
|
|
|
public override List<Partition> GetPartitions()
|
|
{
|
|
return ImagePartitions;
|
|
}
|
|
|
|
public override List<Track> GetTracks()
|
|
{
|
|
return imageTracks;
|
|
}
|
|
|
|
public override List<Track> GetSessionTracks(Session session)
|
|
{
|
|
return GetSessionTracks(session.SessionSequence);
|
|
}
|
|
|
|
public override List<Track> GetSessionTracks(ushort session)
|
|
{
|
|
List<Track> sessionTracks = new List<Track>();
|
|
foreach(Track _track in imageTracks)
|
|
if(_track.TrackSession == session)
|
|
sessionTracks.Add(_track);
|
|
|
|
return sessionTracks;
|
|
}
|
|
|
|
public override List<Session> GetSessions()
|
|
{
|
|
return imageSessions;
|
|
}
|
|
|
|
public override bool? VerifySector(ulong sectorAddress)
|
|
{
|
|
byte[] buffer = ReadSectorLong(sectorAddress);
|
|
return Checksums.CDChecksums.CheckCDSector(buffer);
|
|
}
|
|
|
|
public override bool? VerifySector(ulong sectorAddress, uint track)
|
|
{
|
|
byte[] buffer = ReadSectorLong(sectorAddress, track);
|
|
return Checksums.CDChecksums.CheckCDSector(buffer);
|
|
}
|
|
|
|
public override bool? VerifySectors(ulong sectorAddress, uint length, out List<ulong> FailingLBAs, out List<ulong> UnknownLBAs)
|
|
{
|
|
byte[] buffer = ReadSectorsLong(sectorAddress, length);
|
|
int bps = (int)(buffer.Length / length);
|
|
byte[] sector = new byte[bps];
|
|
FailingLBAs = new List<ulong>();
|
|
UnknownLBAs = new List<ulong>();
|
|
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
Array.Copy(buffer, i * bps, sector, 0, bps);
|
|
bool? sectorStatus = Checksums.CDChecksums.CheckCDSector(sector);
|
|
|
|
switch(sectorStatus)
|
|
{
|
|
case null:
|
|
UnknownLBAs.Add((ulong)i + sectorAddress);
|
|
break;
|
|
case false:
|
|
FailingLBAs.Add((ulong)i + sectorAddress);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(UnknownLBAs.Count > 0)
|
|
return null;
|
|
if(FailingLBAs.Count > 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public override bool? VerifySectors(ulong sectorAddress, uint length, uint track, out List<ulong> FailingLBAs, out List<ulong> UnknownLBAs)
|
|
{
|
|
byte[] buffer = ReadSectorsLong(sectorAddress, length, track);
|
|
int bps = (int)(buffer.Length / length);
|
|
byte[] sector = new byte[bps];
|
|
FailingLBAs = new List<ulong>();
|
|
UnknownLBAs = new List<ulong>();
|
|
|
|
for(int i = 0; i < length; i++)
|
|
{
|
|
Array.Copy(buffer, i * bps, sector, 0, bps);
|
|
bool? sectorStatus = Checksums.CDChecksums.CheckCDSector(sector);
|
|
|
|
switch(sectorStatus)
|
|
{
|
|
case null:
|
|
UnknownLBAs.Add((ulong)i + sectorAddress);
|
|
break;
|
|
case false:
|
|
FailingLBAs.Add((ulong)i + sectorAddress);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(UnknownLBAs.Count > 0)
|
|
return null;
|
|
if(FailingLBAs.Count > 0)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
public override bool? VerifyMediaImage()
|
|
{
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Private methods
|
|
|
|
static MediaType NeroMediaTypeToMediaType(NeroMediaTypes type)
|
|
{
|
|
switch(type)
|
|
{
|
|
case NeroMediaTypes.NERO_MTYP_DDCD:
|
|
return MediaType.DDCD;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_M:
|
|
case NeroMediaTypes.NERO_MTYP_DVD_M_R:
|
|
return MediaType.DVDR;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_P:
|
|
case NeroMediaTypes.NERO_MTYP_DVD_P_R:
|
|
return MediaType.DVDPR;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_RAM:
|
|
return MediaType.DVDRAM;
|
|
case NeroMediaTypes.NERO_MTYP_ML:
|
|
case NeroMediaTypes.NERO_MTYP_MRW:
|
|
case NeroMediaTypes.NERO_MTYP_CDRW:
|
|
return MediaType.CDRW;
|
|
case NeroMediaTypes.NERO_MTYP_CDR:
|
|
return MediaType.CDR;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_ROM:
|
|
case NeroMediaTypes.NERO_MTYP_DVD_ANY:
|
|
case NeroMediaTypes.NERO_MTYP_DVD_ANY_R9:
|
|
case NeroMediaTypes.NERO_MTYP_DVD_ANY_OLD:
|
|
return MediaType.DVDROM;
|
|
case NeroMediaTypes.NERO_MTYP_CDROM:
|
|
return MediaType.CDROM;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_M_RW:
|
|
return MediaType.DVDRW;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_P_RW:
|
|
return MediaType.DVDPRW;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_P_R9:
|
|
return MediaType.DVDPRDL;
|
|
case NeroMediaTypes.NERO_MTYP_DVD_M_R9:
|
|
return MediaType.DVDRDL;
|
|
case NeroMediaTypes.NERO_MTYP_BD:
|
|
case NeroMediaTypes.NERO_MTYP_BD_ANY:
|
|
case NeroMediaTypes.NERO_MTYP_BD_ROM:
|
|
return MediaType.BDROM;
|
|
case NeroMediaTypes.NERO_MTYP_BD_R:
|
|
return MediaType.BDR;
|
|
case NeroMediaTypes.NERO_MTYP_BD_RE:
|
|
return MediaType.BDRE;
|
|
case NeroMediaTypes.NERO_MTYP_HD_DVD:
|
|
case NeroMediaTypes.NERO_MTYP_HD_DVD_ANY:
|
|
case NeroMediaTypes.NERO_MTYP_HD_DVD_ROM:
|
|
return MediaType.HDDVDROM;
|
|
case NeroMediaTypes.NERO_MTYP_HD_DVD_R:
|
|
return MediaType.HDDVDR;
|
|
case NeroMediaTypes.NERO_MTYP_HD_DVD_RW:
|
|
return MediaType.HDDVDRW;
|
|
default:
|
|
return MediaType.CD;
|
|
}
|
|
}
|
|
|
|
static TrackType NeroTrackModeToTrackType(DAOMode mode)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case DAOMode.Data:
|
|
case DAOMode.DataRaw:
|
|
case DAOMode.DataRawSub:
|
|
return TrackType.CDMode1;
|
|
case DAOMode.DataM2F1:
|
|
return TrackType.CDMode2Form1;
|
|
case DAOMode.DataM2F2:
|
|
return TrackType.CDMode2Form2;
|
|
case DAOMode.DataM2RawSub:
|
|
case DAOMode.DataM2Raw:
|
|
return TrackType.CDMode2Formless;
|
|
case DAOMode.Audio:
|
|
case DAOMode.AudioSub:
|
|
return TrackType.Audio;
|
|
default:
|
|
return TrackType.Data;
|
|
}
|
|
}
|
|
|
|
static ushort NeroTrackModeToBytesPerSector(DAOMode mode)
|
|
{
|
|
switch(mode)
|
|
{
|
|
case DAOMode.Data:
|
|
case DAOMode.DataM2F1:
|
|
return 2048;
|
|
case DAOMode.DataM2F2:
|
|
return 2336;
|
|
case DAOMode.DataRaw:
|
|
case DAOMode.DataM2Raw:
|
|
case DAOMode.Audio:
|
|
return 2352;
|
|
case DAOMode.DataM2RawSub:
|
|
case DAOMode.DataRawSub:
|
|
case DAOMode.AudioSub:
|
|
return 2448;
|
|
default:
|
|
return 2352;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Unsupported features
|
|
|
|
public override int GetMediaSequence()
|
|
{
|
|
return ImageInfo.mediaSequence;
|
|
}
|
|
|
|
public override int GetLastDiskSequence()
|
|
{
|
|
return ImageInfo.lastMediaSequence;
|
|
}
|
|
|
|
public override string GetDriveManufacturer()
|
|
{
|
|
return ImageInfo.driveManufacturer;
|
|
}
|
|
|
|
public override string GetDriveModel()
|
|
{
|
|
return ImageInfo.driveModel;
|
|
}
|
|
|
|
public override string GetDriveSerialNumber()
|
|
{
|
|
return ImageInfo.driveSerialNumber;
|
|
}
|
|
|
|
public override string GetMediaPartNumber()
|
|
{
|
|
return ImageInfo.mediaPartNumber;
|
|
}
|
|
|
|
public override string GetMediaManufacturer()
|
|
{
|
|
return ImageInfo.mediaManufacturer;
|
|
}
|
|
|
|
public override string GetMediaModel()
|
|
{
|
|
return ImageInfo.mediaModel;
|
|
}
|
|
|
|
public override string GetImageName()
|
|
{
|
|
return ImageInfo.imageName;
|
|
}
|
|
|
|
public override string GetImageCreator()
|
|
{
|
|
return ImageInfo.imageCreator;
|
|
}
|
|
|
|
public override string GetImageComments()
|
|
{
|
|
return ImageInfo.imageComments;
|
|
}
|
|
|
|
public override string GetMediaSerialNumber()
|
|
{
|
|
return ImageInfo.mediaSerialNumber;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
} |