⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 udf.cpp

📁 DVD CSS 加密标准解码程序. 支持解开vob文件.
💻 CPP
字号:
/*************************************************************************
  vStrip by [maven] (maven@maven.de)
	udf.c:	routines for udf-parsing (because windows just doesn't cut it),
					refs: udf102.pdf, udf200.pdf, ecma 167
					(tabsize 2)
*************************************************************************/

#include "stdafx.h"
#include "udf.h"

static aspi_GetSectorInfo(const HANDLE hDrive, DWORD* sec_size, DWORD* max_sec)
{
	*sec_size = 2048;
	*max_sec = GetFileSize(hDrive, NULL) / *sec_size;
	return true;
}

static bool aspi_ReadSectors(const HANDLE hDrive, int lba, int nSectors, DWORD sec_size, BYTE* sector)
{
	DWORD nbr = 0;
	return lba*sec_size == SetFilePointer(hDrive, lba*sec_size, NULL, FILE_BEGIN)
		&& ReadFile(hDrive, sector, nSectors*sec_size, &nbr, NULL);
}

static bool udf_GetLBA(const tp_udf_FileEntry fe, const DWORD sec_size, DWORD *start, DWORD *end)
{
	if (fe->LengthofAllocationDescriptors == 0)
		return false;
	switch (fe->ICBTag.Flags & udf_icbf_Mask)
	{
		case udf_icbf_ShortAd:
		{
			tp_udf_short_ad ad = (tp_udf_short_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);

			*start = ad->Location;
			*end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
			return true;
		}
		break;
		case udf_icbf_LongAd:
		{
			tp_udf_long_ad ad = (tp_udf_long_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);

			*start = ad->Location.Location; // ignore partition number
			*end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
			return true;
		}
		break;
		case udf_icbf_ExtAd:
		{
			tp_udf_ext_ad ad = (tp_udf_ext_ad)(fe->ExtendedAttributes + fe->LengthofExtendedAttributes);

			*start = ad->Location.Location; // ignore partition number
			*end = *start + ((ad->Length & udf_LengthMask) - 1) / sec_size;
			return true;
		}
		break;
	}
	return false;
}

