udf.cpp
上传用户:xjjlds
上传日期:2015-12-05
资源大小:22823k
文件大小:10k
源码类别:

多媒体编程

开发平台:

Visual C++

  1. /*************************************************************************
  2.   vStrip by [maven] (maven@maven.de)
  3. udf.c: routines for udf-parsing (because windows just doesn't cut it),
  4. refs: udf102.pdf, udf200.pdf, ecma 167
  5. (tabsize 2)
  6. *************************************************************************/
  7. #include "stdafx.h"
  8. #include "udf.h"
  9. static bool aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec)
  10. {
  11. LARGE_INTEGER size;
  12. size.LowPart = GetFileSize(hDrive, (DWORD*)&size.HighPart);
  13. *sec_size = 2048;
  14. *max_sec = size.QuadPart / *sec_size;
  15. return true;
  16. }
  17. static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector)
  18. {
  19. DWORD nbr = 0;
  20. return lba*sec_size == SetFilePointer(hDrive, lba*sec_size, NULL, FILE_BEGIN)
  21. && ReadFile(hDrive, sector, nSectors*sec_size, &nbr, NULL);
  22. }
  23. static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end)
  24. {
  25. if (fe->LengthofAllocationDescriptors == 0)
  26. return false;
  27. switch (fe->ICBTag.Flags & udf_icbf_Mask)
  28. {
  29. case udf_icbf_ShortAd:
  30. {
  31. tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);
  32. *start = ad->Location;
  33. *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
  34. return true;
  35. }
  36. break;
  37. case udf_icbf_LongAd:
  38. {
  39. tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);
  40. *start = ad->Location.Location; // ignore partition number
  41. *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
  42. return true;
  43. }
  44. break;
  45. case udf_icbf_ExtAd:
  46. {
  47. tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);
  48. *start = ad->Location.Location; // ignore partition number
  49. *end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
  50. return true;
  51. }
  52. break;
  53. }
  54. return false;
  55. }
  56. tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number)
  57. {
  58. BYTE sector[fio_SECTOR_SIZE];
  59. tp_udf_tag tag = (tp_udf_tag)sector;
  60. DWORD sec_size, max_sec, i, j;
  61. DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end;
  62. DWORD FileDescriptorSequence_lba, FileDescriptorSequence_lba_end;
  63. DWORD partition_lba, parent_icb;
  64. tp_udf_AnchorVolumeDescriptorPointer avd;
  65. bool res, part_valid, vol_valid;
  66. if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec))
  67. return NULL;
  68. if (sec_size != fio_SECTOR_SIZE || max_sec < 256)
  69. return NULL;
  70. // read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2)
  71. res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector);
  72. if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor)
  73. {
  74. res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector);
  75. if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor)
  76. return NULL;
  77. }
  78. // check Static Structures
  79. // get MainVolumeDescriptorSequence Location & Length
  80. avd = (tp_udf_AnchorVolumeDescriptorPointer)sector;
  81. MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location;
  82. MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size;
  83. MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location;
  84. MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size;
  85. // read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors
  86. part_valid = vol_valid = false;
  87. i = 1;
  88. do
  89. { // try twice (if we need to) for ReserveAnchor
  90. j = MVDS_lba;
  91. do
  92. {
  93. res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector);
  94. if (res)
  95. {
  96. if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid)
  97. { // get stuff out of partition
  98. tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector;
  99. part_valid = par->PartitionNumber == partition_number;
  100. if (part_valid)
  101. { // extract par->PartitionStartingLocation, par->PartitionLength
  102. partition_lba = par->PartitionStartingLocation;
  103. }
  104. }
  105. else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid)
  106. { // get stuff out of volume
  107. tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector;
  108. // check_volume sector size
  109. vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber);
  110. if (vol_valid)
  111. { // extract vol->FileSetDescriptorSequence
  112. FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location;
  113. FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size;
  114. }
  115. }
  116. }
  117. else
  118. tag->TagIdentifier = 0;
  119. } while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid)));
  120. if ((!part_valid) || (!vol_valid)) 
  121. { // try backup
  122. MVDS_lba = MVDS_back_lba;
  123. MVDS_lba_end = MVDS_back_lba_end;
  124. }
  125. } while (i-- && ((!part_valid) || (!vol_valid)));
  126. if (part_valid && vol_valid)
  127. { // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0
  128. res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector);
  129. if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor)
  130. {
  131. tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector;
  132. if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber)
  133. {
  134. parent_icb = fsd->RootDirectoryICB.Location.Location;
  135. res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector);
  136. if (res && tag->TagIdentifier == udf_TAG_FileEntry)
  137. {
  138. tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
  139. if (fe->ICBTag.FileType == udf_FT_Directory)
  140. {
  141. tp_udf_file root = (tp_udf_file)malloc(sizeof *root);
  142. root->partition_lba = partition_lba;
  143. udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba);
  144. root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb
  145. root->sector = NULL;
  146. root->fid = NULL;
  147. root->sec_size = sec_size;
  148. strcpy(root->name, "/");
  149. root->is_dir = true;
  150. root->is_parent = false;
  151. return root;
  152. }
  153. }
  154. }
  155. }
  156. }
  157. return NULL;
  158. }
  159. static void udf_GetName(const BYTE *data, const DWORD len, char *target)
  160. {
  161. DWORD p = 1, i = 0;
  162. if (len == 0 || !(data[0] & 0x18))
  163. target[0] = '';
  164. if (data[0] & 0x10)
  165. { // ignore MSB of unicode16
  166. p++;
  167. while (p < len)
  168. target[i++] = data[p += 2];
  169. }
  170. else
  171. {
  172. while (p < len)
  173. target[i++] = data[p++];
  174. }
  175. target[i]='';
  176. }
  177. tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f)
  178. {
  179. if (f->is_dir && !f->is_parent && f->fid)
  180. {
  181. BYTE sector[fio_SECTOR_SIZE];
  182. tp_udf_tag tag = (tp_udf_tag)sector;
  183. bool res;
  184. res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector);
  185. if (res && tag->TagIdentifier == udf_TAG_FileEntry)
  186. {
  187. tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
  188. if (fe->ICBTag.FileType == udf_FT_Directory)
  189. {
  190. tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf);
  191. strcpy(newf->name, f->name); // maybe just ""?
  192. newf->sec_size = f->sec_size;
  193. newf->partition_lba = f->partition_lba;
  194. udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba);
  195. newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb
  196. newf->sector = NULL;
  197. newf->fid = NULL;
  198. newf->is_dir = true;
  199. newf->is_parent = false;
  200. return newf;
  201. }
  202. }
  203. }
  204. return NULL;
  205. }
  206. tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f)
  207. {
  208. bool res = true;
  209. if (f->dir_left <= 0)
  210. {
  211. f->fid = NULL;
  212. return NULL;
  213. }
  214. if (f->fid)
  215. { // advance to next FileIdentifierDescriptor
  216. DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4);
  217. f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs);
  218. }
  219. if (f->fid == NULL)
  220. {
  221. DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1);
  222. if (!f->sector)
  223. f->sector = (BYTE*)malloc(size);
  224. res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector);
  225. if (res)
  226. f->fid = (tp_udf_FileIdentifierDescriptor)f->sector;
  227. else
  228. f->fid = NULL;
  229. }
  230. if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor)
  231. {
  232. DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4);
  233. f->dir_left -= ofs;
  234. f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0;
  235. f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0;
  236. udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name);
  237. return f;
  238. }
  239. return NULL;
  240. }
  241. void udf_free(tp_udf_file f)
  242. {
  243. if (f)
  244. {
  245. if (f->sector)
  246. free(f->sector);
  247. free(f);
  248. }
  249. }
  250. #define udf_PATH_DELIMITERS "/\"
  251. static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token)
  252. {
  253. while (udf_get_next(hDrive, f))
  254. {
  255. if (stricmp(token, f->name) == 0)
  256. {
  257. char *next_tok = strtok(NULL, udf_PATH_DELIMITERS);
  258. if (!next_tok)
  259. return f; // found
  260. else if (f->is_dir)
  261. {
  262. tp_udf_file f2 = udf_get_sub(hDrive, f);
  263. if (f2)
  264. {
  265. tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok);
  266. if (!f3)
  267. udf_free(f2);
  268. return f3;
  269. }
  270. }
  271. }
  272. }
  273. return NULL;
  274. }
  275. tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name)
  276. {
  277. tp_udf_file f = udf_get_root(hDrive, partition), f2 = NULL;
  278. if (f)
  279. {
  280. char tokenline[udf_MAX_PATHLEN];
  281. char *token;
  282. strcpy(tokenline, name);
  283. token = strtok(tokenline, udf_PATH_DELIMITERS);
  284. if (token)
  285. f2 = udf_ff_traverse(hDrive, f, token);
  286. udf_free(f);
  287. }
  288. return f2;
  289. }
  290. bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba)
  291. {
  292. if (f->fid)
  293. {
  294. BYTE sector[2048];
  295. tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
  296. bool res;
  297. res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector);
  298. if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry)
  299. return udf_GetLBA(fe, f->sec_size, start_lba, end_lba);
  300. }
  301. return false;
  302. }