////////////////////////////////////////////////////////////////////
// Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
// All rights reserved
// This file was released under the GPLv2 on June 2015.
////////////////////////////////////////////////////////////////////

#ifndef __UDF_STRUCT_SUPPORT_H__
#define __UDF_STRUCT_SUPPORT_H__

#include "ecma_167.h"
#include "osta_misc.h"
#include "udf_rel.h"
#include "wcache.h"

// memory re-allocation (returns new buffer size)
uint32    UDFMemRealloc(IN int8* OldBuff,     // old buffer
                       IN uint32 OldLength,   // old buffer size
                       OUT int8** NewBuff,   // address to store new pointer
                       IN uint32 NewLength);  // required size
// convert offset in extent to Lba & calculate block parameters
// it also returns pointer to last valid entry & flags
uint32
UDFExtentOffsetToLba(IN PVCB Vcb,
                     IN PEXTENT_AD Extent,   // Extent array
                     IN int64 Offset,     // offset in extent
                     OUT uint32* SectorOffset,
                     OUT PSIZE_T AvailLength, // available data in this block
                     OUT uint32* Flags,
                     OUT uint32* Index);

// locate frag containing specified Lba in extent
ULONG
UDFLocateLbaInExtent(
    IN PVCB Vcb,
    IN PEXTENT_MAP Extent,   // Extent array
    IN lba_t lba
    );

// see udf_rel.h
//#define LBA_OUT_OF_EXTENT       ((LONG)(-1))
//#define LBA_NOT_ALLOCATED       ((LONG)(-2))

// read data at any offset from extent
OSSTATUS UDFReadExtent(IN PVCB Vcb,
                       IN PEXTENT_INFO ExtInfo, // Extent array
                       IN int64 Offset,   // offset in extent
                       IN SIZE_T Length,
                       IN BOOLEAN Direct,
                       OUT int8* Buffer,
                       OUT PSIZE_T ReadBytes);
// builds mapping for specified amount of data at any offset from specified extent.
OSSTATUS
UDFReadExtentLocation(IN PVCB Vcb,
                      IN PEXTENT_INFO ExtInfo,      // Extent array
                      IN int64 Offset,              // offset in extent to start SubExtent from
                      OUT PEXTENT_MAP* _SubExtInfo, // SubExtent mapping array
                   IN OUT uint32* _SubExtInfoSz,     // IN:  maximum number fragments to get
                                                    // OUT: actually obtained fragments
                      OUT int64* _NextOffset        // offset, caller can start from to continue
                      );
// calculate total length of extent
int64 UDFGetExtentLength(IN PEXTENT_MAP Extent);  // Extent array
// convert compressed Unicode to standard
void 
__fastcall UDFDecompressUnicode(IN OUT PUNICODE_STRING UName,
                              IN uint8* CS0,
                              IN SIZE_T Length,
                              OUT uint16* valueCRC);
// calculate hashes for directory search
uint8    UDFBuildHashEntry(IN PVCB Vcb,
                           IN PUNICODE_STRING Name,
                          OUT PHASH_ENTRY hashes,
                           IN uint8 Mask);

#define HASH_POSIX 0x01
#define HASH_ULFN  0x02
#define HASH_DOS   0x04
#define HASH_ALL   0x07
#define HASH_KEEP_NAME 0x08  // keep DOS '.' and '..' intact

// get dirindex's frame
PDIR_INDEX_ITEM UDFDirIndexGetFrame(IN PDIR_INDEX_HDR hDirNdx,
                                    IN uint32 Frame,
                                   OUT uint32* FrameLen,
                                   OUT uint_di* Index,
                                    IN uint_di Rel);
// release DirIndex
void UDFDirIndexFree(PDIR_INDEX_HDR hDirNdx);
// grow DirIndex
OSSTATUS UDFDirIndexGrow(IN PDIR_INDEX_HDR* _hDirNdx,
                         IN uint_di d);
// truncate DirIndex
OSSTATUS UDFDirIndexTrunc(IN PDIR_INDEX_HDR* _hDirNdx,
                          IN uint_di d);
// init variables for scan (using knowledge about internal structure)
BOOLEAN UDFDirIndexInitScan(IN PUDF_FILE_INFO DirInfo,   //
                           OUT PUDF_DIR_SCAN_CONTEXT Context,
                            IN uint_di Index);
//
PDIR_INDEX_ITEM UDFDirIndexScan(PUDF_DIR_SCAN_CONTEXT Context,
                                PUDF_FILE_INFO* _FileInfo);
// build directory index
OSSTATUS UDFIndexDirectory(IN PVCB Vcb,
                        IN OUT PUDF_FILE_INFO FileInfo);
// search for specified file in specified directory &
// returns corresponding offset in extent if found.
OSSTATUS UDFFindFile(IN PVCB Vcb,
                     IN BOOLEAN IgnoreCase,
                     IN BOOLEAN NotDeleted,
                     IN PUNICODE_STRING Name,
                     IN PUDF_FILE_INFO DirInfo,
                  IN OUT uint_di* Index);

__inline OSSTATUS UDFFindFile__(IN PVCB Vcb,
                                IN BOOLEAN IgnoreCase,
                                IN PUNICODE_STRING Name,
                                IN PUDF_FILE_INFO DirInfo)
{
    if(!DirInfo->Dloc->DirIndex)
        return STATUS_NOT_A_DIRECTORY;
    uint_di i=0;
    return UDFFindFile(Vcb, IgnoreCase, TRUE, Name, DirInfo, &i);
}

// calculate file mapping length (in bytes) including ZERO-terminator
uint32   UDFGetMappingLength(IN PEXTENT_MAP Extent);
// merge 2 sequencial file mappings
PEXTENT_MAP
__fastcall UDFMergeMappings(IN PEXTENT_MAP Extent,
                             IN PEXTENT_MAP Extent2);
// build file mapping according to ShortAllocDesc (SHORT_AD) array
PEXTENT_MAP UDFShortAllocDescToMapping(IN PVCB Vcb,
                                      IN uint32 PartNum,
                                      IN PLONG_AD AllocDesc,
                                      IN uint32 AllocDescLength,
                                      IN uint32 SubCallCount,
                                      OUT PEXTENT_INFO AllocLoc);
// build file mapping according to LongAllocDesc (LONG_AD) array
PEXTENT_MAP UDFLongAllocDescToMapping(IN PVCB Vcb,
                                      IN PLONG_AD AllocDesc,
                                      IN uint32 AllocDescLength,
                                      IN uint32 SubCallCount,
                                      OUT PEXTENT_INFO AllocLoc);
// build file mapping according to ExtendedAllocDesc (EXT_AD) array
PEXTENT_MAP UDFExtAllocDescToMapping(IN PVCB Vcb,
                                      IN PLONG_AD AllocDesc,
                                      IN uint32 AllocDescLength,
                                      IN uint32 SubCallCount,
                                      OUT PEXTENT_INFO AllocLoc);
// build file mapping according to (Extended)FileEntry
PEXTENT_MAP UDFReadMappingFromXEntry(IN PVCB Vcb,
                                     IN uint32 PartNum,
                                     IN tag* XEntry,
                                     IN OUT uint32* Offset,
                                     OUT PEXTENT_INFO AllocLoc);
// read FileEntry described in FileIdentDesc
OSSTATUS UDFReadFileEntry(IN PVCB Vcb,
//                          IN PFILE_IDENT_DESC FileDesc,
                          IN long_ad* Icb,
                       IN OUT PFILE_ENTRY FileEntry, // here we can also get ExtendedFileEntry
                       IN OUT uint16* Ident);
// scan FileSet sequence & return last valid FileSet
OSSTATUS UDFFindLastFileSet(IN PVCB Vcb,
                            IN lb_addr *Addr,  // Addr for the 1st FileSet
                            IN OUT PFILE_SET_DESC FileSetDesc);
// read all sparing tables & stores them in contiguos memory
OSSTATUS UDFLoadSparingTable(IN PVCB Vcb,
                              IN PSPARABLE_PARTITION_MAP PartMap);