tp_udf_file udf_get_root(const HANDLE hDrive, const WORD partition_number)
{
	BYTE sector[fio_SECTOR_SIZE];
	tp_udf_tag tag = (tp_udf_tag)sector;
	DWORD sec_size, max_sec, i, j;
	DWORD MVDS_lba, MVDS_lba_end, MVDS_back_lba, MVDS_back_lba_end;
	DWORD	FileDescriptorSequence_lba, FileDescriptorSequence_lba_end;
	DWORD partition_lba, parent_icb;
	tp_udf_AnchorVolumeDescriptorPointer avd;
	bool res, part_valid, vol_valid;

	if (!aspi_GetSectorInfo(hDrive, &sec_size, &max_sec))
		return NULL;

	if (sec_size != fio_SECTOR_SIZE || max_sec < 256)
		return NULL;
	
	// read AnchorVolumeDescriptorPointer at 256 (or MaxSec) (Tag == 2)
	res = aspi_ReadSectors(hDrive, 256, 1, sec_size, sector);
	if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor)
	{
		res = aspi_ReadSectors(hDrive, max_sec, 1, sec_size, sector);
		if (!res || tag->TagIdentifier != udf_TAG_AnchorVolumeDescriptor)
			return NULL;
	}
	
	// check Static Structures
	
	// get MainVolumeDescriptorSequence Location & Length
	avd = (tp_udf_AnchorVolumeDescriptorPointer)sector;
	MVDS_lba = avd->MainVolumeDescriptorSequenceExtent.Location;
	MVDS_lba_end = MVDS_lba + (avd->MainVolumeDescriptorSequenceExtent.Length - 1) / sec_size;
	MVDS_back_lba = avd->ReserveVolumeDescriptorSequenceExtent.Location;
	MVDS_back_lba_end = MVDS_back_lba + (avd->ReserveVolumeDescriptorSequenceExtent.Length - 1) / sec_size;

	// read MVDS_Location..MVDS_Location + (MVDS_Length - 1) / SectorSize sectors

	part_valid = vol_valid = false;
	i = 1;
	do
	{ // try twice (if we need to) for ReserveAnchor
		j = MVDS_lba;
		do
		{
			res = aspi_ReadSectors(hDrive, j++, 1, sec_size, sector);
			if (res)
			{
				if (tag->TagIdentifier == udf_TAG_PartitionDescriptor && !part_valid)
				{	// get stuff out of partition
					tp_udf_PartitionDescriptor par = (tp_udf_PartitionDescriptor )sector;

					part_valid = par->PartitionNumber == partition_number;
					if (part_valid)
					{ // extract par->PartitionStartingLocation, par->PartitionLength
						partition_lba = par->PartitionStartingLocation;
					}
				}
				else if (tag->TagIdentifier == udf_TAG_LogicalVolumeDescriptor && !vol_valid)
				{ // get stuff out of volume
					tp_udf_LogicalVolumeDescriptor vol = (tp_udf_LogicalVolumeDescriptor)sector;

					// check_volume sector size
					vol_valid = (vol->LogicalBlockSize == sec_size) && (partition_number == vol->FileSetDescriptorSequence.Location.PartitionNumber);
					if (vol_valid)
					{ // extract vol->FileSetDescriptorSequence
						FileDescriptorSequence_lba = vol->FileSetDescriptorSequence.Location.Location;
						FileDescriptorSequence_lba_end = FileDescriptorSequence_lba + ((vol->FileSetDescriptorSequence.Length & udf_LengthMask) - 1) / sec_size;
					}
				}
			}
			else
				tag->TagIdentifier = 0;
		} while (j <= MVDS_lba_end && tag->TagIdentifier != udf_TAG_TerminatingDescriptor && ((!part_valid) || (!vol_valid)));

		if ((!part_valid) || (!vol_valid)) 
		{ // try backup
			MVDS_lba = MVDS_back_lba;
			MVDS_lba_end = MVDS_back_lba_end;
		}
	} while (i-- && ((!part_valid) || (!vol_valid)));

	if (part_valid && vol_valid)
	{ // read FileSetDescriptor, get RootDir Location & Length, RootDir Length != 0
		res = aspi_ReadSectors(hDrive, FileDescriptorSequence_lba + partition_lba, 1, sec_size, sector);
		if (res && tag->TagIdentifier == udf_TAG_FileSetDescriptor)
		{
			tp_udf_FileSetDescriptor fsd = (tp_udf_FileSetDescriptor)sector;

			if (partition_number == fsd->RootDirectoryICB.Location.PartitionNumber)
			{
				parent_icb = fsd->RootDirectoryICB.Location.Location;
				res = aspi_ReadSectors(hDrive, partition_lba + parent_icb, 1, sec_size, sector);
				if (res && tag->TagIdentifier == udf_TAG_FileEntry)
				{
					tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;

					if (fe->ICBTag.FileType == udf_FT_Directory)
					{
						tp_udf_file root = (tp_udf_file)malloc(sizeof *root);

						root->partition_lba = partition_lba;
						udf_GetLBA(fe, sec_size, &root->dir_lba, &root->dir_end_lba);
						root->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb
						root->sector = NULL;
						root->fid = NULL;
						root->sec_size = sec_size;
						strcpy(root->name, "/");
						root->is_dir = true;
						root->is_parent = false;
						return root;
					}
				}
			}
		}
	}
	
	return NULL;
}

static void udf_GetName(const BYTE *data, const DWORD len, char *target)
{
	DWORD p = 1, i = 0;

	if (len == 0 || !(data[0] & 0x18))
		target[0] = '\0';

	if (data[0] & 0x10)
	{	// ignore MSB of unicode16
		p++;

		while (p < len)
			target[i++] = data[p += 2];
	}
	else
	{
		while (p < len)
			target[i++] = data[p++];
	}

	target[i]='\0';
}

tp_udf_file udf_get_sub(const HANDLE hDrive, tp_udf_file f)
{
	if (f->is_dir && !f->is_parent && f->fid)
	{
		BYTE sector[fio_SECTOR_SIZE];
		tp_udf_tag tag = (tp_udf_tag)sector;
		bool res;

		res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector);
		if (res && tag->TagIdentifier == udf_TAG_FileEntry)
		{
			tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;

			if (fe->ICBTag.FileType == udf_FT_Directory)
			{
				tp_udf_file newf = (tp_udf_file)malloc(sizeof *newf);

				strcpy(newf->name, f->name); // maybe just ""?
				newf->sec_size = f->sec_size;
				newf->partition_lba = f->partition_lba;
				udf_GetLBA(fe, f->sec_size, &newf->dir_lba, &newf->dir_end_lba);
				newf->dir_left = (DWORD)fe->InformationLength; // don't want directories of more than 4gb
				newf->sector = NULL;
				newf->fid = NULL;
				newf->is_dir = true;
				newf->is_parent = false;
				return newf;
			}
		}
	}
	return NULL;
}

