Open fengjiannan2010 opened 6 months ago
This is currently supported using DataFile.UdfFileProps.Extents. You can describe the file fragments via UdfExtent objects and add those objects to the DataFile.UdfFileProps.Extents list. BlockDevice will take into account the fragments.
Here is an example:
private static DataFile CreateFileSystemTree()
{
DataFile oRoot = Library.CreateDataFile();
oRoot.IsDirectory = true;
oRoot.FilePath = "\\";
oRoot.LongFilename = "\\";
for (int i = 0; i < _sourceFiles.Count; i++)
{
TFile file = _sourceFiles[i];
DataFile df = Library.CreateDataFile();
// it is a file
df.IsDirectory = false;
// filename long and short
df.LongFilename = Path.GetFileName(file.Path);
df.ShortFilename = "";
df.DataSource = DataSourceType.Disc; // it is already on the cd/dvd
df.DiscAddress = file.Extents[0].DiscAddress; // set the disc address from the first extent
df.FileSize = file.Extents[0].DiscSize; // and the size
if (file.Extents.Count > 1)
{
// We have multiple extents. We need to add them to DataFile.UdfFileProps.Extents
for (int j = 1; j < file.Extents.Count; j++)
{
UdfExtent ext = Library.CreateUdfExtent();
ext.Address = file.Extents[j].DiscAddress; // set the disc address
ext.Length = file.Extents[j].DiscSize; // and the size
df.UdfFileProps.Extents.Add(ext);
ext.Dispose();
}
}
oRoot.Children.Add(df);
// Must dispose the object
df.Dispose();
}
return oRoot;
}
Full code (for Windows):
using System;
using System.IO;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Runtime.InteropServices;
using PrimoSoftware.Burner;
namespace BlockDevice2
{
// Structure to keep the file extent information
public struct TExtent
{
// address on the CD/DVD
public int DiscAddress;
// size on the CD/DVD (in blocks)
public long DiscSize;
};
// Structure to keep the file information for BlockDevice
public class TFile
{
// full path to the file
public string Path;
// file extents
public List<TExtent> Extents = new List<TExtent>();
};
enum BurnOption
{
Unknown = 0,
Write, // write
ReadDiscID, // read
Erase // erase
}
class MainClass
{
// Size must be aligned to 16 blocks
private const int BLOCKS_PER_WRITE = 10 * 16;
/////////////////////////////////////////////
// Command line handlers
//
static void Usage()
{
Console.Write("BlockDevice [-e] [-i <sourcefile>] [-i <sourcefile>] [-i <sourcefile>]\n");
Console.Write(" -i sourcefile = file to burn, multiple files can be specified.\n");
Console.Write(" -e = erase RW disc. \n");
Console.Write(" -d = read and display temporary disc ID. \n");
}
static int ParseCommandLine(string[] args)
{
int i = 0 ;
string sCommand = "";
for (i=0; i < args.Length; i++)
{
sCommand = args[i];
//Input file
if (sCommand == "-i")
{
i++;
if (i == args.Length)
{
Usage();
return -1;
}
TFile f = new TFile();
f.Path = args[i];
_sourceFiles.Add(f);
continue;
}
//Erase
if (sCommand == "-e")
{
if (_burnOption != BurnOption.Unknown)
{
Usage();
return -1;
}
_burnOption = BurnOption.Erase;
continue;
}
// Read Disc ID
if (sCommand == "-d")
{
if (_burnOption != BurnOption.Unknown)
{
Usage();
return -1;
}
_burnOption = BurnOption.ReadDiscID;
continue;
}
}
if (_burnOption == BurnOption.Unknown)
_burnOption = BurnOption.Write;
if ((BurnOption.Erase != _burnOption) && (BurnOption.ReadDiscID != _burnOption) && (_sourceFiles.Count == 0))
{
Usage();
return -1;
}
return 0;
}
private static Device SelectDevice(Engine engine)
{
int ch;
int nDevice;
// A variable to keep the return value
Device device = null;
// Get a device enumerator object. At the time of the creation it will enumerate fileSize CD and DVD Writers installed in the system
DeviceEnumerator Enum = engine.GetDevices();
// Get the number of available devices
int nCount = Enum.Count;
// If nCount is 0 most likely there are not any CD/DVD writer drives installed in the system
if (0 == nCount)
{
Console.WriteLine("No devices available.");
// Release the enumrator to free any allocated resources
Enum.Dispose();
return null;
}
// Now ask the user to choose a device
do
{
Console.WriteLine("Select a device:");
// Loop through fileSize the devices and show their name and description
for (int i = 0; i < nCount; i++)
{
// Get device instance from the enumerator
device = Enum.GetItem(i);
// GetItem may return null if the device was locked
if (null != device)
{
// Get device description
string strName;
strName = device.Description;
// When showing the devices, show also the drive letter
Console.WriteLine(" ({0}:\\) {1}:", device.DriveLetter, strName);
device.Dispose();
}
}
Console.WriteLine("Enter drive letter:");
ch = getch();
nDevice = Library.GetCDROMIndexFromLetter(Convert.ToChar(ch));
}
while (nDevice < 0 || nDevice > nCount - 1);
device = Enum.GetItem(nDevice);
if (null == device)
{
Enum.Dispose();
return null;
}
Enum.Dispose();
return device;
}
private static void WaitUnitReady(Device oDevice)
{
int eError = oDevice.UnitReady;
while (eError != (int)DeviceError.Success)
{
Console.WriteLine("Unit not ready: {0}",oDevice.LastError.ToString("x"));
System.Threading.Thread.Sleep(1000);
eError = oDevice.UnitReady;
}
Console.WriteLine("Unit is ready.");
}
/////////////
// Erase
private static void Erase(Device oDevice)
{
MediaProfile mp = oDevice.MediaProfile;
switch(mp)
{
// DVD+RW (needs to be formatted before the disc can be used)
case MediaProfile.DvdPlusRw:
{
Console.WriteLine("Formatting...");
BgFormatStatus fmt = oDevice.BgFormatStatus;
switch(fmt)
{
case BgFormatStatus.NotFormatted:
oDevice.Format(FormatType.DvdPlusRwFull);
break;
case BgFormatStatus.Partial:
oDevice.Format(FormatType.DvdPlusRwRestart);
break;
}
}
break;
// DVD-RW, Sequential Recording (default for new DVD-RW)
case MediaProfile.DvdMinusRwSeq:
Console.WriteLine("Erasing...");
oDevice.Erase(EraseType.Minimal);
break;
// DVD-RW, Restricted Overwrite (DVD-RW was formatted initially)
case MediaProfile.DvdMinusRwRo:
Console.WriteLine("Formatting...\n");
oDevice.Format(FormatType.DvdMinusRwQuick);
break;
case MediaProfile.CdRw:
Console.WriteLine("Erasing...");
oDevice.Erase(EraseType.Minimal);
break;
}
// Must be DVD-R, DVD+R or CD-R
}
private static DataFile CreateFileSystemTree()
{
DataFile oRoot = Library.CreateDataFile();
oRoot.IsDirectory = true;
oRoot.FilePath = "\\";
oRoot.LongFilename = "\\";
for (int i = 0; i < _sourceFiles.Count; i++)
{
TFile file = _sourceFiles[i];
DataFile df = Library.CreateDataFile();
// it is a file
df.IsDirectory = false;
// filename long and short
df.LongFilename = Path.GetFileName(file.Path);
df.ShortFilename = "";
df.DataSource = DataSourceType.Disc; // it is already on the cd/dvd
df.DiscAddress = file.Extents[0].DiscAddress; // set the disc address from the first extent
df.FileSize = file.Extents[0].DiscSize; // and the size
if (file.Extents.Count > 1)
{
// We have multiple extents. We need to add them to DataFile.UdfFileProps.Extents
for (int j = 1; j < file.Extents.Count; j++)
{
UdfExtent ext = Library.CreateUdfExtent();
ext.Address = file.Extents[j].DiscAddress; // set the disc address
ext.Length = file.Extents[j].DiscSize; // and the size
df.UdfFileProps.Extents.Add(ext);
ext.Dispose();
}
}
oRoot.Children.Add(df);
// Must dispose the object
df.Dispose();
}
return oRoot;
}
private static void PrintError(PrimoSoftware.Burner.BlockDevice oBlockDevice, Device oDevice)
{
BlockDeviceError eError = oBlockDevice.LastError;
int iSystemError = 0;
if (BlockDeviceError.SystemError == eError)
{
iSystemError = oBlockDevice.LastSystemError;
StringBuilder sMessage = new StringBuilder(1024);
FormatMessage(0x1000, IntPtr.Zero, (int)iSystemError, 0, sMessage, 1024, IntPtr.Zero);
Console.WriteLine("IDataDisc System Error: {0} - {1}", iSystemError, sMessage);
}
else if (BlockDeviceError.DeviceError == eError && null != oDevice)
{
int iDeviceError = oDevice.LastError;
if ( (int)DeviceError.SystemError == iDeviceError)
{
iSystemError = oDevice.LastSystemError;
StringBuilder sMessage = new StringBuilder(1024);
FormatMessage(0x1000, IntPtr.Zero, iSystemError, 0, sMessage, 1024, IntPtr.Zero);
Console.WriteLine("IDevice System Error: {0} - {1}", (int)iSystemError, sMessage);
}
else
Console.WriteLine("IDevice Error: {0}", oDevice.LastError);
}
else
Console.WriteLine("IDataDisc Error: {0}", (int)eError);
}
private static bool BurnFile(PrimoSoftware.Burner.BlockDevice bd, int fileIndex, long offset, long length)
{
// Get the start address at which BlockDevice will start writing.
int discAddress = bd.WriteAddress;
FileStream file = null;
try
{
// Open file
file = File.OpenRead(_sourceFiles[fileIndex].Path);
file.Seek(offset, SeekOrigin.Begin);
}
catch (IOException ex)
{
Debug.WriteLine(ex.Message);
return false;
}
// Set up write progress counters
long current = 0;
long fileSize = (long)length;
// Allocate read buffer
byte[] buffer = new byte[(int)BlockSize.Dvd * BLOCKS_PER_WRITE];
// Write the data
while(current < fileSize)
{
int read = file.Read(buffer, 0, (int)BlockSize.Dvd * BLOCKS_PER_WRITE);
int written = 0;
if (read != 0)
{
// Align on 2048 bytes
if ((read % ((int)BlockSize.Dvd)) != 0)
read += (int)BlockSize.Dvd - (read % (int)BlockSize.Dvd);
// Write the data
if(!bd.Write(buffer, (int)read, ref written))
break;
if (0 == written)
break;
}
// Update current position (bytes)
current += (long)written;
}
// Close file
file.Close();
// Create new extent
TExtent ext = new TExtent();
ext.DiscAddress = discAddress;
ext.DiscSize = fileSize;
// add the new extent to the list
_sourceFiles[fileIndex].Extents.Add(ext);
return true;
}
private static bool Burn(PrimoSoftware.Burner.BlockDevice bd)
{
// Open block device
if (!bd.Open())
return false;
// Burn fileSize files that the user specified.
// The code below demonstrates how you can burn the first few bytes of a file last.
// For demo purposes split each file in half and burn first half after the second.
for (int i = 0; i < _sourceFiles.Count; i++)
{
FileInfo fi = new FileInfo(_sourceFiles[i].Path);
// Calculate the first half size and align it to 16 * BlockSize.Dvd(2048).
// The alignment to 16 * BlockSize.Dvd must be done for all partitions except the last one.
long firstHalfSize = (fi.Length / 2);
firstHalfSize = (firstHalfSize / (16 * (long) BlockSize.Dvd)) * (16 * (long) BlockSize.Dvd);
// Calculate the second half size. Since it is the last partiiton of the file we do not have to align it to 2048 byte
long secondHalfSize = fi.Length - firstHalfSize;
// Burn second partion first. BurnFile will add a new extent to _sourceFiles[i].
BurnFile(bd, i, firstHalfSize, secondHalfSize);
// Burn first partition last. BurnFile will add a new extent to _sourceFiles[i].
BurnFile(bd, i, 0, firstHalfSize);
// IMPORTANT: Reverse the extents here so the extent of the second partition comes after the extent of the first partition
_sourceFiles[i].Extents.Reverse();
}
// Close block device
if (!bd.Close())
return false;
// Create files system tree
DataFile fileSystem = CreateFileSystemTree();
// Finalize disc
if (!bd.FinalizeDisc(fileSystem, "HPCDEDISC", true, true, false))
{
fileSystem.Dispose();
return false;
}
fileSystem.Dispose();
return true;
}
private static bool Burn(Device dev)
{
Debug.Assert((dev != null));
// Set write speed
int maxSpeedKB = dev.MaxWriteSpeedKB;
if (dev.MediaIsDVD)
{
Console.WriteLine("Setting write speed to {0}x", Math.Round((double)maxSpeedKB / Speed1xKB.DVD, 1));
dev.WriteSpeedKB = maxSpeedKB;
}
else
{
Console.WriteLine("Setting write speed to {0}x", Math.Round((double)maxSpeedKB / Speed1xKB.CD));
dev.WriteSpeedKB = maxSpeedKB;
}
//Create block device object
PrimoSoftware.Burner.BlockDevice bd = Library.CreateBlockDevice();
// Set device
bd.Device = dev;
// Set temporary disc ID
bd.TempDiscID = "DISCID";
// Burn
bool bRes = Burn(bd);
// Check for errors
if (!bRes)
{
PrintError(bd, dev);
bd.Dispose();
return false;
}
bd.Dispose();
return true;
}
private static void ReadDiscID(Device dev)
{
//Create block device object
PrimoSoftware.Burner.BlockDevice bd = Library.CreateBlockDevice();
//Set device
bd.Device = dev;
// Open block device
if (bd.Open(BlockDeviceOpenFlags.Read))
{
// Show information about the disc in the device
Console.WriteLine();
Console.WriteLine("Disc Info");
Console.WriteLine("---------");
Console.WriteLine("Finalized: {0}", bd.IsFinalized);
Console.WriteLine("Temporary Disc ID: {0}", bd.TempDiscID);
Console.WriteLine();
// Close block device
bd.Close();
}
bd.Dispose();
}
[STAThread]
static int Main(string[] args)
{
int iParseResult = ParseCommandLine(args);
if (0 != iParseResult)
return iParseResult;
//////////////////////////////////////////////////////////////////////////////////////////
// 1) Create an engine object
// Create an instance of IEngine. That is the main iterface that can be used to enumerate
// fileSize devices in the system
Library.Initialize();
Engine oEngine = Library.CreateEngine();
///////////////////////////////////////////////////////////////////////////////////////////
// 2) Inititialize the engine object
// Initialize the engine
oEngine.Initialize();
Library.EnableTraceLog(null, true);
///////////////////////////////////////////////////////////////////////////////////////////
// 3) Select a device (CD/DVD-RW drive)
// The SelectDevice function allows the user to select a device and then
// returns an instance of IDevice.
Device oDevice = SelectDevice(oEngine);
if (oDevice == null)
{
// Something went wrong. Shutdown the engine.
oEngine.Shutdown();
// Release the engine instance. That will free any allocated resources
oEngine.Dispose();
// We are done.
Library.Shutdown();
return -1;
}
// Close the device tray and refresh disc information
if (oDevice.Eject(false))
{
// Wait for the device to become ready
WaitUnitReady(oDevice);
// Refresh disc information. Need to call this method when media changes
oDevice.Refresh();
}
// Check if disc is present
if (MediumReady.MediumPresent != oDevice.MediumReady)
{
Console.WriteLine("Please insert a blank disc in the device and try again.");
oDevice.Dispose();
oEngine.Shutdown();
oEngine.Dispose();
Library.Shutdown();
return -1;
}
// Do the work now
switch (_burnOption)
{
case BurnOption.Erase:
Erase(oDevice);
break;
case BurnOption.ReadDiscID:
ReadDiscID(oDevice);
break;
default:
{
// Check if disc is blank
if (MediaProfile.DvdPlusRw != oDevice.MediaProfile && !oDevice.MediaIsBlank)
{
Console.WriteLine("Please insert a blank disc in the device and try again.");
oDevice.Dispose();
oEngine.Shutdown();
oEngine.Dispose();
Library.Shutdown();
return -1;
}
Burn(oDevice);
}
break;
}
// Dismount the device volume. This forces the operating system to refresh the CD file system.
oDevice.Dismount();
// Release IDevice object
oDevice.Dispose();
// Shutdown the engine
oEngine.Shutdown();
// Release the engine instance
oEngine.Dispose();
Library.DisableTraceLog();
Library.Shutdown();
return 0;
}
private static List<TFile> _sourceFiles = new List<TFile>();
private static BurnOption _burnOption = BurnOption.Unknown;
[DllImport("msvcrt.dll", EntryPoint = "_getch")]
protected static extern int getch();
[DllImport("kernel32.dll")]
public static extern int FormatMessage(int lFlags, IntPtr lSource, int lMessageId, int lLanguageId, StringBuilder sBuffer, int lSize, IntPtr lArguments);
}
}
thanks
---- Replied Message ---- | From | @.> | | Date | 04/30/2024 11:52 | | To | @.> | | Cc | @.>@.> | | Subject | Re: [primoburner/primoburner-support] UDF File System Layout (Issue #6) |
Full code (for Windows):
using System;using System.IO;using System.Collections.Generic;using System.Diagnostics;using System.Text;using System.Runtime.InteropServices;using PrimoSoftware.Burner;namespaceBlockDevice2{// Structure to keep the file extent informationpublicstructTExtent{// address on the CD/DVDpublicintDiscAddress;// size on the CD/DVD (in blocks)publiclongDiscSize;};// Structure to keep the file information for BlockDevicepublicclassTFile{// full path to the filepublicstringPath;// file extentspublicList
_sourceFiles.Add(f);continue;}//Eraseif(sCommand=="-e"){if(_burnOption!= BurnOption.Unknown){
Usage();return-1;}_burnOption= BurnOption.Erase;continue;}// Read Disc IDif(sCommand=="-d"){if(_burnOption!= BurnOption.Unknown){
Usage();return-1;}_burnOption= BurnOption.ReadDiscID;continue;}}if(_burnOption== BurnOption.Unknown)_burnOption= BurnOption.Write;if((BurnOption.Erase !=_burnOption)&&(BurnOption.ReadDiscID !=_burnOption)&&(_sourceFiles.Count ==0)){
Usage();return-1;}return0;}privatestatic Device SelectDevice(Engineengine){intch;intnDevice;// A variable to keep the return valueDevicedevice=null;// Get a device enumerator object. At the time of the creation it will enumerate fileSize CD and DVD Writers installed in the systemDeviceEnumeratorEnum= engine.GetDevices();// Get the number of available devicesintnCount= Enum.Count;// If nCount is 0 most likely there are not any CD/DVD writer drives installed in the system if(0==nCount){
Console.WriteLine("No devices available.");// Release the enumrator to free any allocated resources
Enum.Dispose();returnnull;}// Now ask the user to choose a devicedo{
Console.WriteLine("Select a device:");// Loop through fileSize the devices and show their name and descriptionfor(inti=0;i<nCount;i++){// Get device instance from the enumeratordevice= Enum.GetItem(i);// GetItem may return null if the device was lockedif(null!=device){// Get device descriptionstringstrName;strName= device.Description;// When showing the devices, show also the drive letter
Console.WriteLine(" ({0}:\\) {1}:", device.DriveLetter, strName);
device.Dispose();}}
Console.WriteLine("Enter drive letter:");ch= getch();nDevice= Library.GetCDROMIndexFromLetter(Convert.ToChar(ch));}while(nDevice<0||nDevice>nCount-1);device= Enum.GetItem(nDevice);if(null==device){
Enum.Dispose();returnnull;}
Enum.Dispose();returndevice;}privatestaticvoidWaitUnitReady(DeviceoDevice){inteError= oDevice.UnitReady;while(eError!=(int)DeviceError.Success){
Console.WriteLine("Unit not ready: {0}",oDevice.LastError.ToString("x"));
System.Threading.Thread.Sleep(1000);eError= oDevice.UnitReady;}
Console.WriteLine("Unit is ready.");}/////////////// EraseprivatestaticvoidErase(DeviceoDevice){MediaProfilemp= oDevice.MediaProfile;switch(mp){// DVD+RW (needs to be formatted before the disc can be used)case MediaProfile.DvdPlusRw:{
Console.WriteLine("Formatting...");BgFormatStatusfmt= oDevice.BgFormatStatus;switch(fmt){case BgFormatStatus.NotFormatted:
oDevice.Format(FormatType.DvdPlusRwFull);break;case BgFormatStatus.Partial:
oDevice.Format(FormatType.DvdPlusRwRestart);break;}}break;// DVD-RW, Sequential Recording (default for new DVD-RW)case MediaProfile.DvdMinusRwSeq:
Console.WriteLine("Erasing...");
oDevice.Erase(EraseType.Minimal);break;// DVD-RW, Restricted Overwrite (DVD-RW was formatted initially)case MediaProfile.DvdMinusRwRo:
Console.WriteLine("Formatting...\n");
oDevice.Format(FormatType.DvdMinusRwQuick);break;case MediaProfile.CdRw:
Console.WriteLine("Erasing...");
oDevice.Erase(EraseType.Minimal);break;}// Must be DVD-R, DVD+R or CD-R}privatestatic DataFile CreateFileSystemTree(){DataFileoRoot= Library.CreateDataFile();
oRoot.IsDirectory =true;
oRoot.FilePath ="\\";
oRoot.LongFilename ="\\";for(inti=0;i< _sourceFiles.Count;i++){TFilefile= _sourceFiles[i];DataFiledf= Library.CreateDataFile();// it is a file
df.IsDirectory =false;// filename long and short
df.LongFilename = Path.GetFileName(file.Path);
df.ShortFilename ="";
df.DataSource = DataSourceType.Disc;// it is already on the cd/dvd
df.DiscAddress = file.Extents[0].DiscAddress;// set the disc address from the first extent
df.FileSize = file.Extents[0].DiscSize;// and the sizeif(file.Extents.Count >1){// We have multiple extents. We need to add them to DataFile.UdfFileProps.Extentsfor(intj=1;j< file.Extents.Count;j++){UdfExtentext= Library.CreateUdfExtent();
ext.Address = file.Extents[j].DiscAddress;// set the disc address
ext.Length = file.Extents[j].DiscSize;// and the size
df.UdfFileProps.Extents.Add(ext);
ext.Dispose();}}
oRoot.Children.Add(df);// Must dispose the object
df.Dispose();}returnoRoot;}privatestaticvoidPrintError(PrimoSoftware.Burner.BlockDevice oBlockDevice,DeviceoDevice){BlockDeviceErroreError= oBlockDevice.LastError;intiSystemError=0;if(BlockDeviceError.SystemError ==eError){iSystemError= oBlockDevice.LastSystemError;StringBuildersMessage=new StringBuilder(1024);
FormatMessage(0x1000, IntPtr.Zero,(int)iSystemError,0, sMessage,1024, IntPtr.Zero);
Console.WriteLine("IDataDisc System Error: {0} - {1}", iSystemError, sMessage);}elseif(BlockDeviceError.DeviceError ==eError&&null!=oDevice){intiDeviceError= oDevice.LastError;if((int)DeviceError.SystemError ==iDeviceError){iSystemError= oDevice.LastSystemError;StringBuildersMessage=new StringBuilder(1024);
FormatMessage(0x1000, IntPtr.Zero, iSystemError,0, sMessage,1024, IntPtr.Zero);
Console.WriteLine("IDevice System Error: {0} - {1}",(int)iSystemError, sMessage);}else
Console.WriteLine("IDevice Error: {0}", oDevice.LastError);}else
Console.WriteLine("IDataDisc Error: {0}",(int)eError);}privatestaticboolBurnFile(PrimoSoftware.Burner.BlockDevice bd,intfileIndex,longoffset,longlength){// Get the start address at which BlockDevice will start writing.intdiscAddress= bd.WriteAddress;FileStreamfile=null;try{// Open filefile= File.OpenRead(_sourceFiles[fileIndex].Path);
file.Seek(offset, SeekOrigin.Begin);}catch(IOExceptionex){
Debug.WriteLine(ex.Message);returnfalse;}// Set up write progress counterslongcurrent=0;longfileSize=(long)length;// Allocate read bufferbyte[]buffer=newbyte[(int)BlockSize.Dvd *BLOCKS_PER_WRITE];// Write the datawhile(current<fileSize){intread= file.Read(buffer,0,(int)BlockSize.Dvd *BLOCKS_PER_WRITE);intwritten=0;if(read!=0){// Align on 2048 bytesif((read%((int)BlockSize.Dvd))!=0)read+=(int)BlockSize.Dvd -(read%(int)BlockSize.Dvd);// Write the dataif(!bd.Write(buffer,(int)read,ref written))break;if(0==written)break;}// Update current position (bytes)current+=(long)written;}// Close file
file.Close();// Create new extentTExtentext=new TExtent();
ext.DiscAddress =discAddress;
ext.DiscSize =fileSize;// add the new extent to the list
_sourceFiles[fileIndex].Extents.Add(ext);returntrue;}privatestaticboolBurn(PrimoSoftware.Burner.BlockDevice bd){// Open block device if(!bd.Open())returnfalse;// Burn fileSize files that the user specified. // The code below demonstrates how you can burn the first few bytes of a file last.// For demo purposes split each file in half and burn first half after the second.for(inti=0;i< _sourceFiles.Count;i++){FileInfofi=new FileInfo(_sourceFiles[i].Path);// Calculate the first half size and align it to 16 * BlockSize.Dvd(2048).// The alignment to 16 * BlockSize.Dvd must be done for all partitions except the last one.longfirstHalfSize=(fi.Length /2);firstHalfSize=(firstHalfSize/(16*(long) BlockSize.Dvd))*(16*(long) BlockSize.Dvd);// Calculate the second half size. Since it is the last partiiton of the file we do not have to align it to 2048 bytelongsecondHalfSize= fi.Length -firstHalfSize;// Burn second partion first. BurnFile will add a new extent to _sourceFiles[i].
BurnFile(bd, i, firstHalfSize, secondHalfSize);// Burn first partition last. BurnFile will add a new extent to _sourceFiles[i].
BurnFile(bd, i,0, firstHalfSize);// IMPORTANT: Reverse the extents here so the extent of the second partition comes after the extent of the first partition
_sourceFiles[i].Extents.Reverse();}// Close block deviceif(!bd.Close())returnfalse;// Create files system treeDataFilefileSystem= CreateFileSystemTree();// Finalize discif(!bd.FinalizeDisc(fileSystem,"HPCDEDISC",true,true,false)){
fileSystem.Dispose();returnfalse;}
fileSystem.Dispose();returntrue;}privatestaticboolBurn(Devicedev){
Debug.Assert((dev!=null));// Set write speedintmaxSpeedKB= dev.MaxWriteSpeedKB;if(dev.MediaIsDVD){
Console.WriteLine("Setting write speed to {0}x", Math.Round((double)maxSpeedKB / Speed1xKB.DVD,1));
dev.WriteSpeedKB =maxSpeedKB;}else{
Console.WriteLine("Setting write speed to {0}x", Math.Round((double)maxSpeedKB / Speed1xKB.CD));
dev.WriteSpeedKB =maxSpeedKB;}//Create block device object
PrimoSoftware.Burner.BlockDevice bd= Library.CreateBlockDevice();// Set device
bd.Device =dev;// Set temporary disc ID
bd.TempDiscID ="DISCID";// Burn boolbRes= Burn(bd);// Check for errorsif(!bRes){
PrintError(bd, dev);
bd.Dispose();returnfalse;}
bd.Dispose();returntrue;}privatestaticvoidReadDiscID(Devicedev){//Create block device object
PrimoSoftware.Burner.BlockDevice bd= Library.CreateBlockDevice();//Set device
bd.Device =dev;// Open block device if(bd.Open(BlockDeviceOpenFlags.Read)){// Show information about the disc in the device
Console.WriteLine();
Console.WriteLine("Disc Info");
Console.WriteLine("---------");
Console.WriteLine("Finalized: {0}", bd.IsFinalized);
Console.WriteLine("Temporary Disc ID: {0}", bd.TempDiscID);
Console.WriteLine();// Close block device
bd.Close();}
bd.Dispose();}[STAThread]staticintMain(string[]args){intiParseResult= ParseCommandLine(args);if(0!=iParseResult)returniParseResult;//////////////////////////////////////////////////////////////////////////////////////////// 1) Create an engine object// Create an instance of IEngine. That is the main iterface that can be used to enumerate // fileSize devices in the system
Library.Initialize();EngineoEngine= Library.CreateEngine();///////////////////////////////////////////////////////////////////////////////////////////// 2) Inititialize the engine object// Initialize the engine
oEngine.Initialize();
Library.EnableTraceLog(null,true);///////////////////////////////////////////////////////////////////////////////////////////// 3) Select a device (CD/DVD-RW drive)// The SelectDevice function allows the user to select a device and then // returns an instance of IDevice.DeviceoDevice= SelectDevice(oEngine);if(oDevice==null){// Something went wrong. Shutdown the engine.
oEngine.Shutdown();// Release the engine instance. That will free any allocated resources
oEngine.Dispose();// We are done.
Library.Shutdown();return-1;}// Close the device tray and refresh disc informationif(oDevice.Eject(false)){// Wait for the device to become ready
WaitUnitReady(oDevice);// Refresh disc information. Need to call this method when media changes
oDevice.Refresh();}// Check if disc is presentif(MediumReady.MediumPresent != oDevice.MediumReady){
Console.WriteLine("Please insert a blank disc in the device and try again.");
oDevice.Dispose();
oEngine.Shutdown();
oEngine.Dispose();
Library.Shutdown();return-1;}// Do the work nowswitch(_burnOption){case BurnOption.Erase:
Erase(oDevice);break;case BurnOption.ReadDiscID:
ReadDiscID(oDevice);break;default:{// Check if disc is blankif(MediaProfile.DvdPlusRw != oDevice.MediaProfile &&!oDevice.MediaIsBlank){
Console.WriteLine("Please insert a blank disc in the device and try again.");
oDevice.Dispose();
oEngine.Shutdown();
oEngine.Dispose();
Library.Shutdown();return-1;}
Burn(oDevice);}break;}// Dismount the device volume. This forces the operating system to refresh the CD file system.
oDevice.Dismount();// Release IDevice object
oDevice.Dispose();// Shutdown the engine
oEngine.Shutdown();// Release the engine instance
oEngine.Dispose();
Library.DisableTraceLog();
Library.Shutdown();return0;}privatestaticList<TFile>_sourceFiles=newList<TFile>();privatestaticBurnOption_burnOption= BurnOption.Unknown;[DllImport("msvcrt.dll", EntryPoint ="_getch")]protectedstaticexternintgetch();[DllImport("kernel32.dll")]publicstaticexternintFormatMessage(intlFlags,IntPtrlSource,intlMessageId,intlLanguageId,StringBuildersBuffer,intlSize,IntPtrlArguments);}}
— Reply to this email directly, view it on GitHub, or unsubscribe. You are receiving this because you authored the thread.Message ID: @.***>
When burning a 100GB file onto a disc under normal circumstances, I need to establish the file system layout, specifying the starting address, file size, file name, and file attributes for the file to be burned. Now, I wish to be able to write the file in fragments, with each fragment being 10GB, allowing for the possibility of fragment write failures to be rewritten during the writing process. The final file layout will need to be modified into a UDF linked list, specifying all segments of the file as well as the starting address and size of each fragment.
To meet this requirement, you can utilize the Universal Disk Format (UDF) file system to manage data on the optical disc. UDF is a file system used for optical discs and other removable storage media, offering support for high-capacity storage and the ability to dynamically add/remove files.
In the UDF file system, files are organized into a series of descriptors and data areas. For large files, UDF supports segmented storage, facilitating handling of large files and allowing segmented writing. You can employ UDF's linked list structure to track file segments and their associated information.
Below is a simplified layout example of a UDF file system:
For your requirements, here's a modification plan for the UDF file system layout:
When implementing the UDF file system, consider the UDF specifications and related file system operations. You may need to use specialized UDF file system libraries or tools to build and manage the UDF file system.
I want to write large files in this way and store them in UDF partitions. I read large files through network streaming and write them using BlockDevice. Due to network reasons, the data is written abnormally and the entire disc becomes unusable. I need to use a blank disc to rewrite. If I write according to file fragments and record the fragment information (address, size, file name), and finally organize it into a UDF file system, can PrimoBurner support the UDF partition storage interface?