www.pudn.com > NEROSDK5582.ZIP > NeroISODemo.h


/****************************************************************************** 
|* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
|* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
|* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
|* PARTICULAR PURPOSE. 
|*  
|* Copyright 1995-2002 Ahead Software AG. All Rights Reserved. 
|*----------------------------------------------------------------------------- 
|* NeroSDK / Samples 
|* 
|* PROGRAM: NeroISODemo.cpp 
|* 
|* PURPOSE: This demo implementation supports storing of files 
|*			or complete directory trees in the root directory 
|*			of an ISO track. Each subdirectory is scanned while 
|*			the Nero API builds its internal tree, so we don't 
|*			have to build a tree ourselves. 
|* 
|*			However, the implementation of CNeroIsoHandle becomes 
|*			very inefficient this way because each handle contains 
|*			the full path. It would be better for trees with many 
|*			files to use a tree and construct the full filename 
|*			from going back in the tree to the root. 
******************************************************************************/ 
 
 
#include "NeroIsoTrack.h" 
#include  
#include  
#include  
using namespace std; 
#ifdef LINUX 
#include "defs.h" 
#include "crtdll.h" 
#endif 
#include  
#include  
 
extern void Exit (int ret); 
 
// 
// This demo implementation supports storing of files 
// or complete directory trees in the root directory 
// of an ISO track. Each subdirectory is scanned while 
// the Nero API builds its internal tree, so we don't 
// have to build a tree ourselves. 
// 
// However, the implementation of CNeroIsoHandle becomes 
// very inefficient this way because each handle contains 
// the full path. It would be better for trees with many 
// files to use a tree and construct the full filename 
// from going back in the tree to the root. 
// 
 
// 
// Reading is done with ordinary FILEs. 
// 
class CDemoReadCallback : public CNeroDataCallback 
{ 
	FILE *m_pFile; 
public: 
	CDemoReadCallback (string sFullName)	// open file 
	{ 
		m_pFile = fopen (sFullName.c_str (), "rb"); 
	} 
	~CDemoReadCallback ()					// delete file 
	{ 
		if (m_pFile) { 
			fclose (m_pFile); 
		} 
	} 
	virtual DWORD IOCallback (BYTE *pBuffer, DWORD dwLen)	// read from file 
	{ 
		int read = 0; 
	    
		if (m_pFile) { 
			read = fread (pBuffer, 1, dwLen, m_pFile); 
			if (read < 0) { 
				perror ("fread"); 
			} 
		} 
		return read; 
	} 
	virtual BOOL EOFCallback ()		{ return m_pFile && feof (m_pFile); }		// calls map to standard functions directly 
	virtual BOOL ErrorCallback ()	{ 
	   /* FIXME: no implementation for ferror() in crtdll. 
	    * so no errors occur here :-) */ 
	   /*return m_pFile && ferror (m_pFile);*/ 
	   return 0;		 
	} 
 
	BOOL Okay () { return m_pFile != NULL; }									// initialized okay? 
}; 
 
// 
// This callback is created by this handle from the full name 
// store in it: 
// 
class CDemoIsoHandle : public CNeroIsoHandle 
{ 
	string m_sFullName; 
public: 
	CDemoIsoHandle (string sFullName) : m_sFullName (sFullName) { } 
	virtual CNeroIsoHandle *Clone ()	{ return new CDemoIsoHandle (m_sFullName); } 
 
	virtual int GetFileName (char *strBuffer, UINT nBufferSize) 
	{ 
		// you can choose if files are read by Nero API or via callback 
		#if 1 
 
		// directly by API: give the name to the API 
		if (nBufferSize) { 
			strncpy (strBuffer, m_sFullName.c_str (), nBufferSize); 
			strBuffer[nBufferSize - 1] = 0; 
		} 
		return m_sFullName.length (); 
 
		#else 
 
		// via callback: refuse to give away the name 
		return 0; 
 
		#endif 
	} 
 
	 
	CNeroDataCallback *Open () 
	{ 
		CDemoReadCallback *pCallback = new CDemoReadCallback (m_sFullName); 
		// opening it may have failed 
		if (pCallback && !pCallback->Okay ()) { 
			delete pCallback; 
			pCallback = NULL; 
		} 
		return pCallback; 
	} 
}; 
 