tp_udf_file udf_get_next(const HANDLE hDrive, tp_udf_file f)
{
	bool res = true;

	if (f->dir_left <= 0)
	{
		f->fid = NULL;
		return NULL;
	}
	
	if (f->fid)
	{ // advance to next FileIdentifierDescriptor
		DWORD ofs = 4 * ((sizeof *(f->fid) + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4);

		f->fid = (tp_udf_FileIdentifierDescriptor)((BYTE *)f->fid + ofs);
	}
	
	if (f->fid == NULL)
	{
		DWORD size = f->sec_size * (f->dir_end_lba - f->dir_lba + 1);

		if (!f->sector)
			f->sector = (BYTE*)malloc(size);
		res = aspi_ReadSectors(hDrive, f->partition_lba + f->dir_lba, (WORD)(f->dir_end_lba - f->dir_lba + 1), f->sec_size, f->sector);
		if (res)
			f->fid = (tp_udf_FileIdentifierDescriptor)f->sector;
		else
			f->fid = NULL;
	}
	
	if (f->fid && f->fid->DescriptorTag.TagIdentifier == udf_TAG_FileIdentifierDescriptor)
	{
		DWORD ofs = 4 * ((sizeof *f->fid + f->fid->LengthofImplementationUse + f->fid->LengthofFileIdentifier + 3) / 4);

		f->dir_left -= ofs;
		f->is_dir = (f->fid->FileCharacteristics & udf_FID_Directory) != 0;
		f->is_parent = (f->fid->FileCharacteristics & udf_FID_Parent) != 0;
		udf_GetName(f->fid->ImplementationUse + f->fid->LengthofImplementationUse, f->fid->LengthofFileIdentifier, f->name);
		return f;
	}
	return NULL;
}

void udf_free(tp_udf_file f)
{
	if (f)
	{
		if (f->sector)
			free(f->sector);
		free(f);
	}
}

#define udf_PATH_DELIMITERS "/\\"

static tp_udf_file udf_ff_traverse(const HANDLE hDrive, tp_udf_file f, char *token)
{
	while (udf_get_next(hDrive, f))
	{
		if (stricmp(token, f->name) == 0)
		{
			char *next_tok = strtok(NULL, udf_PATH_DELIMITERS);

			if (!next_tok)
				return f; // found
			else if (f->is_dir)
			{
				tp_udf_file f2 = udf_get_sub(hDrive, f);

				if (f2)
				{
					tp_udf_file f3 = udf_ff_traverse(hDrive, f2, next_tok);

					if (!f3)
						udf_free(f2);
					return f3;
				}
			}
		}
	}
	return NULL;
}

tp_udf_file udf_find_file(const HANDLE hDrive, const WORD partition, const char *name)
{
	tp_udf_file f = udf_get_root(hDrive, partition), f2 = NULL;

	if (f)
	{
		char tokenline[udf_MAX_PATHLEN];
		char *token;

		strcpy(tokenline, name);
		token = strtok(tokenline, udf_PATH_DELIMITERS);
		if (token)
			f2 = udf_ff_traverse(hDrive, f, token);
		udf_free(f);
	}
	return f2;
}

bool udf_get_lba(const HANDLE hDrive, const tp_udf_file f, DWORD *start_lba, DWORD *end_lba)
{
	if (f->fid)
	{
		BYTE sector[2048];
		tp_udf_FileEntry fe = (tp_udf_FileEntry)sector;
		bool res;

		res = aspi_ReadSectors(hDrive, f->partition_lba + f->fid->ICB.Location.Location, 1, f->sec_size, sector);
		if (res && fe->DescriptorTag.TagIdentifier == udf_TAG_FileEntry)
			return udf_GetLBA(fe, f->sec_size, start_lba, end_lba);
	}
	return false;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -