#ifndef _UDF_ALLOCATION_DESCRIPTOR_LIST_H
#define _UDF_ALLOCATION_DESCRIPTOR_LIST_H
#include "UdfDebug.h"
#include "Icb.h"
#include "UdfStructures.h"
#include "Volume.h"
#include <util/kernel_cpp.h>
template <class Accessor>
class AllocationDescriptorList {
private:
typedef typename Accessor::DescriptorType Descriptor;
public:
AllocationDescriptorList(Icb *icb,
Accessor accessor = Accessor());
status_t FindExtent(off_t start, long_address *extent,
bool *isEmpty);
private:
off_t _BlockIndex() const { return fBlockIndex; }
Descriptor *_CurrentDescriptor() const;
Descriptor *_DescriptorArray() const;
size_t _DescriptorArraySize() const;
int32 _DescriptorIndex() const { return fDescriptorIndex; }
int32 _DescriptorNumber() const { return fDescriptorNumber; }
status_t _MoveToNextDescriptor();
void _Rewind();
void _WalkContinuationChain(Descriptor *descriptor);
Accessor fAccessor;
CachedBlock fAdditionalDescriptors;
off_t fBlockIndex;
int32 fDescriptorIndex;
int32 fDescriptorNumber;
Icb *fIcb;
Descriptor *fIcbDescriptors;
int32 fIcbDescriptorsSize;
bool fReadFromIcb;
Volume *fVolume;
};
template<class Accessor>
AllocationDescriptorList<Accessor>::AllocationDescriptorList(Icb *icb,
Accessor accessor)
:
fAccessor(accessor),
fAdditionalDescriptors(icb->GetVolume()),
fBlockIndex(0),
fDescriptorIndex(0),
fDescriptorNumber(0),
fIcb(icb),
fIcbDescriptors((Descriptor *)icb->AllocationDescriptors()),
fIcbDescriptorsSize(icb->AllocationDescriptorsSize()),
fReadFromIcb(true),
fVolume(icb->GetVolume())
{
TRACE(("AllocationDescriptorList<>::AllocationDescriptorList\n"));
_WalkContinuationChain(_CurrentDescriptor());
}
template<class Accessor>
status_t
AllocationDescriptorList<Accessor>::FindExtent(off_t start,
long_address *extent, bool *isEmpty)
{
TRACE(("AllocationDescriptorList<>::FindExtent: start: %" B_PRIdOFF ", "
"extent: %p, isEmpty: %p\n", start, extent, isEmpty));
off_t startBlock = start >> fVolume->BlockShift();
if (startBlock < _BlockIndex())
_Rewind();
status_t status = B_OK;
while (true) {
Descriptor *descriptor = _CurrentDescriptor();
if (descriptor) {
if (_BlockIndex() <= startBlock && startBlock
< _BlockIndex() + fAccessor.GetLength(*descriptor)) {
off_t offset = startBlock - _BlockIndex();
extent->set_block(fAccessor.GetBlock(*descriptor) + offset);
extent->set_partition(fAccessor.GetPartition(*descriptor));
extent->set_length(fAccessor.GetLength(*descriptor)
- (offset*fVolume->BlockSize()));
extent->set_type(fAccessor.GetType(*descriptor));
break;
} else {
_MoveToNextDescriptor();
}
} else {
TRACE_ERROR(("AllocationDescriptorList<>::FindExtent: "
"Descriptor #%" B_PRId32 " found NULL\n",
_DescriptorNumber()));
status = B_ERROR;
break;
}
}
return status;
}
template<class Accessor>
typename AllocationDescriptorList<Accessor>::Descriptor*
AllocationDescriptorList<Accessor>::_CurrentDescriptor() const
{
TRACE(("AllocationDescriptorList<>::_CurrentDescriptor:\n"
"\t_DescriptorIndex() + 1 * sizeof(Descriptor) = %ld\n"
"\t_DescriptorArraySize() = %ld\n"
"\t_DescriptorArray() = %p\n",
(_DescriptorIndex() + 1) * sizeof(Descriptor),
_DescriptorArraySize(), _DescriptorArray()));
return ((_DescriptorIndex() + 1) * sizeof(Descriptor)
<= _DescriptorArraySize())
? &(_DescriptorArray()[_DescriptorIndex()])
: NULL;
}
template<class Accessor>
status_t
AllocationDescriptorList<Accessor>::_MoveToNextDescriptor()
{
Descriptor* descriptor = _CurrentDescriptor();
if (!descriptor)
return B_ENTRY_NOT_FOUND;
fBlockIndex += fAccessor.GetLength(*descriptor);
fDescriptorIndex++;
fDescriptorNumber++;
descriptor = _CurrentDescriptor();
_WalkContinuationChain(descriptor);
return B_ERROR;
}
template<class Accessor>
void
AllocationDescriptorList<Accessor>::_WalkContinuationChain(Descriptor *descriptor)
{
TRACE(("AllocationDescriptorList<>::_WalkContinuationChain: descriptor = %p\n",
descriptor));
if (descriptor
&& fAccessor.GetType(*descriptor) == EXTENT_TYPE_CONTINUATION) {
fAdditionalDescriptors.SetTo(fAccessor, *descriptor);
fReadFromIcb = false;
fDescriptorIndex = 0;
_WalkContinuationChain(_CurrentDescriptor());
}
}
template<class Accessor>
void
AllocationDescriptorList<Accessor>::_Rewind()
{
fDescriptorIndex = 0;
fDescriptorNumber = 0;
fReadFromIcb = true;
}
template<class Accessor>
typename AllocationDescriptorList<Accessor>::Descriptor*
AllocationDescriptorList<Accessor>::_DescriptorArray() const
{
return fReadFromIcb ? fIcbDescriptors
: (typename AllocationDescriptorList<Accessor>::Descriptor *)
fAdditionalDescriptors.Block();
}
template<class Accessor>
size_t
AllocationDescriptorList<Accessor>::_DescriptorArraySize() const
{
return fReadFromIcb ? fIcbDescriptorsSize
: fAdditionalDescriptors.BlockSize();
}
class ShortDescriptorAccessor {
public:
ShortDescriptorAccessor(uint16 partition)
:
fPartition(partition)
{
}
typedef short_address DescriptorType;
inline uint32 GetBlock(DescriptorType &descriptor) const
{
return descriptor.block();
}
inline uint32 GetLength(DescriptorType &descriptor) const
{
return descriptor.length();
}
inline uint16 GetPartition(DescriptorType &descriptor) const
{
return fPartition;
}
inline uint8 GetType(DescriptorType &descriptor) const
{
return descriptor.type();
}
private:
uint16 fPartition;
};
class LongDescriptorAccessor {
public:
typedef long_address DescriptorType;
inline uint32 GetBlock(DescriptorType &descriptor) const
{
return descriptor.block();
}
inline uint32 GetLength(DescriptorType &descriptor) const
{
return descriptor.length();
}
inline uint16 GetPartition(DescriptorType &descriptor) const
{
return descriptor.partition();
}
inline uint8 GetType(DescriptorType &descriptor) const
{
return descriptor.type();
}
};
#endif