// build mapping for extent
PEXTENT_MAP
__fastcall UDFExtentToMapping_(IN PEXTENT_AD Extent
#ifdef UDF_TRACK_EXTENT_TO_MAPPING
                              ,IN ULONG src,
                               IN ULONG line
#endif //UDF_TRACK_EXTENT_TO_MAPPING
                              );

#ifdef UDF_TRACK_EXTENT_TO_MAPPING
  #define UDFExtentToMapping(e)  UDFExtentToMapping_(e, UDF_BUG_CHECK_ID, __LINE__) 
#else //UDF_TRACK_EXTENT_TO_MAPPING
  #define UDFExtentToMapping(e)  UDFExtentToMapping_(e)
#endif //UDF_TRACK_EXTENT_TO_MAPPING

//    This routine remaps sectors from bad packet
OSSTATUS
__fastcall UDFRemapPacket(IN PVCB Vcb,
                        IN uint32 Lba,
                        IN BOOLEAN RemapSpared);

//    This routine releases sector mapping when entire packet is marked as free
OSSTATUS
__fastcall UDFUnmapRange(IN PVCB Vcb,
                        IN uint32 Lba,
                        IN uint32 BCount);

// return physical address for relocated sector
uint32
__fastcall UDFRelocateSector(IN PVCB Vcb,
                          IN uint32 Lba);
// check
BOOLEAN
__fastcall UDFAreSectorsRelocated(IN PVCB Vcb,
                                  IN uint32 Lba,
                                  IN uint32 BlockCount);
// build mapping for relocated extent
PEXTENT_MAP
__fastcall UDFRelocateSectors(IN PVCB Vcb,
                               IN uint32 Lba,
                               IN uint32 BlockCount);
// check for presence of given char among specified ones
BOOLEAN  UDFUnicodeInString(IN uint8* string,
                            IN WCHAR ch);     // Unicode char to search for.
// validate char
BOOLEAN 
__fastcall UDFIsIllegalChar(IN WCHAR ch);
// translate udfName to dosName using OSTA compliant.
#define  UDFDOSName__(Vcb, DosName, UdfName, FileInfo) \
    UDFDOSName(Vcb, DosName, UdfName, (FileInfo) && ((FileInfo)->Index < 2));

void 
__fastcall UDFDOSName(IN PVCB Vcb,
                    IN OUT PUNICODE_STRING DosName,
                    IN PUNICODE_STRING UdfName,
                    IN BOOLEAN KeepIntact);

void 
__fastcall UDFDOSName201(IN OUT PUNICODE_STRING DosName,
                       IN PUNICODE_STRING UdfName,
                       IN BOOLEAN KeepIntact);

void 
__fastcall UDFDOSName200(IN OUT PUNICODE_STRING DosName,
                       IN PUNICODE_STRING UdfName,
                       IN BOOLEAN KeepIntact,
                       IN BOOLEAN Mode150);

void 
__fastcall UDFDOSName100(IN OUT PUNICODE_STRING DosName,
                       IN PUNICODE_STRING UdfName,
                       IN BOOLEAN KeepIntact);

// return length of bit-chain starting from Offs bit
#ifdef _X86_
SIZE_T
__stdcall
UDFGetBitmapLen(
#else   // NO X86 optimization , use generic C/C++
SIZE_T    UDFGetBitmapLen(
#endif // _X86_
                         uint32* Bitmap,
                         SIZE_T Offs,
                         SIZE_T Lim);
// scan disc free space bitmap for minimal suitable extent
SIZE_T    UDFFindMinSuitableExtent(IN PVCB Vcb,
                                   IN uint32 Length, // in blocks
                                   IN uint32 SearchStart,
                                   IN uint32 SearchLim,
                                   OUT uint32* MaxExtLen,
                                   IN uint8  AllocFlags);

#ifdef UDF_CHECK_DISK_ALLOCATION
// mark space described by Mapping as Used/Freed (optionaly)
void     UDFCheckSpaceAllocation_(IN PVCB Vcb,
                                  IN PEXTENT_MAP Map,
                                  IN uint32 asXXX
#ifdef UDF_TRACK_ONDISK_ALLOCATION
                                 ,IN uint32 FE_lba,
                                  IN uint32 BugCheckId,
                                  IN uint32 Line
#endif //UDF_TRACK_ONDISK_ALLOCATION
                                  );

#ifdef UDF_TRACK_ONDISK_ALLOCATION
#define UDFCheckSpaceAllocation(Vcb, FileInfo, Map, asXXX) \
    UDFCheckSpaceAllocation_(Vcb, Map, asXXX, (uint32)FileInfo, UDF_BUG_CHECK_ID,__LINE__);
#else //UDF_TRACK_ONDISK_ALLOCATION
#define UDFCheckSpaceAllocation(Vcb, FileInfo, Map, asXXX) \
    UDFCheckSpaceAllocation_(Vcb, Map, asXXX);
#endif //UDF_TRACK_ONDISK_ALLOCATION
#else // UDF_CHECK_DISK_ALLOCATION
#define UDFCheckSpaceAllocation(Vcb, FileInfo, Map, asXXX) {;}
#endif //UDF_CHECK_DISK_ALLOCATION

// mark space described by Mapping as Used/Freed (optionaly)
// this routine doesn't acquire any resource
void
UDFMarkSpaceAsXXXNoProtect_(
    IN PVCB Vcb,
    IN PEXTENT_MAP Map,
    IN uint32 asXXX
#ifdef UDF_TRACK_ONDISK_ALLOCATION
   ,IN uint32 FE_lba,
    IN uint32 BugCheckId,
    IN uint32 Line
#endif //UDF_TRACK_ONDISK_ALLOCATION
    );

#ifdef UDF_TRACK_ONDISK_ALLOCATION
#define UDFMarkSpaceAsXXXNoProtect(Vcb, FileInfo, Map, asXXX) \
    UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX, (uint32)FileInfo, UDF_BUG_CHECK_ID,__LINE__);
#else //UDF_TRACK_ONDISK_ALLOCATION
#define UDFMarkSpaceAsXXXNoProtect(Vcb, FileInfo, Map, asXXX) \
    UDFMarkSpaceAsXXXNoProtect_(Vcb, Map, asXXX);
#endif //UDF_TRACK_ONDISK_ALLOCATION


// mark space described by Mapping as Used/Freed (optionaly)
void     UDFMarkSpaceAsXXX_(IN PVCB Vcb,
                            IN PEXTENT_MAP Map,
                            IN uint32 asXXX
#ifdef UDF_TRACK_ONDISK_ALLOCATION
                           ,IN uint32 FE_lba,
                            IN uint32 BugCheckId,
                            IN uint32 Line
#endif //UDF_TRACK_ONDISK_ALLOCATION
                            );

#ifdef UDF_TRACK_ONDISK_ALLOCATION
#define UDFMarkSpaceAsXXX(Vcb, FileInfo, Map, asXXX) \
    UDFMarkSpaceAsXXX_(Vcb, Map, asXXX, (uint32)FileInfo, UDF_BUG_CHECK_ID,__LINE__);
#else //UDF_TRACK_ONDISK_ALLOCATION
#define UDFMarkSpaceAsXXX(Vcb, FileInfo, Map, asXXX) \
    UDFMarkSpaceAsXXX_(Vcb, Map, asXXX);
#endif //UDF_TRACK_ONDISK_ALLOCATION

#define AS_FREE         0x00
#define AS_USED         0x01
#define AS_DISCARDED    0x02
#define AS_BAD          0x04

// build mapping for Length bytes in FreeSpace
OSSTATUS UDFAllocFreeExtent_(IN PVCB Vcb,
                            IN int64 Length,
                            IN uint32 SearchStart,
                            IN uint32 SearchLim,
                            OUT PEXTENT_INFO Extent,
                            IN uint8 AllocFlags
#ifdef UDF_TRACK_ALLOC_FREE_EXTENT
                           ,IN uint32 src,
                            IN uint32 line
#endif //UDF_TRACK_ALLOC_FREE_EXTENT
                            );

