ISOTrack.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. #include "BurnCore.h"
  2. #include "FindFile.h"
  3. //---------------------------------------------------------------------------------
  4. void StoreFileName (char (& shortFilename) [252], char * psLongFilename, LPCSTR psFilename)
  5. {
  6. // If filename can fit in the old field, store it there
  7. // to prevent unnecessary allocation. If not, allocate
  8. // a sufficient buffer to hold the string.
  9. //
  10. int iLen = strlen (psFilename);
  11. if (iLen < sizeof (shortFilename))
  12. {
  13. strcpy (shortFilename, psFilename);
  14. }
  15. else
  16. {
  17. psLongFilename = new char [iLen + 1];
  18. if (psLongFilename != NULL)
  19. {
  20. strcpy (psLongFilename, psFilename);
  21. }
  22. }
  23. }
  24. inline LPCSTR GetFilename (const NERO_ISO_ITEM * pItem)
  25. {
  26. return (pItem->longFileName != NULL)? pItem->longFileName: pItem->fileName;
  27. }
  28. //---------------------------------------------------------------------------------
  29. void DeleteIsoItemTree (NERO_ISO_ITEM * pItem)
  30. {
  31. // First free our own long filename strings, then free the whole tree.
  32. //
  33. FreeOurOwnResources (pItem);
  34. NeroFreeIsoItemTree (pItem);
  35. }
  36. //---------------------------------------------------------------------------------
  37. void FreeOurOwnResources (NERO_ISO_ITEM * pItem)
  38. {
  39. // Step through the tree until the
  40. // ISO item tree pointer becomes NULL
  41. while (NULL != pItem)
  42. {
  43. NERO_ISO_ITEM* pNextItem = pItem->nextItem;
  44. if (pItem->isDirectory)
  45. {
  46. // We have encountered another ISO item tree;
  47. // recurse another level.
  48. FreeOurOwnResources (pItem->subDirFirstItem);
  49. }
  50. // It the item is not a reference, free its associated long
  51. // filenames, if any.
  52. //
  53. if (!pItem->isReference)
  54. {
  55. delete pItem->longFileName;
  56. delete (char *) pItem->longSourceFilePath;
  57. }
  58. pItem = pNextItem;
  59. }
  60. }
  61. //---------------------------------------------------------------------------------
  62. EXITCODE GetIsoTrack (string s_VolumeName,const CFileList *fList,CNeroIsoTrack** ppIsoTrack, NERO_ISO_ITEM** ppItem)
  63. {
  64. *ppIsoTrack = NULL;
  65. // Iterate through the file list and it each one to the tree.
  66. // If directory is stumbled upon, recurse it and it all of
  67. // its contents.
  68. for (CFileList::const_iterator it=fList->begin();
  69. it!=fList->end();it++)
  70. {
  71. NERO_ISO_ITEM* pItem=NULL;
  72. EXITCODE code;
  73. // Create a tree from the filename supplied.
  74. code = CreateIsoTree ((*it)->Recursive, (*it)->szLocalPath.c_str(), &pItem);
  75. // If there was a problem creating the tree then delete
  76. // the whole tree that has been created so far and
  77. // return the error code.
  78. if (code != EXITCODE_OK)
  79. {
  80. DeleteIsoItemTree (*ppItem);
  81. *ppItem=NULL;
  82. return code;
  83. }
  84. // Merge the new track with the existing one. The user could
  85. // specify similar paths/content on the command line. We must make
  86. // sure the duplicates are weeded out. If return value is false,
  87. // we need to quit.
  88. //
  89. if (!MergeIsoTrack (ppItem, pItem))
  90. {
  91. return EXITCODE_FAILED_TO_CREATE_ISO_TRACK;
  92. }
  93. }
  94. if (NULL != *ppItem)
  95. {
  96. // This is used only for debugging purposese. Never allow this
  97. // call to take place in Release code.
  98. //
  99. // DebugPrintIsoTrack (*ppItem);
  100. DWORD dwFlags=NCITEF_USE_JOLIET|NCITEF_CREATE_ISO_FS;
  101. NERO_CITE_ARGS citeArgs;
  102. memset (&citeArgs, 0, sizeof (citeArgs));
  103. citeArgs.dwBurnOptions = dwFlags;
  104. citeArgs.name = s_VolumeName.c_str();
  105. citeArgs.firstRootItem = *ppItem;
  106. /*
  107. citeArgs.abstract = params.GetAbstract ();
  108. citeArgs.application = params.GetApplication ();
  109. citeArgs.bibliographic = params.GetBibliographic ();
  110. citeArgs.copyright = params.GetCopyright ();
  111. citeArgs.dataPreparer = params.GetDataPreparer ();
  112. citeArgs.publisher = params.GetPublisher ();
  113. citeArgs.systemIdentifier = params.GetSystemIdentifier ();
  114. citeArgs.volumeSet = params.GetVolumeSet ();
  115. */
  116. // Finally, create the ISO track.
  117. *ppIsoTrack = NeroCreateIsoTrackEx (NULL,
  118. (const char *) &citeArgs,
  119. NCITEF_USE_STRUCT);
  120. // If the ISO track could not be created then delete the
  121. // ISO item tree and return with an error
  122. if (NULL == *ppIsoTrack)
  123. {
  124. DeleteIsoItemTree (*ppItem);
  125. return EXITCODE_FAILED_TO_CREATE_ISO_TRACK;
  126. }
  127. }
  128. return EXITCODE_OK;
  129. }
  130. //---------------------------------------------------------------
  131. EXITCODE CreateIsoTree (bool Recursive, LPCSTR psFilename, NERO_ISO_ITEM ** ppItem, int iLevel)
  132. {
  133. // CFindFiles is a helper class for file and subdirectory handling
  134. CFindFiles ff (psFilename);
  135. *ppItem = NULL;
  136. if (!ff.IsValidEntry())
  137. {
  138. if (0 == iLevel)
  139. {
  140. // If we haven't found any entries and we are on the
  141. // first level of recursion then this should be
  142. // reported as an error.
  143. return EXITCODE_FILE_NOT_FOUND;
  144. }
  145. else
  146. {
  147. // If we are on a level other than first, it is ok
  148. // not to find any entries. This simply means we
  149. // stumbled upon an empty directory somewhere in a tree.
  150. return EXITCODE_OK;
  151. }
  152. }
  153. char sPath[MAX_PATH];
  154. // Make sure that we have no relative path names, but only absolute paths
  155. if (NULL == _fullpath (sPath, psFilename, sizeof (sPath)))
  156. {
  157. // Our path buffer is too small. Bail out!
  158. return EXITCODE_INTERNAL_ERROR;
  159. }
  160. // Find the last blackslash and remove it if found.
  161. // This will leave us with a root directory.
  162. LPSTR psBackslash = strrchr (sPath, '\\');
  163. if (NULL != psBackslash)
  164. {
  165. *psBackslash = '\0';
  166. }
  167. do
  168. {
  169. std::string sNewPath;
  170. sNewPath = sPath;
  171. sNewPath += "\\";
  172. sNewPath += ff.GetName ();
  173. if (ff.IsSubDir())
  174. {
  175. // Here we handle subdirectories
  176. // strcmp returns 0 on equal strings.
  177. // Proceed if name contains none of "." or ".."
  178. if ((0 != strcmp (ff.GetName (), ".")) && (0 != strcmp (ff.GetName (), "..")))
  179. {
  180. // Append a wildcard to the path and do a recursive search.
  181. sNewPath += "\\";
  182. sNewPath += ff.GetWildcard ();
  183. NERO_ISO_ITEM * pNewItem = NeroCreateIsoItem ();
  184. if (NULL == pNewItem)
  185. {
  186. DeleteIsoItemTree (*ppItem);
  187. return EXITCODE_OUT_OF_MEMORY;
  188. }
  189. // Attach this item to the beginning of the list.
  190. if (*ppItem != NULL)
  191. {
  192. pNewItem->nextItem = *ppItem;
  193. }
  194. *ppItem = pNewItem;
  195. pNewItem->isDirectory = TRUE;
  196. time_t t = ff.GetCreateTime ();
  197. pNewItem->entryTime = *localtime (&t);
  198. StoreFileName (pNewItem->fileName, pNewItem->longFileName, ff.GetName ());
  199. // If we the user wants recursive search, only then do we
  200. // actually recurse at deeper levels otherwise ignore directories
  201. // alltogether.
  202. //
  203. if (Recursive)
  204. {
  205. // Create an ISO item tree at a deeper level
  206. EXITCODE code = CreateIsoTree (Recursive, sNewPath.c_str (), &pNewItem->subDirFirstItem, iLevel + 1);
  207. if (EXITCODE_OK != code)
  208. {
  209. DeleteIsoItemTree (*ppItem);
  210. return code;
  211. }
  212. // We don't allow empty directories. This should probably
  213. // be regulated by a command line switch.
  214. //
  215. if (pNewItem->subDirFirstItem == NULL)
  216. {
  217. // If the newly added directory is empty, remove it!
  218. // We first detach it from the list and then
  219. // deallocate it.
  220. //
  221. *ppItem = pNewItem->nextItem;
  222. pNewItem->nextItem = NULL;
  223. DeleteIsoItemTree (pNewItem);
  224. }
  225. }
  226. }
  227. }
  228. else
  229. {
  230. // Here we handle regular files
  231. NERO_ISO_ITEM * pNewItem = NeroCreateIsoItem ();
  232. if (NULL == pNewItem)
  233. {
  234. DeleteIsoItemTree (*ppItem);
  235. return EXITCODE_OUT_OF_MEMORY;
  236. }
  237. StoreFileName (pNewItem->sourceFilePath, (char *) pNewItem->longSourceFilePath, sNewPath.c_str ());
  238. pNewItem->isDirectory = FALSE;
  239. time_t t = ff.GetCreateTime ();
  240. pNewItem->entryTime = *localtime (&t);
  241. StoreFileName (pNewItem->fileName, pNewItem->longFileName, ff.GetName ());
  242. // Attach this item to the beginning of the list.
  243. if (*ppItem != NULL)
  244. {
  245. pNewItem->nextItem = *ppItem;
  246. }
  247. *ppItem = pNewItem;
  248. }
  249. ff.FindNext ();
  250. }
  251. while (ff.IsValidEntry ());
  252. return EXITCODE_OK;
  253. }
  254. bool MergeIsoTrack (NERO_ISO_ITEM ** ppItemFirst, NERO_ISO_ITEM * pItemToAdd)
  255. {
  256. bool bSuccess = true;
  257. // Two loops. Outter loops the first tree, the inner loops the second
  258. // tree.
  259. //
  260. for (; bSuccess && *ppItemFirst != NULL; ppItemFirst = &(*ppItemFirst)->nextItem)
  261. {
  262. for (NERO_ISO_ITEM ** ppItemSecond = &pItemToAdd; *ppItemSecond != NULL; )
  263. {
  264. // Compare entry names...
  265. //
  266. if ((*ppItemFirst)->isDirectory == (*ppItemSecond)->isDirectory &&
  267. 0 == stricmp (GetFilename (*ppItemFirst), GetFilename (*ppItemSecond)))
  268. {
  269. bool bReplace = true;
  270. // The items point to the same file/directory. We need
  271. // to remove one of them. Which one is removed depends
  272. // on whether "--backup" is specified on command line.
  273. // If it is a directory, make sure to recurse anyway
  274. // because the trees below may not be identical.
  275. //
  276. if ((*ppItemFirst)->isDirectory)
  277. {
  278. bSuccess = MergeIsoTrack (&(*ppItemFirst)->subDirFirstItem, (*ppItemSecond)->subDirFirstItem);
  279. (*ppItemSecond)->subDirFirstItem = NULL;
  280. if (!bSuccess)
  281. {
  282. break;
  283. }
  284. // Since the item is a directory, we won't replace
  285. // the old one as it doesn't matter which one we
  286. // keep. Directory is just a name. It has no file
  287. // access time stamp.
  288. //
  289. bReplace = false;
  290. }
  291. else
  292. {
  293. // If there is a file name conflict between iso items
  294. // that don't belong to imported sessions, ask the user
  295. // what to do.
  296. //
  297. if (!(*ppItemFirst)->isReference)
  298. {
  299. time_t timeOld = mktime (&(*ppItemFirst)->entryTime);
  300. time_t timeNew = mktime (&(*ppItemSecond)->entryTime);
  301. bReplace = timeOld < timeNew;
  302. }
  303. }
  304. if (bReplace)
  305. {
  306. // We will now switch places of items in the first and
  307. // second tree. Since one of the items has to be deleted
  308. // eventually, this operation will essentially keep
  309. // the item from the second tree and delete the item
  310. // from the first tree.
  311. //
  312. NERO_ISO_ITEM * pTempItem = *ppItemSecond;
  313. *ppItemSecond = *ppItemFirst;
  314. *ppItemFirst = pTempItem;
  315. pTempItem = (*ppItemSecond)->nextItem;
  316. (*ppItemSecond)->nextItem = (*ppItemFirst)->nextItem;
  317. (*ppItemFirst)->nextItem = pTempItem;
  318. }
  319. // Remove the item from the second tree.
  320. //
  321. NERO_ISO_ITEM * pTempItem = *ppItemSecond;
  322. *ppItemSecond = pTempItem->nextItem;
  323. pTempItem->nextItem = NULL;
  324. DeleteIsoItemTree (pTempItem);
  325. }
  326. else
  327. {
  328. // No match, advance to the next item.
  329. //
  330. ppItemSecond = &(*ppItemSecond)->nextItem;
  331. }
  332. }
  333. }
  334. // Attach whatever is left of the new tree to the main tree.
  335. //
  336. *ppItemFirst = pItemToAdd;
  337. // Returning true means, everything is fine, continue.
  338. //
  339. return bSuccess;
  340. }