// 
// reads the file/directory infos and gives them to the API 
// 
class CDemoIsoEntry : public CNeroIsoEntry 
{ 
	string	m_sFullName;		// name including full path 
	string	m_sFileName;		// the name within the current directory 
	__int64	m_i64Size;			// < 0 for directory, otherwise size of file  
	time_t	fileTime; 
 
public: 
	CDemoIsoEntry () { m_i64Size = -1; } 
	CDemoIsoEntry (const char *strFullName) { this->SetName (strFullName); } 
	 
	void SetName (const char *strFullName)		// read infos and remember everything 
	{ 
	   #ifndef LINUX 
		struct stat buf; 
	   #else 
	   	struct win_stat buf; 
	   #endif 
	    
		if (stat (strFullName,  
			  &buf)) { 
			perror (strFullName); 
			Exit (10); 
		} 
		m_sFullName = strFullName; 
 
		// find last occurance of either "/" or "\" 
		const char *name = strrchr (strFullName, '/'); 
		const char *tmp = strrchr (strFullName, '\\'); 
		if (!name) { 
			name = tmp; 
		} else if (tmp) { 
			if (tmp > name) { 
				name = tmp; 
			} 
		} 
		if (!name || !*name) { 
			name = strFullName; 
		} else { 
			name++; 
		} 
		m_sFileName = name; 
		m_i64Size = (buf.st_mode & _S_IFDIR) ? -1 : buf.st_size; 
 
		fileTime=buf.st_mtime; 
	} 
 
	virtual CNeroIsoIterator * CreateDirectoryIterator();	// implemented below because we have to define CDemoIsoIterator first 
	 
	virtual const char *       GetName ()					{ return m_sFileName.c_str (); } 
	virtual __int64            GetLength ()					{ return m_i64Size; } 
	virtual BOOL GetEntryTime(tm *tm) 
	{ 
		struct tm *time=localtime(&fileTime); 
		if (time==NULL)  
			return FALSE; 
		else 
		{ 
			*tm=*time; 
			return TRUE; 
		} 
	} 
	virtual CNeroIsoHandle *   CreateHandle ()				{ return new CDemoIsoHandle (m_sFullName); } 
}; 
 
// 
// Our iterator implements both interfaces and thus returns a pointer 
// to itself when asked for the current entry (but only while it really 
// has information about a file). 
// 
class CDemoIsoIterator : public CNeroIsoIterator, public CDemoIsoEntry 
{ 
	long m_lHandle;				// for searching with findfirst/next/close() 
	_finddata_t m_FindData;		// the result of last call to findfirst/next() 
	string m_sPath;				// the directory we are searching in 
	BOOL m_bValid;				// we currently have valid information 
 
 
	// The information about the current entry are stored in the base 
	// class CDemoIsoEntry. FindData2Entry() sets them there: 
	void FindData2Entry () 
	{ 
		// skip current and parent directory entries 
		while (!strcmp (m_FindData.name, ".") || !strcmp (m_FindData.name, "..")) { 
			this->Next (); 
			if (!m_bValid) { 
				// found end of directory, give up 
				return; 
			} 
		} 
 
		// build name 
		string sFullName = m_sPath; 
		sFullName += "\\"; 
		sFullName += m_FindData.name; 
 
		// ask base class to analyze this name 
		this->SetName (sFullName.c_str ()); 
 
		// base class would have quit if there was a problem, 
		// so now we are fine 
		m_bValid = TRUE; 
	} 
 
public: 
	CDemoIsoIterator (const char *strPath) : m_sPath (strPath), m_bValid (FALSE) 
	{ 
		// start searching this directory for any file 
		string pattern = strPath; 
		pattern += "\\*"; 
		m_lHandle = _findfirst (pattern.c_str (), &m_FindData); 
		if (m_lHandle == -1) { 
			perror (strPath); 
			Exit (10); 
		} 
 
		// copy informations for first entry 
		this->FindData2Entry (); 
	} 
	~CDemoIsoIterator () { _findclose (m_lHandle); } 
 