#ifdef UDF_TRACK_ALLOC_FREE_EXTENT
#define UDFAllocFreeExtent(v, l, ss, sl, e, af)  UDFAllocFreeExtent_(v, l, ss, sl, e, af, UDF_BUG_CHECK_ID, __LINE__)
#else //UDF_TRACK_ALLOC_FREE_EXTENT
#define UDFAllocFreeExtent(v, l, ss, sl, e, af)  UDFAllocFreeExtent_(v, l, ss, sl, e, af)
#endif //UDF_TRACK_ALLOC_FREE_EXTENT
//

uint32 __fastcall
UDFGetPartFreeSpace(IN PVCB Vcb,
                           IN uint32 partNum);

#define UDF_PREALLOC_CLASS_FE    0x00
#define UDF_PREALLOC_CLASS_DIR   0x01

// try to find cached allocation
OSSTATUS
UDFGetCachedAllocation(
    IN PVCB Vcb,
    IN uint32 ParentLocation,
   OUT PEXTENT_INFO Ext,
   OUT uint32* Items, // optional
    IN uint32 AllocClass
    );
// put released pre-allocation to cache
OSSTATUS
UDFStoreCachedAllocation(
    IN PVCB Vcb,
    IN uint32 ParentLocation,
    IN PEXTENT_INFO Ext,
    IN uint32 Items,
    IN uint32 AllocClass
    );
// discard all cached allocations
OSSTATUS
UDFFlushAllCachedAllocations(
    IN PVCB Vcb,
    IN uint32 AllocClass
    );
// allocate space for FE
OSSTATUS UDFAllocateFESpace(IN PVCB Vcb,
                            IN PUDF_FILE_INFO DirInfo,
                            IN uint32 PartNum,
                            IN PEXTENT_INFO FEExtInfo,
                            IN uint32 Len);
#ifndef UDF_READ_ONLY_BUILD
// free space FE's allocation
void UDFFreeFESpace(IN PVCB Vcb,
                    IN PUDF_FILE_INFO DirInfo,
                    IN PEXTENT_INFO FEExtInfo);
#endif //UDF_READ_ONLY_BUILD

#define FLUSH_FE_KEEP       FALSE
#define FLUSH_FE_FOR_DEL    TRUE

// flush FE charge
void UDFFlushFESpace(IN PVCB Vcb,
                     IN PUDF_DATALOC_INFO Dloc,
                     IN BOOLEAN Discard = FLUSH_FE_KEEP);
// discard file allocation
void UDFFreeFileAllocation(IN PVCB Vcb,
                           IN PUDF_FILE_INFO DirInfo,
                           IN PUDF_FILE_INFO FileInfo);
// convert physical address to logical in specified partition
uint32    UDFPhysLbaToPart(IN PVCB Vcb,
                          IN uint32 PartNum,
                          IN uint32 Addr);
/*#define UDFPhysLbaToPart(Vcb, PartNum, Addr) \
    ((Addr - Vcb->Partitions[PartNum].PartitionRoot) >> Vcb->LB2B_Bits)*/
// initialize Tag structure.
void     UDFSetUpTag(IN PVCB Vcb,
                     IN tag* Tag,
                     IN uint16 DataLen,
                     IN uint32 TagLoc);
// build content for AllocDesc sequence for specified extent
OSSTATUS UDFBuildShortAllocDescs(IN PVCB Vcb,
                                 IN uint32 PartNum,
                                 OUT int8** Buff,  // data for AllocLoc
                                 IN uint32 InitSz,
                              IN OUT PUDF_FILE_INFO FileInfo);
// build data for AllocDesc sequence for specified
OSSTATUS UDFBuildLongAllocDescs(IN PVCB Vcb,
                                IN uint32 PartNum,
                                OUT int8** Buff,  // data for AllocLoc
                                IN uint32 InitSz,
                             IN OUT PUDF_FILE_INFO FileInfo);
// builds FileEntry & associated AllocDescs for specified extent.
OSSTATUS UDFBuildFileEntry(IN PVCB Vcb,
                           IN PUDF_FILE_INFO DirInfo,
                           IN PUDF_FILE_INFO FileInfo,
                           IN uint32 PartNum,
                           IN uint16 AllocMode, // short/long/ext/in-icb
                           IN uint32 ExtAttrSz,
                           IN BOOLEAN Extended/*,
                           OUT PFILE_ENTRY* FEBuff,
                           OUT uint32* FELen,
                           OUT PEXTENT_INFO FEExtInfo*/);
// find partition containing given physical sector
uint32
__fastcall UDFGetPartNumByPhysLba(IN PVCB Vcb,
                                IN uint32 Lba);
// add given bitmap to existing one
#define UDF_FSPACE_BM    0x00
#define UDF_ZSPACE_BM    0x01

OSSTATUS UDFAddXSpaceBitmap(IN PVCB Vcb,
                            IN uint32 PartNum,
                            IN PSHORT_AD bm,
                            IN ULONG bm_type);
// subtract given Bitmap to existing one
OSSTATUS UDFDelXSpaceBitmap(IN PVCB Vcb,
                            IN uint32 PartNum,
                            IN PSHORT_AD bm);
// build FreeSpaceBitmap (internal) according to media parameters & input data
OSSTATUS UDFBuildFreeSpaceBitmap(IN PVCB Vcb,
                                IN uint32 PartNdx,
                                IN PPARTITION_HEADER_DESC phd,
                                IN uint32 Lba);
// fill ExtentInfo for specified FileEntry
OSSTATUS UDFLoadExtInfo(IN PVCB Vcb,
                        IN PFILE_ENTRY fe,
                        IN PLONG_AD fe_loc,
                        IN OUT PEXTENT_INFO FExtInfo,
                        IN OUT PEXTENT_INFO AExtInfo);
// convert standard Unicode to compressed
void 
__fastcall UDFCompressUnicode(IN PUNICODE_STRING UName,
                            IN OUT uint8** _CS0,
                            IN OUT PSIZE_T Length);
// build FileIdent for specified FileEntry.
OSSTATUS UDFBuildFileIdent(IN PVCB Vcb,
                           IN PUNICODE_STRING fn,
                           IN PLONG_AD FileEntryIcb,       // virtual address of FileEntry
                           IN uint32 ImpUseLen,
                           OUT PFILE_IDENT_DESC* _FileId,
                           OUT uint32* FileIdLen);
// rebuild mapping on write attempts to Alloc-Not-Rec area.
OSSTATUS UDFMarkAllocatedAsRecorded(IN PVCB Vcb,
                                    IN int64 Offset,
                                    IN uint32 Length,
                                    IN PEXTENT_INFO ExtInfo);   // Extent array
// rebuild mapping on write attempts to Not-Alloc-Not-Rec area
OSSTATUS UDFMarkNotAllocatedAsAllocated(IN PVCB Vcb,
                                        IN int64 Offset,
                                        IN uint32 Length,
                                        IN PEXTENT_INFO ExtInfo);   // Extent array
OSSTATUS UDFMarkAllocatedAsNotXXX(IN PVCB Vcb,
                                  IN int64 Offset,
                                  IN uint32 Length,
                                  IN PEXTENT_INFO ExtInfo,   // Extent array
                                  IN BOOLEAN Deallocate);
#ifdef DBG
__inline OSSTATUS UDFMarkAllocatedAsNotAllocated(IN PVCB Vcb,
                                  IN int64 Offset,
                                  IN uint32 Length,
                                  IN PEXTENT_INFO ExtInfo)
{
    return UDFMarkAllocatedAsNotXXX(Vcb, Offset, Length, ExtInfo, TRUE);
}
#else
#define UDFMarkAllocatedAsNotAllocated(Vcb, Off, Len, Ext) \
    UDFMarkAllocatedAsNotXXX(Vcb, Off, Len, Ext, TRUE)
