#pragma segment Catalog
#include <sys/param.h>
#include <sys/utfconv.h>
#include "../../hfs_endian.h"
#include "../headers/FileMgrInternal.h"
#include "../headers/BTreesInternal.h"
#include "../headers/CatalogPrivate.h"
#include "../headers/HFSUnicodeWrappers.h"
extern SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 );
UInt32
GetDirEntrySize(BTreeIterator *bip, ExtendedVCB * vol)
{
CatalogKey * ckp;
CatalogName * cnp;
ByteCount utf8chars;
UInt8 name[kdirentMaxNameBytes + 1];
OSErr result;
ckp = (CatalogKey*) &bip->key;
if (vol->vcbSigWord == kHFSPlusSigWord) {
cnp = (CatalogName*) &ckp->hfsPlus.nodeName;
utf8chars = utf8_encodelen(cnp->ustr.unicode,
cnp->ustr.length * sizeof(UniChar), ':', 0);
if (utf8chars > kdirentMaxNameBytes)
utf8chars = kdirentMaxNameBytes;
} else {
cnp = (CatalogName*) ckp->hfs.nodeName;
result = hfs_to_utf8(vol, cnp->pstr, kdirentMaxNameBytes + 1,
&utf8chars, name);
if (result) {
result = mac_roman_to_utf8(cnp->pstr, MAXHFSVNODELEN + 1,
&utf8chars, name);
}
}
return DIRENTRY_SIZE(utf8chars);
}
OSErr
PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op)
{
#define CAT_START_OFFSET (2 * sizeof(struct hfsdotentry))
ExtendedVCB * vol;
FCB * fcb;
OSErr result = 0;
if (cip->folderID != cip->parentID)
return(cmNotFound);
vol = cip->volume;
fcb = GetFileControlBlock(vol->catalogRefNum);
UpdateBtreeIterator(cip, bip);
if (cip->currentOffset == offset) {
*op = kBTreeCurrentRecord;
} else if (cip->nextOffset == offset) {
*op = kBTreeNextRecord;
} else {
*op = kBTreeNextRecord;
result = BTSearchRecord(fcb, bip, NULL, NULL, bip);
if (result)
goto exit;
if (offset > CAT_START_OFFSET) {
HFSCatalogNodeID pid, *idp;
UInt32 curOffset, nextOffset;
result = BTIterateRecord( fcb, kBTreeNextRecord, bip, NULL, NULL );
if (result)
goto exit;
if (vol->vcbSigWord == kHFSPlusSigWord)
idp = &((CatalogKey*) &bip->key)->hfsPlus.parentID;
else
idp = &((CatalogKey*) &bip->key)->hfs.parentID;
pid = *idp;
curOffset = CAT_START_OFFSET;
nextOffset = CAT_START_OFFSET + GetDirEntrySize(bip, vol);
while (nextOffset < offset) {
result = BTIterateRecord( fcb, kBTreeNextRecord, bip, NULL, NULL );
if (result)
goto exit;
if (pid != *idp) {
result = cmNotFound;
goto exit;
}
curOffset = nextOffset;
nextOffset += GetDirEntrySize(bip, vol);
};
if (nextOffset != offset) {
result = cmNotFound;
goto exit;
}
UpdateCatalogIterator(bip, cip);
cip->currentOffset = curOffset;
cip->nextOffset = nextOffset;
}
}
exit:
if (result == btNotFound)
result = cmNotFound;
return result;
}
SInt32
CompareCatalogKeys(HFSCatalogKey *searchKey, HFSCatalogKey *trialKey)
{
HFSCatalogNodeID searchParentID, trialParentID;
SInt32 result;
searchParentID = searchKey->parentID;
trialParentID = trialKey->parentID;
if ( searchParentID > trialParentID ) result = 1;
else if ( searchParentID < trialParentID )
result = -1;
else result = FastRelString(searchKey->nodeName, trialKey->nodeName);
return result;
}
SInt32
CompareExtendedCatalogKeys(HFSPlusCatalogKey *searchKey, HFSPlusCatalogKey *trialKey)
{
SInt32 result;
HFSCatalogNodeID searchParentID, trialParentID;
searchParentID = searchKey->parentID;
trialParentID = trialKey->parentID;
if ( searchParentID > trialParentID ) {
result = 1;
}
else if ( searchParentID < trialParentID )
{
result = -1;
}
else {
if ( searchKey->nodeName.length == 0 || trialKey->nodeName.length == 0 )
result = searchKey->nodeName.length - trialKey->nodeName.length;
else
result = FastUnicodeCompare(&searchKey->nodeName.unicode[0], searchKey->nodeName.length,
&trialKey->nodeName.unicode[0], trialKey->nodeName.length);
}
return result;
}