	virtual CNeroIsoEntry *GetCurrentEntry () { return m_bValid ? this : NULL; }	// our base class _is_ the current entry if m_bValid is TRUE 
	virtual void Next () 
	{ 
		// invalidate ourself 
		m_bValid = FALSE; 
		if (_findnext (m_lHandle, &m_FindData) == -1) { 
			// quit unless the error indicates the end of the directory 
			if (errno != ENOENT) { 
				perror ("findnext"); 
				Exit (10); 
			} 
		} else { 
			// copy new infos 
			this->FindData2Entry (); 
		} 
	} 
}; 
 
// now that CDemoIsoIterator is defined we can implement this function 
CNeroIsoIterator * CDemoIsoEntry::CreateDirectoryIterator() 
{ 
	return new CDemoIsoIterator (m_sFullName.c_str ()); 
}; 
 
// 
// The root directory is implemented by a seperate class 
// which has a list of entries that are traversed by 
// a special iterator and also provides the other 
// ISO track options. 
// 
class CDemoIsoTrack : public CNeroIsoTrack 
{ 
	string m_sVolumeName;						// ISO volume name 
	typedef list  DemoList_t;	// type definition for storing them and 
	DemoList_t m_Entries;						// all entries in the root directory themselves 
 
	BOOL m_bUseJoliet; 
	BOOL m_bUseMode2; 
	BOOL m_bBurnISO; 
	BOOL m_bBurnUDF; 
 
	class CDemoRootIterator : public CNeroIsoIterator	// traverses any STL collection of CDemoIsoEntries 
	{ 
		DemoList_t::iterator m_End;						// STL end marker 
		DemoList_t::iterator m_Current;					// STL iterator 
 
	public: 
		CDemoRootIterator (DemoList_t &List) : m_End (List.end ()), m_Current (List.begin ()) { } 
		virtual CNeroIsoEntry *GetCurrentEntry ()	{ return m_Current != m_End ? &(*m_Current) : NULL; } 
		virtual void Next ()						{ m_Current++; } 
	}; 
 
public: 
	CDemoIsoTrack () 
	{ 
		m_bUseJoliet = TRUE; 
		m_bUseMode2 = FALSE; 
		m_bBurnISO = TRUE; 
		m_bBurnUDF = FALSE; 
	} 
 
	// modify settings for ISO track 
	void SetVolumeName (const char *strVolumeName)	{ m_sVolumeName = strVolumeName; } 
	void SetJoliet (BOOL bUseJoliet)				{ m_bUseJoliet = bUseJoliet; } 
	void SetMode2 (BOOL bUseMode2)					{ m_bUseMode2 = bUseMode2; } 
	void SetISO(BOOL b)								{ m_bBurnISO = b;} 
	void SetUDF(BOOL b)								{ m_bBurnUDF = b;} 
 
	// return settings 
	virtual const char *       GetName ()					{ return m_sVolumeName.c_str (); } 
	virtual BOOL               UseJoliet ()					{ return m_bUseJoliet; } 
	virtual BOOL               UseMode2 ()					{ return m_bUseMode2; } 
 
	// add a file/directory - the base name is kept in the ISO track, 
	// but the path is discarded, i.e. "C:\Dir1\Dir2" will be stored 
	// as ":\Dir2" on the disc. 
	void AddEntry (const char *strEntryName)		{ m_Entries.insert (m_Entries.end(), CDemoIsoEntry (strEntryName)); } 
 
	// return new iterator 
	virtual CNeroIsoIterator * CreateDirectoryIterator ()	{ return new CDemoRootIterator (m_Entries); } 
 
    virtual BOOL               BurnISO() { return m_bBurnISO; } // TRUE if ISO should be created 
    virtual BOOL               BurnUDF() { return m_bBurnUDF; } // TRUE if UDF should be created 
};