#endif //DBG

#ifdef DBG
__inline OSSTATUS UDFMarkRecordedAsAllocated(IN PVCB Vcb,
                                  IN int64 Offset,
                                  IN uint32 Length,
                                  IN PEXTENT_INFO ExtInfo)
{
    return UDFMarkAllocatedAsNotXXX(Vcb, Offset, Length, ExtInfo, FALSE);
}
#else
#define UDFMarkRecordedAsAllocated(Vcb, Off, Len, Ext) \
    UDFMarkAllocatedAsNotXXX(Vcb, Off, Len, Ext, FALSE)
#endif //DBG
// write data at any offset from specified extent.
OSSTATUS UDFWriteExtent(IN PVCB Vcb,
                        IN PEXTENT_INFO ExtInfo,   // Extent array
                        IN int64 Offset,           // offset in extent
                        IN SIZE_T Length,
                        IN BOOLEAN Direct,         // setting this flag delays flushing of given
                                                   // data to indefinite term
                        IN int8* Buffer,
                        OUT PSIZE_T WrittenBytes);

// deallocate/zero data at any offset from specified extent.
OSSTATUS UDFZeroExtent(IN PVCB Vcb,
                       IN PEXTENT_INFO ExtInfo,   // Extent array
                       IN int64 Offset,           // offset in extent
                       IN SIZE_T Length,
                       IN BOOLEAN Deallocate,     // deallocate frag or just mark as unrecorded
                       IN BOOLEAN Direct,         // setting this flag delays flushing of given
                                                  // data to indefinite term
                       OUT PSIZE_T WrittenBytes);

#define UDFZeroExtent__(Vcb, Ext, Off, Len, Dir, WB) \
  UDFZeroExtent(Vcb, Ext, Off, Len, FALSE, Dir, WB)

#define UDFSparseExtent__(Vcb, Ext, Off, Len, Dir, WB) \
  UDFZeroExtent(Vcb, Ext, Off, Len, TRUE, Dir, WB)

uint32 
__fastcall UDFPartStart(PVCB Vcb,
                        uint32 PartNum);
uint32
__fastcall UDFPartEnd(PVCB Vcb,
                      uint32 PartNum);
// resize extent & associated mapping
OSSTATUS UDFResizeExtent(IN PVCB Vcb,
                         IN uint32 PartNum,
                         IN int64 Length,
                         IN BOOLEAN AlwaysInIcb,   // must be TRUE for AllocDescs
                         OUT PEXTENT_INFO ExtInfo);
// (re)build AllocDescs data  & resize associated extent
OSSTATUS UDFBuildAllocDescs(IN PVCB Vcb,
                            IN uint32 PartNum,
                         IN OUT PUDF_FILE_INFO FileInfo,
                            OUT int8** AllocData);
// set informationLength field in (Ext)FileEntry
void     UDFSetFileSize(IN PUDF_FILE_INFO FileInfo,
                        IN int64 Size);
// sync cached FileSize from DirNdx and actual FileSize from FE
void     UDFSetFileSizeInDirNdx(IN PVCB Vcb,
                                IN PUDF_FILE_INFO FileInfo,
                                IN int64* ASize);
// get informationLength field in (Ext)FileEntry
int64 UDFGetFileSize(IN PUDF_FILE_INFO FileInfo);
//
int64 UDFGetFileSizeFromDirNdx(IN PVCB Vcb,
                                  IN PUDF_FILE_INFO FileInfo);
// set lengthAllocDesc field in (Ext)FileEntry
void     UDFSetAllocDescLen(IN PVCB Vcb,
                            IN PUDF_FILE_INFO FileInfo);
// change fileLinkCount field in (Ext)FileEntry
void     UDFChangeFileLinkCount(IN PUDF_FILE_INFO FileInfo,
                                IN BOOLEAN Increase);
#define  UDFIncFileLinkCount(fi)  UDFChangeFileLinkCount(fi, TRUE)
#define  UDFDecFileLinkCount(fi)  UDFChangeFileLinkCount(fi, FALSE)
// ee
void     UDFSetEntityID_imp_(IN EntityID* eID,
                             IN uint8* Str,
                             IN uint32 Len);

// get fileLinkCount field from (Ext)FileEntry
uint16   UDFGetFileLinkCount(IN PUDF_FILE_INFO FileInfo);
#ifdef UDF_CHECK_UTIL
// set fileLinkCount field in (Ext)FileEntry
void
UDFSetFileLinkCount(
    IN PUDF_FILE_INFO FileInfo,
    uint16 LinkCount
    );
#endif //UDF_CHECK_UTIL

#define  UDFSetEntityID_imp(eID, Str) \
    UDFSetEntityID_imp_(eID, (uint8*)(Str), sizeof(Str));
//
void     UDFReadEntityID_Domain(PVCB Vcb,
                                EntityID* eID);
// get lengthExtendedAttr field in (Ext)FileEntry
uint32    UDFGetFileEALength(IN PUDF_FILE_INFO FileInfo);
// set UniqueID field in (Ext)FileEntry
void     UDFSetFileUID(IN PVCB Vcb,
                       IN PUDF_FILE_INFO FileInfo);
// get UniqueID field in (Ext)FileEntry
int64 UDFGetFileUID(IN PUDF_FILE_INFO FileInfo);
// change counters in LVID
void  UDFChangeFileCounter(IN PVCB Vcb,
                           IN BOOLEAN FileCounter,
                           IN BOOLEAN Increase);
#define UDFIncFileCounter(Vcb) UDFChangeFileCounter(Vcb, TRUE, TRUE);
#define UDFDecFileCounter(Vcb) UDFChangeFileCounter(Vcb, TRUE, FALSE);
#define UDFIncDirCounter(Vcb)  UDFChangeFileCounter(Vcb, FALSE, TRUE);
#define UDFDecDirCounter(Vcb)  UDFChangeFileCounter(Vcb, FALSE, FALSE);
// write to file
OSSTATUS UDFWriteFile__(IN PVCB Vcb,
                        IN PUDF_FILE_INFO FileInfo,
                        IN int64 Offset,
                        IN SIZE_T Length,
                        IN BOOLEAN Direct,
                        IN int8* Buffer,
                        OUT PSIZE_T WrittenBytes);
// mark file as deleted & decrease file link counter.
OSSTATUS UDFUnlinkFile__(IN PVCB Vcb,
                         IN PUDF_FILE_INFO FileInfo,
                         IN BOOLEAN FreeSpace);
// delete all files in directory (FreeSpace = TRUE)
OSSTATUS UDFUnlinkAllFilesInDir(IN PVCB Vcb,
                                IN PUDF_FILE_INFO DirInfo);
// init UDF_FILE_INFO structure for specifiend file
OSSTATUS UDFOpenFile__(IN PVCB Vcb,
                       IN BOOLEAN IgnoreCase,
                       IN BOOLEAN NotDeleted,
                       IN PUNICODE_STRING fn,
                       IN PUDF_FILE_INFO DirInfo,
                       OUT PUDF_FILE_INFO* _FileInfo,
                       IN uint_di* IndexToOpen);
// init UDF_FILE_INFO structure for root directory
OSSTATUS UDFOpenRootFile__(IN PVCB Vcb,
                          IN lb_addr* RootLoc,
                          OUT PUDF_FILE_INFO FileInfo);
// free all memory blocks referenced by given FileInfo
uint32    UDFCleanUpFile__(IN PVCB Vcb,
                          IN PUDF_FILE_INFO FileInfo);
#define  UDF_FREE_NOTHING     0x00
#define  UDF_FREE_FILEINFO    0x01
#define  UDF_FREE_DLOC        0x02
// create zero-sized file
OSSTATUS UDFCreateFile__(IN PVCB Vcb,
                         IN BOOLEAN IgnoreCase,
                         IN PUNICODE_STRING fn,
                         IN uint32 ExtAttrSz,
                         IN uint32 ImpUseLen,
                         IN BOOLEAN Extended,
                         IN BOOLEAN CreateNew,
                      IN OUT PUDF_FILE_INFO DirInfo,
                         OUT PUDF_FILE_INFO* _FileInfo);
// read data from file described with FileInfo
/*
    This routine reads data from file described by FileInfo
 */
__inline
OSSTATUS UDFReadFile__(IN PVCB Vcb,
                       IN PUDF_FILE_INFO FileInfo,
                       IN int64 Offset,   // offset in extent
                       IN SIZE_T Length,
                       IN BOOLEAN Direct,
                       OUT int8* Buffer,
                       OUT PSIZE_T ReadBytes)
{
    ValidateFileInfo(FileInfo);

    return UDFReadExtent(Vcb, &(FileInfo->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes);
} // end UDFReadFile__()*/

/*
    This routine reads data from file described by FileInfo
 */
__inline
OSSTATUS UDFReadFileLocation__(IN PVCB Vcb,
                               IN PUDF_FILE_INFO FileInfo,
                               IN int64 Offset,              // offset in extent to start SubExtent from
                               OUT PEXTENT_MAP* SubExtInfo,  // SubExtent mapping array
                            IN OUT uint32* SubExtInfoSz,      // IN:  maximum number fragments to get
                                                             // OUT: actually obtained fragments
                               OUT int64* NextOffset         // offset, caller can start from to continue
                               )
{
    ValidateFileInfo(FileInfo);

    return UDFReadExtentLocation(Vcb, &(FileInfo->Dloc->DataLoc), Offset, SubExtInfo, SubExtInfoSz, NextOffset);
} // end UDFReadFile__()*/

/*
#define UDFReadFile__(Vcb, FileInfo, Offset, Length, Direct, Buffer, ReadBytes)  \
    (UDFReadExtent(Vcb, &((FileInfo)->Dloc->DataLoc), Offset, Length, Direct, Buffer, ReadBytes))
*/

// zero data in file described by FileInfo
__inline
OSSTATUS UDFZeroFile__(IN PVCB Vcb,
                       IN PUDF_FILE_INFO FileInfo,
                       IN int64 Offset,   // offset in extent
                       IN uint32 Length,
                       IN BOOLEAN Direct,
                       OUT uint32* ReadBytes);
// make sparse area in file described by FileInfo
__inline
OSSTATUS UDFSparseFile__(IN PVCB Vcb,
                         IN PUDF_FILE_INFO FileInfo,
                         IN int64 Offset,   // offset in extent
                         IN uint32 Length,
                         IN BOOLEAN Direct,
                         OUT uint32* ReadBytes);
// pad sector tail with zeros
OSSTATUS UDFPadLastSector(IN PVCB Vcb,
                          IN PEXTENT_INFO ExtInfo);
// update AllocDesc sequence, FileIdent & FileEntry
OSSTATUS UDFCloseFile__(IN PVCB Vcb,
                        IN PUDF_FILE_INFO FileInfo);
// load specified bitmap.
OSSTATUS UDFPrepareXSpaceBitmap(IN PVCB Vcb,
                             IN OUT PSHORT_AD XSpaceBitmap,
                             IN OUT PEXTENT_INFO XSBMExtInfo,
                             IN OUT int8** XSBM,
                             IN OUT uint32* XSl);
// update Freed & Unallocated space bitmaps
OSSTATUS UDFUpdateXSpaceBitmaps(IN PVCB Vcb,
                                IN uint32 PartNum,
                                IN PPARTITION_HEADER_DESC phd); // partition header pointing to Bitmaps
// update Partition Desc & associated data structures
OSSTATUS UDFUpdatePartDesc(PVCB Vcb,
                           int8* Buf);
// update Logical volume integrity descriptor
OSSTATUS UDFUpdateLogicalVolInt(PVCB            Vcb,
                                BOOLEAN         Close);
// blank Unalloc Space Desc
OSSTATUS UDFUpdateUSpaceDesc(IN PVCB Vcb,
                             int8* Buf);
// update Volume Descriptor Sequence
OSSTATUS UDFUpdateVDS(IN PVCB Vcb,
                      IN uint32 block,
                      IN uint32 lastblock,
                      IN uint32 flags);
// rebuild & flushes all system areas
OSSTATUS UDFUmount__(IN PVCB Vcb);
// move file from DirInfo1 to DirInfo2 & renames it to fn
OSSTATUS UDFRenameMoveFile__(IN PVCB Vcb,
                             IN BOOLEAN IgnoreCase,
                          IN OUT BOOLEAN* Replace,   // replace if destination file exists
                             IN PUNICODE_STRING fn,  // destination
                         //    IN uint32 ExtAttrSz,
                          IN OUT PUDF_FILE_INFO DirInfo1,
                          IN OUT PUDF_FILE_INFO DirInfo2,
                          IN OUT PUDF_FILE_INFO FileInfo); // source (opened)
// change file size (on disc)
OSSTATUS UDFResizeFile__(IN PVCB Vcb,
                      IN OUT PUDF_FILE_INFO FileInfo,
                         IN int64 NewLength);
// transform zero-sized file to directory
OSSTATUS UDFRecordDirectory__(IN PVCB Vcb,
                           IN OUT PUDF_FILE_INFO DirInfo); // source (opened)
// remove all DELETED entries from Dir & resize it.
#ifndef UDF_READ_ONLY_BUILD
OSSTATUS UDFPackDirectory__(IN PVCB Vcb,
                         IN OUT PUDF_FILE_INFO FileInfo);   // source (opened)
// rebuild tags for all entries from Dir.
OSSTATUS
UDFReTagDirectory(IN PVCB Vcb,
                  IN OUT PUDF_FILE_INFO FileInfo);   // source (opened)
#endif //UDF_READ_ONLY_BUILD
// load VAT.
OSSTATUS UDFLoadVAT(IN PVCB Vcb,
                     IN uint32 PartNdx);
// get volume free space
int64
__fastcall UDFGetFreeSpace(IN PVCB Vcb);
// get volume total space
int64
__fastcall UDFGetTotalSpace(IN PVCB Vcb);
// get DirIndex for specified FileInfo
PDIR_INDEX_HDR UDFGetDirIndexByFileInfo(IN PUDF_FILE_INFO FileInfo);
// check if the file has been found is deleted
/*BOOLEAN  UDFIsDeleted(IN PDIR_INDEX_ITEM DirNdx);*/
#define UDFIsDeleted(DirNdx) \
    (((DirNdx)->FileCharacteristics & FILE_DELETED) ? TRUE : FALSE)
// check Directory flag
/*BOOLEAN  UDFIsADirectory(IN PUDF_FILE_INFO FileInfo);*/
#define UDFIsADirectory(FileInfo) \
    (((FileInfo) && ((FileInfo)->Dloc) && ((FileInfo)->Dloc->DirIndex || ((FileInfo)->FileIdent && ((FileInfo)->FileIdent->fileCharacteristics & FILE_DIRECTORY)))) ? TRUE : FALSE)
// calculate actual allocation size
/*int64 UDFGetFileAllocationSize(IN PVCB Vcb,
                                  IN PUDF_FILE_INFO FileInfo);*/
#define UDFGetFileAllocationSize(Vcb, FileInfo)  \
    (((FileInfo)->Dloc->DataLoc.Mapping) ? UDFGetExtentLength((FileInfo)->Dloc->DataLoc.Mapping) : Vcb->LBlockSize)
// check if the directory is empty
BOOLEAN  UDFIsDirEmpty(IN PDIR_INDEX_HDR hCurDirNdx);
// flush FE
OSSTATUS UDFFlushFE(IN PVCB Vcb,
                    IN PUDF_FILE_INFO FileInfo,
                    IN uint32 PartNum);
// flush FI
OSSTATUS UDFFlushFI(IN PVCB Vcb,
                    IN PUDF_FILE_INFO FileInfo,
                    IN uint32 PartNum);
// flush all metadata & update counters
OSSTATUS UDFFlushFile__(IN PVCB Vcb,
                        IN PUDF_FILE_INFO FileInfo,
                        IN ULONG FlushFlags = 0);
// check if the file is flushed
#define UDFIsFlushed(FI) \
    (   FI &&                    \
      !(FI->Dloc->FE_Flags & UDF_FE_FLAG_FE_MODIFIED) &&      \
      !(FI->Dloc->DataLoc.Modified) && \
      !(FI->Dloc->AllocLoc.Modified) &&\
      !(FI->Dloc->FELoc.Modified) &&   \
      !(UDFGetDirIndexByFileInfo(FI)[FI->Index].FI_Flags & UDF_FI_FLAG_FI_MODIFIED) )
// compare opened directories
BOOLEAN  UDFCompareFileInfo(IN PUDF_FILE_INFO f1,
                           IN PUDF_FILE_INFO f2);
// pack mappings
void
__fastcall UDFPackMapping(IN PVCB Vcb,
                        IN PEXTENT_INFO ExtInfo);   // Extent array
// check if all the data is in cache.
BOOLEAN  UDFIsExtentCached(IN PVCB Vcb,
                           IN PEXTENT_INFO ExtInfo, // Extent array
                           IN int64 Offset,      // offset in extent
                           IN uint32 Length,
                           IN BOOLEAN ForWrite);
/*BOOLEAN  UDFIsFileCached__(IN PVCB Vcb,
                       IN PUDF_FILE_INFO FileInfo,
                       IN int64 Offset,   // offset in extent
                       IN uint32 Length,
                       IN BOOLEAN ForWrite);*/
#define UDFIsFileCached__(Vcb, FileInfo, Offset, Length, ForWrite)  \
    (UDFIsExtentCached(Vcb, &((FileInfo)->Dloc->DataLoc), Offset, Length, ForWrite))
// check if specified sector belongs to a file
ULONG  UDFIsBlockAllocated(IN void* _Vcb,
                           IN uint32 Lba);
// record VolIdent
OSSTATUS UDFUpdateVolIdent(IN PVCB Vcb,
                           IN UDF_VDS_RECORD Lba,
                           IN PUNICODE_STRING VolIdent);
// calculate checksum for unicode string (for DOS-names)
uint16 
__fastcall UDFUnicodeCksum(PWCHAR s,
                         uint32 n);
//#define UDFUnicodeCksum(s,n)  UDFCrc((uint8*)(s), (n)*sizeof(WCHAR))
//
uint16 
__fastcall
UDFUnicodeCksum150(PWCHAR s,
                uint32 n);

uint32 
__fastcall crc32(IN uint8* s,
            IN uint32 len);
// calculate a 16-bit CRC checksum using ITU-T V.41 polynomial
uint16 
__fastcall UDFCrc(IN uint8* Data,
                IN SIZE_T Size);
// read the first block of a tagged descriptor & check it
OSSTATUS UDFReadTagged(IN PVCB Vcb,
                       IN int8* Buf,
                       IN uint32 Block, 
                       IN uint32 Location, 
                       OUT uint16 *Ident);
// get physycal Lba for partition-relative addr
uint32
__fastcall UDFPartLbaToPhys(IN PVCB Vcb,
                            IN lb_addr* Addr);
// look for Anchor(s) at all possible locations
lba_t  UDFFindAnchor(PVCB           Vcb);         // Volume control block
// look for Volume recognition sequence
uint32    UDFFindVRS(PVCB           Vcb);
// process Primary volume descriptor
void     UDFLoadPVolDesc(PVCB Vcb,
                         int8* Buf); // pointer to buffer containing PVD
//
#define UDFGetLVIDiUse(Vcb) \
    ( ((Vcb) && (Vcb)->LVid) ? \
        ( (LogicalVolIntegrityDescImpUse*) \
                     ( ((int8*)(Vcb->LVid+1)) + \
                       Vcb->LVid->numOfPartitions*2*sizeof(uint32))) \
       : NULL)

// load Logical volume integrity descriptor
OSSTATUS UDFLoadLogicalVolInt(PDEVICE_OBJECT DeviceObject,
                              PVCB           Vcb,
                              extent_ad      loc);
// load Logical volume descriptor
OSSTATUS UDFLoadLogicalVol(PDEVICE_OBJECT DeviceObject,
                           PVCB           Vcb,
                           int8*          Buf,
                           lb_addr        *fileset);
// process Partition descriptor
OSSTATUS UDFLoadPartDesc(PVCB      Vcb,
                         int8*     Buf);
// scan VDS & fill special array
OSSTATUS UDFReadVDS(IN PVCB Vcb,
                    IN uint32 block,
                    IN uint32 lastblock,
                    IN PUDF_VDS_RECORD vds,
                    IN int8* Buf);
// process a main/reserve volume descriptor sequence.
OSSTATUS UDFProcessSequence(IN PDEVICE_OBJECT DeviceObject,
                            IN PVCB           Vcb,
                            IN uint32          block,
                            IN uint32          lastblock,
                           OUT lb_addr        *fileset);
// Verifies a main/reserve volume descriptor sequence.
OSSTATUS UDFVerifySequence(IN PDEVICE_OBJECT    DeviceObject,
                           IN PVCB              Vcb,
                           IN uint32             block,
                           IN uint32             lastblock,
                          OUT lb_addr           *fileset);
// remember some useful info about FileSet & RootDir location
void     UDFLoadFileset(IN PVCB            Vcb,
                        IN PFILE_SET_DESC  fset,
                       OUT lb_addr         *root,
                       OUT lb_addr         *sysstream);
// load partition info
OSSTATUS UDFLoadPartition(IN PDEVICE_OBJECT  DeviceObject,
                          IN PVCB            Vcb,
                         OUT lb_addr         *fileset);
// check if this is an UDF-formatted disk
OSSTATUS UDFGetDiskInfoAndVerify(IN PDEVICE_OBJECT DeviceObject, // the target device object
                                 IN PVCB           Vcb);         // Volume control block from this DevObj
// create hard link for the file
OSSTATUS UDFHardLinkFile__(IN PVCB Vcb,
                           IN BOOLEAN IgnoreCase,
                        IN OUT BOOLEAN* Replace,      // replace if destination file exists
                           IN PUNICODE_STRING fn,     // destination
                        IN OUT PUDF_FILE_INFO DirInfo1,
                        IN OUT PUDF_FILE_INFO DirInfo2,
                        IN OUT PUDF_FILE_INFO FileInfo);  // source (opened)
//
LONG     UDFFindDloc(IN PVCB Vcb,
                     IN uint32 Lba);
//
LONG     UDFFindFreeDloc(IN PVCB Vcb,
                         IN uint32 Lba);
//
OSSTATUS UDFAcquireDloc(IN PVCB Vcb,
                        IN PUDF_DATALOC_INFO Dloc);
//
OSSTATUS UDFReleaseDloc(IN PVCB Vcb,
                        IN PUDF_DATALOC_INFO Dloc);
//
OSSTATUS UDFStoreDloc(IN PVCB Vcb,
                      IN PUDF_FILE_INFO fi,
                      IN uint32 Lba);
//
OSSTATUS UDFRemoveDloc(IN PVCB Vcb,
                       IN PUDF_DATALOC_INFO Dloc);
//
OSSTATUS UDFUnlinkDloc(IN PVCB Vcb,
                       IN PUDF_DATALOC_INFO Dloc);
//
void     UDFFreeDloc(IN PVCB Vcb,
                     IN PUDF_DATALOC_INFO Dloc);
//
void     UDFRelocateDloc(IN PVCB Vcb,
                         IN PUDF_DATALOC_INFO Dloc,
                         IN uint32 NewLba);
//
void     UDFReleaseDlocList(IN PVCB Vcb);
//
PUDF_FILE_INFO UDFLocateParallelFI(PUDF_FILE_INFO di,  // parent FileInfo
                                   uint_di i,            // Index
                                   PUDF_FILE_INFO fi);
//
PUDF_FILE_INFO UDFLocateAnyParallelFI(PUDF_FILE_INFO fi);   // FileInfo to start search from
//
void UDFInsertLinkedFile(PUDF_FILE_INFO fi,   // FileInfo to be added to chain
                         PUDF_FILE_INFO fi2);   // any FileInfo fro the chain
//
OSSTATUS UDFCreateRootFile__(IN PVCB Vcb,
                         //    IN uint16 AllocMode, // short/long/ext/in-icb  // always in-ICB
                             IN uint32 PartNum,
                             IN uint32 ExtAttrSz,
                             IN uint32 ImpUseLen,
                             IN BOOLEAN Extended,
                             OUT PUDF_FILE_INFO* _FileInfo);
// try to create StreamDirectory associated with given file
OSSTATUS UDFCreateStreamDir__(IN PVCB Vcb,
                              IN PUDF_FILE_INFO FileInfo,    // file containing stream-dir
                              OUT PUDF_FILE_INFO* _SDirInfo);
//
OSSTATUS UDFOpenStreamDir__(IN PVCB Vcb,
                            IN PUDF_FILE_INFO FileInfo,    // file containing stream-dir
                            OUT PUDF_FILE_INFO* _SDirInfo);
//
#define UDFIsAStreamDir(FI)  ((FI) && ((FI)->Dloc) && ((FI)->Dloc->FE_Flags & UDF_FE_FLAG_IS_SDIR))
//
#define UDFHasAStreamDir(FI)  ((FI) && ((FI)->Dloc) && ((FI)->Dloc->FE_Flags & UDF_FE_FLAG_HAS_SDIR))
//
#define UDFIsAStream(FI)  ((FI) && UDFIsAStreamDir((FI)->ParentFile))
//
#define UDFIsSDirDeleted(FI)  ((FI) && (FI)->Dloc && ((FI)->Dloc->FE_Flags & UDF_FE_FLAG_IS_DEL_SDIR))
// Record updated VAT (if updated)
OSSTATUS UDFRecordVAT(IN PVCB Vcb);
//
OSSTATUS UDFModifyVAT(IN PVCB Vcb,
                      IN uint32 Lba,
                      IN uint32 Length);
//
OSSTATUS UDFUpdateVAT(IN void* _Vcb,
                      IN uint32 Lba,
                      IN uint32* RelocTab,
                      IN uint32 BCount);
//
OSSTATUS
__fastcall UDFUnPackMapping(IN PVCB Vcb,
                          IN PEXTENT_INFO ExtInfo);   // Extent array
//
OSSTATUS UDFConvertFEToNonInICB(IN PVCB Vcb,
                                IN PUDF_FILE_INFO FileInfo,
                                IN uint8 NewAllocMode);
//
OSSTATUS UDFConvertFEToExtended(IN PVCB Vcb,
                                IN PUDF_FILE_INFO FileInfo);
//
#define UDFGetPartNumByPartNdx(Vcb, pi) (Vcb->Partitions[pi].PartitionNum)
//
uint32
__fastcall UDFPartLen(PVCB Vcb,
                      uint32 PartNum);
//
OSSTATUS UDFPretendFileDeleted__(IN PVCB Vcb,
                                 IN PUDF_FILE_INFO FileInfo);

#define UDFStreamsSupported(Vcb) \
    (Vcb->maxUDFWriteRev >= 0x0200)

#define UDFNtAclSupported(Vcb) \
    (Vcb->maxUDFWriteRev >= 0x0200)

#define UDFReferenceFile__(fi)                       \
{                                                    \
    UDFInterlockedIncrement((PLONG)&((fi)->RefCount));  \
    UDFInterlockedIncrement((PLONG)&((fi)->Dloc->LinkRefCount));  \
    if((fi)->ParentFile) {                           \
        UDFInterlockedIncrement((PLONG)&((fi)->ParentFile->OpenCount));  \
    }                                                \
}

#define UDFReferenceFileEx__(fi,i)                   \
{                                                    \
    UDFInterlockedExchangeAdd((PLONG)&((fi)->RefCount),i);  \
    UDFInterlockedExchangeAdd((PLONG)&((fi)->Dloc->LinkRefCount),i);  \
    if((fi)->ParentFile) {                           \
        UDFInterlockedExchangeAdd((PLONG)&((fi)->ParentFile->OpenCount),i);  \
    }                                                \
}

#define UDFDereferenceFile__(fi)                     \
{                                                    \
    UDFInterlockedDecrement((PLONG)&((fi)->RefCount));  \
    UDFInterlockedDecrement((PLONG)&((fi)->Dloc->LinkRefCount));  \
    if((fi)->ParentFile) {                           \
        UDFInterlockedDecrement((PLONG)&((fi)->ParentFile->OpenCount));  \
    }                                                \
}

#define UDFIsDirEmpty__(fi) UDFIsDirEmpty((fi)->Dloc->DirIndex)
#define UDFIsDirOpened__(fi) (fi->OpenCount)

#define UDFSetFileAllocMode__(fi, mode)  \
{                                       \
    (fi)->Dloc->DataLoc.Flags = \
        ((fi)->Dloc->DataLoc.Flags & ~EXTENT_FLAG_ALLOC_MASK) | (mode & EXTENT_FLAG_ALLOC_MASK);     \
}

#define UDFGetFileAllocMode__(fi)  ((fi)->Dloc->DataLoc.Flags & EXTENT_FLAG_ALLOC_MASK)

#define UDFGetFileICBAllocMode__(fi)  (((PFILE_ENTRY)((fi)->Dloc->FileEntry))->icbTag.flags & ICB_FLAG_ALLOC_MASK)

#ifndef UDF_LIMIT_DIR_SIZE // release
#define UDF_DIR_INDEX_FRAME_SH   9
#else   //  demo
#define UDF_DIR_INDEX_FRAME_SH   7
#endif

#define UDF_DIR_INDEX_FRAME      ((uint_di)(1 << UDF_DIR_INDEX_FRAME_SH))

#define UDF_DIR_INDEX_FRAME_GRAN (32)
#define UDF_DIR_INDEX_FRAME_GRAN_MASK (UDF_DIR_INDEX_FRAME_GRAN-1)
#define AlignDirIndex(n)   ((n+UDF_DIR_INDEX_FRAME_GRAN_MASK) & ~(UDF_DIR_INDEX_FRAME_GRAN_MASK))

#if defined _X86_ && !defined UDF_LIMIT_DIR_SIZE

PDIR_INDEX_ITEM
__fastcall
UDFDirIndex(
    IN PDIR_INDEX_HDR hDirNdx,
    IN uint32 i
    );

#else   // NO X86 optimization , use generic C/C++
__inline PDIR_INDEX_ITEM UDFDirIndex(IN PDIR_INDEX_HDR hDirNdx,
                                     IN uint_di i)
{
#ifdef UDF_LIMIT_DIR_SIZE
    if( hDirNdx && (i < hDirNdx->LastFrameCount))
        return &( (((PDIR_INDEX_ITEM*)(hDirNdx+1))[0])[i] );
#else //UDF_LIMIT_DIR_SIZE
    uint_di j, k;
    if( hDirNdx &&
        ((j = (i >> UDF_DIR_INDEX_FRAME_SH)) < (k = hDirNdx->FrameCount) ) &&
        ((i = (i & (UDF_DIR_INDEX_FRAME-1))) < ((j < (k-1)) ? UDF_DIR_INDEX_FRAME : hDirNdx->LastFrameCount)) )
        return &( (((PDIR_INDEX_ITEM*)(hDirNdx+1))[j])[i] );
#endif // UDF_LIMIT_DIR_SIZE
    return NULL;
}
#endif // _X86_

#define UDFDirIndexGetLastIndex(di)  ((((di)->FrameCount - 1) << UDF_DIR_INDEX_FRAME_SH) + (di)->LastFrameCount)

// arr - bit array,  bit - number of bit
#ifdef _X86_

#ifdef _CONSOLE
#define CheckAddr(addr) {ASSERT((uint32)(addr) > 0x1000);}
#else
#define CheckAddr(addr) {ASSERT((uint32)(addr) & 0x80000000);}
#endif

#define UDFGetBit(arr, bit) UDFGetBit__((uint32*)(arr), bit)

BOOLEAN
__fastcall
UDFGetBit__(
    IN uint32* arr,
    IN uint32 bit
    );

#define UDFSetBit(arr, bit) UDFSetBit__((uint32*)(arr), bit)

void
__fastcall
UDFSetBit__(
    IN uint32* arr,
    IN uint32 bit
    );

#define UDFSetBits(arr, bit, bc) UDFSetBits__((uint32*)(arr), bit, bc)

void
UDFSetBits__(
    IN uint32* arr,
    IN uint32 bit,
    IN uint32 bc
    );

#define UDFClrBit(arr, bit) UDFClrBit__((uint32*)(arr), bit)

void
__fastcall
UDFClrBit__(
    IN uint32* arr,
    IN uint32 bit
    );

#define UDFClrBits(arr, bit, bc) UDFClrBits__((uint32*)(arr), bit, bc)

void
UDFClrBits__(
    IN uint32* arr,
    IN uint32 bit,
    IN uint32 bc
    );

#else   // NO X86 optimization , use generic C/C++

#define UDFGetBit(arr, bit) (    (BOOLEAN) ( ((((uint32*)(arr))[(bit)>>5]) >> ((bit)&31)) &1 )    )
#define UDFSetBit(arr, bit) ( (((uint32*)(arr))[(bit)>>5]) |= (((uint32)1) << ((bit)&31)) )
#define UDFClrBit(arr, bit) ( (((uint32*)(arr))[(bit)>>5]) &= (~(((uint32)1) << ((bit)&31))) )

#define UDFSetBits(arr, bit, bc) \
{uint32 j;                       \
    for(j=0;j<bc;j++) {          \
        UDFSetBit(arr, (bit)+j); \
}}

#define UDFClrBits(arr, bit, bc) \
{uint32 j;                       \
    for(j=0;j<bc;j++) {          \
        UDFClrBit(arr, (bit)+j); \
}}

#endif // _X86_

#define UDFGetUsedBit(arr,bit)      (!UDFGetBit(arr,bit))
#define UDFGetFreeBit(arr,bit)      UDFGetBit(arr,bit)
#define UDFSetUsedBit(arr,bit)      UDFClrBit(arr,bit)
#define UDFSetFreeBit(arr,bit)      UDFSetBit(arr,bit)
#define UDFSetUsedBits(arr,bit,bc)  UDFClrBits(arr,bit,bc)
#define UDFSetFreeBits(arr,bit,bc)  UDFSetBits(arr,bit,bc)

#define UDFGetBadBit(arr,bit)       UDFGetBit(arr,bit)

#define UDFGetZeroBit(arr,bit)      UDFGetBit(arr,bit)
#define UDFSetZeroBit(arr,bit)      UDFSetBit(arr,bit)
#define UDFClrZeroBit(arr,bit)      UDFClrBit(arr,bit)
#define UDFSetZeroBits(arr,bit,bc)  UDFSetBits(arr,bit,bc)
#define UDFClrZeroBits(arr,bit,bc)  UDFClrBits(arr,bit,bc)

#if defined UDF_DBG || defined _CONSOLE
  #ifdef UDF_TRACK_ONDISK_ALLOCATION_OWNERS
    #define UDFSetFreeBitOwner(Vcb, i) (Vcb)->FSBM_Bitmap_owners[i] = 0;
    #define UDFSetUsedBitOwner(Vcb, i, o) (Vcb)->FSBM_Bitmap_owners[i] = o;
    #define UDFGetUsedBitOwner(Vcb, i) ((Vcb)->FSBM_Bitmap_owners[i])
    #define UDFCheckUsedBitOwner(Vcb, i, o) { \
      ASSERT(i<(Vcb)->FSBM_BitCount); \
      if((Vcb)->FSBM_Bitmap_owners[i] != -1) { \
        ASSERT((Vcb)->FSBM_Bitmap_owners[i] == o); \
      } else { \
        ASSERT((Vcb)->FSBM_Bitmap_owners[i] != 0); \
        (Vcb)->FSBM_Bitmap_owners[i] = o; \
      } \
    }
    #define UDFCheckFreeBitOwner(Vcb, i) ASSERT((Vcb)->FSBM_Bitmap_owners[i] == 0);
  #else
    #define UDFSetFreeBitOwner(Vcb, i)
    #define UDFSetUsedBitOwner(Vcb, i, o)
    #define UDFCheckUsedBitOwner(Vcb, i, o)
    #define UDFCheckFreeBitOwner(Vcb, i)
  #endif //UDF_TRACK_ONDISK_ALLOCATION_OWNERS
#else
    #define UDFSetFreeBitOwner(Vcb, i)
    #define UDFSetUsedBitOwner(Vcb, i, o)
    #define UDFCheckUsedBitOwner(Vcb, i, o)
    #define UDFCheckFreeBitOwner(Vcb, i)
#endif //UDF_DBG

#ifdef UDF_TRACK_FS_STRUCTURES
extern
VOID
UDFRegisterFsStructure(
    PVCB   Vcb,
    uint32 Lba,
    uint32 Length  // sectors
    );
#else //UDF_TRACK_FS_STRUCTURES
#define UDFRegisterFsStructure(Vcb, Lba, Length)   {NOTHING;}
#endif //UDF_TRACK_FS_STRUCTURES

extern const char hexChar[];

#define UDF_MAX_VERIFY_CACHE   (8*1024*1024/2048)
#define UDF_VERIFY_CACHE_LOW   (4*1024*1024/2048)
#define UDF_VERIFY_CACHE_GRAN  (512*1024/2048)
#define UDF_SYS_CACHE_STOP_THR (10*1024*1024/2048)

OSSTATUS
UDFVInit(
    IN PVCB Vcb
    );

VOID
UDFVRelease(
    IN PVCB Vcb
    );

#define PH_FORGET_VERIFIED    0x00800000
#define PH_READ_VERIFY_CACHE  0x00400000
#define PH_KEEP_VERIFY_CACHE  0x00200000

OSSTATUS
UDFVWrite(
    IN PVCB Vcb,
    IN void* Buffer,     // Target buffer
    IN uint32 BCount,
    IN uint32 LBA,
//    OUT PSIZE_T WrittenBytes,
    IN uint32 Flags
    );

OSSTATUS
UDFVRead(
    IN PVCB Vcb,
    IN void* Buffer,     // Target buffer
    IN uint32 BCount,
    IN uint32 LBA,
//    OUT uint32* ReadBytes,
    IN uint32 Flags
    );

OSSTATUS
UDFVForget(
    IN PVCB Vcb,
    IN uint32 BCount,
    IN uint32 LBA,
    IN uint32 Flags
    );

#define UFD_VERIFY_FLAG_FORCE   0x01
#define UFD_VERIFY_FLAG_WAIT    0x02
#define UFD_VERIFY_FLAG_BG      0x04
#define UFD_VERIFY_FLAG_LOCKED  0x10

VOID
UDFVVerify(
    IN PVCB Vcb,
    IN ULONG Flags
    );

VOID
UDFVFlush(
    IN PVCB Vcb
    );

__inline
BOOLEAN
__fastcall UDFVIsStored(
    IN PVCB Vcb,
    IN lba_t lba
    )
{
    if(!Vcb->VerifyCtx.VInited)
        return FALSE;
    return UDFGetBit(Vcb->VerifyCtx.StoredBitMap, lba);
} // end UDFVIsStored()

BOOLEAN
__fastcall
UDFCheckArea(
    IN PVCB Vcb,
    IN lba_t LBA,
    IN uint32 BCount
    );

#endif // __UDF_STRUCT_SUPPORT_H__