/******************************************************************************
 * biso.c
 *
 * Copyright (c) 2020, longpanda <admin@ventoy.net>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "biso.h"
#include "biso_list.h"
#include "biso_util.h"
#include "biso_9660.h"
#include "biso_eltorito.h"
#include "biso_rockridge.h"
#include "biso_joliet.h"
#include "biso_dump.h"

CONST STATIC CHAR *g_aszErrMsg[] = 
{
    "Success",                   /* BISO_SUCCESS */
    "General failed",            /* BISO_ERR_FAILED */
    "Null pointer",              /* BISO_ERR_NULL_PTR */
    "Failed to alloc memory",    /* BISO_ERR_ALLOC_MEM */
    "Failed to open file",       /* BISO_ERR_OPEN_FILE */
    "Failed to read file",       /* BISO_ERR_READ_FILE */
    "Failed to write file",      /* BISO_ERR_WRITE_FILE */
    "Invalid iso-9660 format",   /* BISO_ERR_INVALID_ISO9660 */
    "Unsupported block size",    /* BISO_ERR_UNSUPPORTED_BLKSIZE */
    "Invalid parameter",         /* BISO_ERR_INVALID_PARAM */
    "Not found",                 /* BISO_ERR_NOT_FOUND */
    "Not record in iso file",    /* BISO_ERR_NOT_RECORD */
    "Handle is not initialized", /* BISO_ERR_HANDLE_UNINITIALIZED */
};

int g_biso_debug = 0;

VOID BISO_SetDebug(int debug)
{
    g_biso_debug = debug;
}

CONST CHAR * BISO_GetErrMsg(IN ULONG ulErrCode)
{
    if (ulErrCode > BISO_ERR_BASE)
    {
        ulErrCode -= BISO_ERR_BASE;
    }

    if (ulErrCode > ARRAY_SIZE(g_aszErrMsg))
    {
        return NULL;
    }

    return g_aszErrMsg[ulErrCode];
}

VOID BISO_GetNow(OUT BISO_DATE_S *pstTM)
{
    INT iTimeZone;
    INT iLocalHour;
    INT iGMTHour;
    time_t ulTime;
    struct tm *pstLocalTM = NULL;
    struct tm *pstGMTM = NULL;

    if (NULL == pstTM)
    {
        return;
    }
    
    time(&ulTime);
    pstGMTM = gmtime(&ulTime); 
    iGMTHour = pstGMTM->tm_hour;

    pstLocalTM = localtime(&ulTime);
    iLocalHour = pstLocalTM->tm_hour;

    iTimeZone = iLocalHour - iGMTHour;     
    if (iTimeZone < -12) 
    {  
        iTimeZone += 24;
    } 
    else if (iTimeZone > 12) 
    {
        iTimeZone -= 24;
    }

    pstTM->usYear    = pstLocalTM->tm_year + 1900;
    pstTM->ucMonth   = pstLocalTM->tm_mon  + 1;
    pstTM->ucDay     = pstLocalTM->tm_mday;
    pstTM->ucHour    = pstLocalTM->tm_hour;
    pstTM->ucMin     = pstLocalTM->tm_min;
    pstTM->ucSecond  = pstLocalTM->tm_sec;
    pstTM->usMillSec = 0;
    pstTM->cZone     = (CHAR)iTimeZone;

    return;
}

VOID BISO_TimeConv(IN ULONG ulTime, OUT BISO_DATE_S *pstTM)
{
    time_t ulTm = ulTime;
    struct tm *pstLocalTM = NULL;

    pstLocalTM = localtime(&ulTm);
    pstTM->usYear    = pstLocalTM->tm_year + 1900;
    pstTM->ucMonth   = pstLocalTM->tm_mon  + 1;
    pstTM->ucDay     = pstLocalTM->tm_mday;
    pstTM->ucHour    = pstLocalTM->tm_hour;
    pstTM->ucMin     = pstLocalTM->tm_min;
    pstTM->ucSecond  = pstLocalTM->tm_sec;
    pstTM->usMillSec = 0;
    pstTM->cZone     = (CHAR)BISO_UTIL_GetTimeZone();
    
    return;
}

BISO_READ_S * BISO_AllocReadHandle(VOID)
{
    return (BISO_READ_S *)BISO_9660_CreateParser();
}

VOID BISO_FreeReadHandle(INOUT BISO_READ_S *pstRead)
{
    BISO_9660_DestroyParser((BISO_PARSER_S *)pstRead);
}

BOOL_T BISO_IsISOFile(IN CONST CHAR *pcFileName)
{
    UINT uiReadLen;
    UINT64 ui64FileSize = 0;
    BISO_FILE_S *pstFile = NULL;
    BISO_VD_S stVolDesc;

    /* 先看文件大小,过小的文件不可能是ISO文件 */
    ui64FileSize = BISO_PLAT_GetFileSize(pcFileName);
    if (ui64FileSize < BISO_SYSTEM_AREA_SIZE + sizeof(BISO_PVD_S))
    {
        return BOOL_FALSE;
    }

    /* 打开ISO文件 */
    pstFile = BISO_PLAT_OpenExistFile(pcFileName);
    if (NULL == pstFile)
    {
        return BOOL_FALSE;
    }

    /* 标准规定前16个逻辑扇区用来保存系统数据,VD信息从第17个扇区开始 */
    BISO_PLAT_SeekFile(pstFile, BISO_SYSTEM_AREA_SIZE, SEEK_SET);

    /* 读出VD信息 */
    uiReadLen = (UINT)BISO_PLAT_ReadFile(pstFile, 1, sizeof(stVolDesc), &stVolDesc);
    if (uiReadLen != sizeof(stVolDesc))
    {
        BISO_PLAT_CloseFile(pstFile);
        return BOOL_FALSE;
    }

    /* 根据ID检验是否是合法的ISO-9660格式 */
    if (0 != strncmp(stVolDesc.szId, BISO_VD_ID, strlen(BISO_VD_ID)))
    {
        BISO_PLAT_CloseFile(pstFile);
        return BOOL_FALSE;
    }

    BISO_PLAT_CloseFile(pstFile);
    return BOOL_TRUE;
}

BOOL_T BISO_HasSVD(IN CONST BISO_READ_S *pstRead)
{
    if (((BISO_PARSER_S *)pstRead)->pstSVD)
    {
        return BOOL_TRUE;
    }

    return BOOL_FALSE;
}

BOOL_T BISO_IsUDFFile(IN CONST CHAR *pcFileName)
{
    UINT uiReadLen;
    UINT64 ui64FileSize = 0;
    BISO_FILE_S *pstFile = NULL;
    BISO_VD_S stVolDesc;

    /* 先看文件大小,过小的文件不可能是ISO文件 */
    ui64FileSize = BISO_PLAT_GetFileSize(pcFileName);
    if (ui64FileSize < BISO_SYSTEM_AREA_SIZE + sizeof(BISO_PVD_S))
    {
        return BOOL_FALSE;
    }

    /* 打开ISO文件 */
    pstFile = BISO_PLAT_OpenExistFile(pcFileName);
    if (NULL == pstFile)
    {
        return BOOL_FALSE;
    }

    /* 标准规定前16个逻辑扇区用来保存系统数据,VD信息从第17个扇区开始 */
    BISO_PLAT_SeekFile(pstFile, BISO_SYSTEM_AREA_SIZE, SEEK_SET);

    do
    {
        /* 每次读取1个VD结构 */
        uiReadLen = (UINT)BISO_PLAT_ReadFile(pstFile, 1, sizeof(stVolDesc), &stVolDesc);
        if (uiReadLen != sizeof(stVolDesc))
        {
            BISO_PLAT_CloseFile(pstFile);
            return BOOL_FALSE;
        }
    } while (BISO_VD_TYPE_END != stVolDesc.ucType);

    /* 根据ID检验是否是合法的UDF格式 */
    (VOID)BISO_PLAT_ReadFile(pstFile, 1, sizeof(stVolDesc), &stVolDesc);
    if (0 != strncmp(stVolDesc.szId, "BEA01", strlen("BEA01")))
    {
        BISO_PLAT_CloseFile(pstFile);
        return BOOL_FALSE;
    }

    /* 根据ID检验是否是合法的UDF格式 */
    (VOID)BISO_PLAT_ReadFile(pstFile, 1, sizeof(stVolDesc), &stVolDesc);
    if (0 != strncmp(stVolDesc.szId, "NSR02", strlen("NSR02")) &&
        0 != strncmp(stVolDesc.szId, "NSR03", strlen("NSR03")))
    {
        BISO_PLAT_CloseFile(pstFile);
        return BOOL_FALSE;
    }

    BISO_PLAT_CloseFile(pstFile);
    return BOOL_TRUE;
}

ULONG BISO_OpenImage(IN CONST CHAR *pcFileName, OUT BISO_READ_S *pstRead)
{
    return BISO_9660_OpenImage(BOOL_FALSE, pcFileName, (BISO_PARSER_S *)pstRead);
}

ULONG BISO_OpenImageWithSVD(IN CONST CHAR *pcFileName, OUT BISO_READ_S *pstRead)
{
    return BISO_9660_OpenImage(BOOL_TRUE, pcFileName, (BISO_PARSER_S *)pstRead);
}

ULONG BISO_GetVolumeSummary
(
    IN CONST BISO_READ_S *pstRead, 
    OUT BISO_VOLUME_SUMMARY_S *pstSummary
)
{
    BISO_PVD_S *pstPVD = NULL;
    BISO_PARSER_S *pstParser = NULL;

    if (NULL == pstRead || NULL == pstSummary)
    {
        return BISO_ERR_NULL_PTR;
    }

    if (BOOL_TRUE != BISO_IS_READ_HANDLE_VALID(pstRead))
    {
        return BISO_ERR_INVALID_PARAM;
    }

    pstParser = (BISO_PARSER_S *)pstRead;
    pstPVD = pstParser->pstPVD;

    /* 拷贝字符串 */
    BISO_UTIL_CopyStr(pstPVD->szVolumeId, sizeof(pstPVD->szVolumeId), pstSummary->szVolumeId);
    BISO_UTIL_CopyStr(pstPVD->szSystemId, sizeof(pstPVD->szSystemId), pstSummary->szSystemId);
    BISO_UTIL_CopyStr(pstPVD->szPublisherId, sizeof(pstPVD->szPublisherId), pstSummary->szPublisherId);
    BISO_UTIL_CopyStr(pstPVD->szPreparerId, sizeof(pstPVD->szPreparerId), pstSummary->szPreparerId);
    BISO_UTIL_CopyStr(pstPVD->szApplicationId, sizeof(pstPVD->szApplicationId), pstSummary->szApplicationId);
    BISO_UTIL_CopyStr(pstPVD->szCopyrightFileId, sizeof(pstPVD->szCopyrightFileId), pstSummary->szCopyrightFileId);
    BISO_UTIL_CopyStr(pstPVD->szAbstractFileId, sizeof(pstPVD->szAbstractFileId), pstSummary->szAbstractFileId);

    /* 其他字段赋值 */
    pstSummary->uiRockRidgeVer = pstParser->ucRRIPVersion;
    pstSummary->uiJolietLevel  = BISO_GetJolietLevel(pstRead);
    pstSummary->uiTotDirNum    = pstParser->stDirTree.pstDirStat->uiTotDirNum;
    pstSummary->uiTotFileNum   = pstParser->stDirTree.pstDirStat->uiTotFileNum;
    pstSummary->uiTotLinkNum   = pstParser->stDirTree.pstDirStat->uiTotLinkNum;

    return BISO_SUCCESS;
}

ULONG BISO_GetDate
(
    IN CONST BISO_READ_S *pstRead, 
    IN  BISO_DATE_TYPE_E enType, 
    OUT BISO_DATE_S *pstDate
)
{
    CONST CHAR *pcDate = NULL;
    BISO_PVD_S *pstPVD = NULL;
    
    if ((NULL == pstRead) || (enType >= BISO_DATE_TYPE_BUTT) || (NULL == pstDate))
    {
        BISO_DIAG("Invalid param %p %d %p.", pstRead, enType, pstDate);
        return BISO_ERR_INVALID_PARAM;
    }

    BISO_CHECK_READ_HANDLE(pstRead);
    pstPVD = ((BISO_PARSER_S *)pstRead)->pstPVD;

    switch (enType)
    {
        case BISO_DATE_TYPE_CREATE:
        {
            pcDate = pstPVD->szCreationDate;
            break;
        }
        case BISO_DATE_TYPE_MODIFY:
        {
            pcDate = pstPVD->szModifyDate;
            break;
        }
        case BISO_DATE_TYPE_EXPIRATION:
        {
            pcDate = pstPVD->szExpirationDate;
            break;
        }
        case BISO_DATE_TYPE_EFFECTIVE:
        {
            pcDate = pstPVD->szEffectiveDate;
            break;
        }
        default :
        {
            return BISO_ERR_INVALID_PARAM;
        }
    }

    return BISO_9660_ParseDate84261(pcDate, pstDate);
}

/* 获取Rock Ridge扩展的Version 0: 没有使用Rock Ridge扩展  具体版本号: 一般都是1 */
UINT BISO_GetRockRidgeVer(IN CONST BISO_READ_S *pstRead)
{  
    if ((NULL == pstRead) || (BOOL_TRUE != BISO_IS_READ_HANDLE_VALID(pstRead)))
    {
        return 0;
    }

    return ((BISO_PARSER_S *)pstRead)->ucRRIPVersion;    
}

/* 获取Joliet扩展的Level */
UINT BISO_GetJolietLevel(IN CONST BISO_READ_S *pstRead)
{    
    BISO_PARSER_S *pstParser = NULL;

    if ((NULL == pstRead) || (BOOL_TRUE != BISO_IS_READ_HANDLE_VALID(pstRead)))
    {
        return 0;
    }
    
    pstParser = (BISO_PARSER_S *)pstRead;
    if (NULL == pstParser->pstSVD)
    {
        return 0;
    }
    return BISO_JOLIET_GetLevel(pstParser->pstSVD->aucEscape);
}

BISO_HANDLE BISO_GetRoot(IN CONST BISO_READ_S *pstRead)
{
    BISO_PARSER_S *pstParser = (BISO_PARSER_S *)pstRead;
    
    if (NULL == pstParser)
    {
        return NULL;
    }
    return (BISO_HANDLE)(&pstParser->stDirTree);
}

ULONG BISO_GetFileNodeByHdl
(
    IN  BISO_HANDLE       hFileHdl, 
    OUT BISO_FILE_NODE_S *pstFileNode
)
{
    BISO_POSIX_INFO_S *pstPosix = NULL;
    BISO_DIR_TREE_S *pstDirTree = (BISO_DIR_TREE_S *)hFileHdl;

    if ((NULL == pstDirTree) || (NULL == pstFileNode))
    {
        return BISO_ERR_NULL_PTR;
    }

    pstPosix = pstDirTree->pstPosixInfo;

    /* 设置类型 */
    BISO_SET_FLAG(pstFileNode, pstDirTree);

    /* 设置名称 */
    scnprintf(pstFileNode->szName, sizeof(pstFileNode->szName), "%s", pstDirTree->szName);

    /* 设置连接路径 */
    if (BOOL_TRUE == BISO_DIR_TREE_IS_SYMLINK(pstDirTree))
    {
        scnprintf(pstFileNode->szLinkTgt, sizeof(pstFileNode->szLinkTgt), "%s", pstPosix->pcLinkSrc);
    }

    pstFileNode->ui64FileSize = pstDirTree->uiSize;
    pstFileNode->ui64Seek = (UINT64)((UINT64)pstDirTree->uiExtent * BISO_BLOCK_SIZE);
    pstFileNode->hParent = (BISO_HANDLE)(pstDirTree->pstParent);
    pstFileNode->hCurrent = hFileHdl;

    return BISO_SUCCESS;
}

ULONG BISO_GetFileNodeByName
(
    IN CONST BISO_READ_S *pstRead,
    IN CONST CHAR *pcFullPath, 
    IN UCHAR ucFollowLink,
    OUT BISO_FILE_NODE_S *pstFileNode
)
{
    UINT i = 0;
    UINT uiDirNum = 0;
    UINT auiDirPos[32];
    USHORT usPos = 0;
    USHORT usLen = 0;
    CHAR szDirName[1024];
    BISO_DIR_TREE_S *pstCurDir = NULL;
    BISO_DIR_TREE_S *pstRootDir = NULL;
    BISO_DIR_TREE_S *pstFileList = NULL;
    BISO_PARSER_S *pstParser = (BISO_PARSER_S *)pstRead;

    if ((NULL == pstRead) || (NULL == pcFullPath) || (NULL == pstFileNode))
    {
        return BISO_ERR_NULL_PTR;
    }

    if ('/' == pcFullPath[0])
    {
        return BISO_ERR_FAILED;
    }

    pstRootDir = &(pstParser->stDirTree);
    pstCurDir = pstRootDir->pstChild;

    if ((0 == pcFullPath[0]) || ((1 == strlen(pcFullPath)) && ('/' == pcFullPath[0])))
    {
        /* 出参赋值 */
        memset(pstFileNode, 0, sizeof(BISO_FILE_NODE_S));        
        BISO_SET_FLAG(pstFileNode, pstCurDir);
        scnprintf(pstFileNode->szName, sizeof(pstFileNode->szName), "%s", pstCurDir->szName);
        pstFileNode->hParent = 0;
        pstFileNode->hCurrent = (BISO_HANDLE)(pstRootDir);
        return BISO_SUCCESS;
    }

    if ((1 == uiDirNum) && (NULL != pstRootDir))
    {
        pstFileList = pstRootDir->pstFileList;
        pstCurDir = pstFileList;
        while (pstCurDir)
        {
            if (0 == BISO_PATH_STRCMP(pstCurDir->szName, pcFullPath))
            {
                goto FOUND;
            }
            pstCurDir = pstCurDir->pstNext;
        }
    }

    /* 先将目录分解开 */
    if (BISO_SUCCESS != BISO_UTIL_PathSplit(pcFullPath, &uiDirNum, auiDirPos))
    {
        BISO_DIAG("Failed to split path %s", pcFullPath);
        return BISO_ERR_FAILED;
    }

    /* 依次查找每一级目录 */
    if (pstRootDir)
    {
        pstCurDir = pstRootDir->pstChild;
    } 
    for (i = 0; (i < uiDirNum) && (NULL != pstRootDir) && (NULL != pstCurDir); i++)
    {
        usPos = auiDirPos[i] >> 16;
        usLen = auiDirPos[i] & 0xFF;

        memcpy(szDirName, pcFullPath + usPos, usLen);
        szDirName[usLen] = 0;

        pstCurDir = pstRootDir->pstChild;
        pstFileList = pstRootDir->pstFileList;

        /* 先查找目录 */
        while (pstCurDir)
        {
            if (0 == BISO_PATH_STRCMP(pstCurDir->szName, szDirName))
            {
                pstRootDir = pstCurDir;
                break;
            }
            pstCurDir = pstCurDir->pstNext;
        }

        /* 再查找文件 */
        if (NULL == pstCurDir)
        {
            pstCurDir = pstFileList;
            while (pstCurDir)
            {
                if (0 == BISO_PATH_STRCMP(pstCurDir->szName, szDirName))
                {
                    break;
                }
                pstCurDir = pstCurDir->pstNext;
            }
        }

        if (NULL == pstCurDir)
        {
            return BISO_ERR_FAILED;
        }

        /* 如果是符号链接则尝试找对应的实际文件 */
        if ((ucFollowLink > 0) && (BOOL_TRUE == BISO_DIR_TREE_IS_SYMLINK(pstCurDir)))
        {
            pstCurDir = BISO_UTIL_FindLinkTgt(pstCurDir);
        }

        /* 如果是文件(或者是非法链接)的话一定是最后一级 */
        if ((NULL == pstCurDir->pstDirStat) && (i + 1 != uiDirNum))
        {
            return BISO_ERR_FAILED;
        }
    }

FOUND:

    if (NULL == pstCurDir)
    {
        return BISO_ERR_FAILED;
    }
    else
    {
        /* 出参赋值 */
        memset(pstFileNode, 0, sizeof(BISO_FILE_NODE_S));        
        BISO_SET_FLAG(pstFileNode, pstCurDir);
        scnprintf(pstFileNode->szName, sizeof(pstFileNode->szName), "%s", pstCurDir->szName);
        if (BOOL_TRUE == BISO_DIR_TREE_IS_SYMLINK(pstCurDir))
        {
            scnprintf(pstFileNode->szLinkTgt, sizeof(pstFileNode->szLinkTgt), "%s", 
                      pstCurDir->pstPosixInfo->pcLinkSrc);
        }
        pstFileNode->ui64FileSize = pstCurDir->uiSize;
        pstFileNode->ui64DirRecOffet = pstCurDir->ui64FileRecordOffset;
        pstFileNode->ui64Seek = (UINT64)((UINT64)pstCurDir->uiExtent * BISO_BLOCK_SIZE);
        pstFileNode->hParent = (BISO_HANDLE)(pstCurDir->pstParent);
        pstFileNode->hCurrent = (BISO_HANDLE)(pstCurDir);
        return BISO_SUCCESS;
    }
}

ULONG BISO_GetFileNodeByExtent
(
    IN CONST BISO_READ_S *pstRead,
    IN UINT uiExtent,
    OUT BISO_FILE_NODE_S *pstFileNode
)
{
    BOOL_T bFind = BOOL_FALSE;
    BISO_QUEUE_S *pstQueue = NULL;
    BISO_DIR_TREE_S *pstRootDir = NULL;
    BISO_DIR_TREE_S *pstDirTree = NULL;
    BISO_DIR_TREE_S *pstCurDir = NULL;
    BISO_DIR_TREE_S *pstFileList = NULL;
    BISO_PARSER_S *pstParser = (BISO_PARSER_S *)pstRead;

    if ((NULL == pstRead) || (NULL == pstFileNode))
    {
        return BISO_ERR_NULL_PTR;
    }

    pstRootDir = &(pstParser->stDirTree);

    /* 创建堆栈,同时ROOT入栈 */
    pstQueue = BISO_QUEUE_Create();
    BISO_QUEUE_Push(pstQueue, pstRootDir);

    while (NULL != (pstDirTree = (BISO_DIR_TREE_S *)BISO_QUEUE_PopHead(pstQueue)))
    {
        pstCurDir = pstDirTree->pstChild;
        while (pstCurDir)
        {
            BISO_QUEUE_Push(pstQueue, pstCurDir);
            pstCurDir = pstCurDir->pstNext;
        }
        
        pstFileList = pstDirTree->pstFileList;
        pstCurDir = pstFileList;
        while (pstCurDir)
        {
            if (uiExtent == pstCurDir->uiExtent)
            {
                while (BISO_QUEUE_PopHead(pstQueue))
                {
                    bFind = BOOL_TRUE;
                }
                break;
            }
            pstCurDir = pstCurDir->pstNext;
        }
    }

    BISO_QUEUE_Destroy(pstQueue);
    if (BOOL_TRUE != bFind)
    {
        return BISO_ERR_FAILED;
    }
    else
    {
        /* 出参赋值 */
        memset(pstFileNode, 0, sizeof(BISO_FILE_NODE_S));        
        BISO_SET_FLAG(pstFileNode, pstCurDir);
        scnprintf(pstFileNode->szName, sizeof(pstFileNode->szName), "%s", pstCurDir->szName);
        if (BOOL_TRUE == BISO_DIR_TREE_IS_SYMLINK(pstCurDir))
        {
            scnprintf(pstFileNode->szLinkTgt, sizeof(pstFileNode->szLinkTgt), "%s", 
                      pstCurDir->pstPosixInfo->pcLinkSrc);
        }
        pstFileNode->ui64FileSize = pstCurDir->uiSize;
        pstFileNode->ui64DirRecOffet = pstCurDir->ui64FileRecordOffset;
        pstFileNode->ui64Seek = (UINT64)((UINT64)pstCurDir->uiExtent * BISO_BLOCK_SIZE);
        pstFileNode->hParent = (BISO_HANDLE)(pstCurDir->pstParent);
        pstFileNode->hCurrent = (BISO_HANDLE)(pstCurDir);
        return BISO_SUCCESS;
    }
}


ULONG BISO_GetSVDFileNodeByExtent
(
    IN CONST BISO_READ_S *pstRead,
    IN UINT uiExtent,
    OUT BISO_SVD_FILE_NODE_S *pstFileNode
)
{
    BOOL_T bFind = BOOL_FALSE;
    BISO_QUEUE_S *pstQueue = NULL;
    BISO_SVD_DIR_TREE_S *pstRootDir = NULL;
    BISO_SVD_DIR_TREE_S *pstDirTree = NULL;
    BISO_SVD_DIR_TREE_S *pstCurDir = NULL;
    BISO_SVD_DIR_TREE_S *pstFileList = NULL;
    BISO_PARSER_S *pstParser = (BISO_PARSER_S *)pstRead;

    if ((NULL == pstRead) || (NULL == pstFileNode))
    {
        return BISO_ERR_NULL_PTR;
    }

    pstRootDir = &(pstParser->stSVDDirTree);

    /* 创建堆栈,同时ROOT入栈 */
    pstQueue = BISO_QUEUE_Create();
    BISO_QUEUE_Push(pstQueue, pstRootDir);

    while (NULL != (pstDirTree = (BISO_SVD_DIR_TREE_S *)BISO_QUEUE_PopHead(pstQueue)))
    {
        pstCurDir = pstDirTree->pstChild;
        while (pstCurDir)
        {
            BISO_QUEUE_Push(pstQueue, pstCurDir);
            pstCurDir = pstCurDir->pstNext;
        }
        
        pstFileList = pstDirTree->pstFileList;
        pstCurDir = pstFileList;
        while (pstCurDir)
        {
            if (uiExtent == pstCurDir->uiExtent)
            {
                while (BISO_QUEUE_PopHead(pstQueue))
                {
                    bFind = BOOL_TRUE;
                }
                break;
            }
            pstCurDir = pstCurDir->pstNext;
        }
    }

    BISO_QUEUE_Destroy(pstQueue);
    if (BOOL_TRUE != bFind)
    {
        return BISO_ERR_FAILED;
    }
    else
    {
        /* 出参赋值 */
        memset(pstFileNode, 0, sizeof(BISO_SVD_FILE_NODE_S));        
        pstFileNode->ui64FileSize = pstCurDir->uiSize;
        pstFileNode->ui64DirRecOffet = pstCurDir->ui64FileRecordOffset;
        pstFileNode->ui64Seek = (UINT64)((UINT64)pstCurDir->uiExtent * BISO_BLOCK_SIZE);
        return BISO_SUCCESS;
    }
}

ULONG BISO_GetFileTree
(
    IN  BISO_HANDLE  hTopDir, 
    IN  UINT         uiFlag,
    OUT BISO_HANDLE *phFileTree,
    OUT UINT        *puiNodeNum
)
{    
    BISO_DIR_STAT_S *pstDirStat = NULL;
    BISO_DIR_TREE_S *pstCurNode = NULL;
    BISO_DIR_TREE_S *pstDirTree = (BISO_DIR_TREE_S *)hTopDir;
    
    if ((NULL == pstDirTree) || (NULL == phFileTree) || (NULL == puiNodeNum))
    {
        return BISO_ERR_NULL_PTR;
    }

    pstDirStat = pstDirTree->pstDirStat;
    if (NULL == pstDirStat)
    {
        return BISO_ERR_INVALID_PARAM;
    }

    *puiNodeNum = pstDirStat->uiCurDirNum + pstDirStat->uiCurFileNum + pstDirStat->uiCurLinkNum;

    switch (uiFlag)
    {
        case BISO_TREE_FLAG_CUR:
        {
            pstCurNode = pstDirTree->pstChild;
            
            while (NULL != pstCurNode)
            {
                *phFileTree++ = (BISO_HANDLE)pstCurNode;
                pstCurNode = pstCurNode->pstNext;
            }

            pstCurNode = pstDirTree->pstFileList;
            while (NULL != pstCurNode)
            {
                *phFileTree++ = (BISO_HANDLE)pstCurNode;
                pstCurNode = pstCurNode->pstNext;
            }
            
            break;
        }
        case BISO_TREE_FLAG_DFS:
        {
            break;
        }
        case BISO_TREE_FLAG_BFS:
        {
            break;
        }
        default :
        {
            return BISO_ERR_INVALID_PARAM;
        }
    }

    return BISO_SUCCESS;
}

ULONG BISO_GetDirStat
(
    IN  BISO_HANDLE      hTopDir, 
    OUT BISO_DIR_STAT_S *pstDirStat
)
{
    BISO_DIR_TREE_S *pstDirTree = NULL;
    
    if ((NULL == hTopDir) || (NULL == pstDirStat))
    {
        return BISO_ERR_NULL_PTR;
    }

    pstDirTree = (BISO_DIR_TREE_S *)hTopDir;
    if (NULL == pstDirTree->pstDirStat)
    {
        return BISO_ERR_INVALID_PARAM;
    }
    
    memcpy(pstDirStat, pstDirTree->pstDirStat, sizeof(BISO_DIR_STAT_S));
    return BISO_SUCCESS;
}


VOID BISO_Fill733(IN UINT uiData, OUT VOID *pBuf)
{
    UINT uiSwap = 0;
    UINT *puiData = (UINT *)pBuf;

    uiSwap |= (uiData & 0xFF) << 24;
    uiSwap |= ((uiData >> 8) & 0xFF) << 16;
    uiSwap |= ((uiData >> 16) & 0xFF) << 8;
    uiSwap |= (uiData >> 24) & 0xFF;

#if (__BYTE_ORDER == __LITTLE_ENDIAN)
    puiData[0] = uiData;
    puiData[1] = uiSwap;
#else
    puiData[0] = uiSwap;
    puiData[1] = uiData;
#endif    
}

UINT BISO_Get733(IN CONST VOID *pBuf)
{
    UINT *puiData = (UINT *)pBuf;
    
#if (__BYTE_ORDER == __LITTLE_ENDIAN)
    return puiData[0];
#else
    return puiData[1];
#endif  
}

UINT BISO_GetFileOccupySize(IN UINT uiRawSize)
{
    UINT uiAlign = uiRawSize % BISO_SECTOR_SIZE;
    
    if (0 == uiAlign)
    {
        return uiRawSize;
    }
    else
    {
        return uiRawSize + BISO_SECTOR_SIZE - uiAlign;
    }
}

UINT BISO_GetBootEntryNum(IN CONST BISO_READ_S *pstRead)
{
    return BISO_ELTORITO_GetBootEntryNum((CONST BISO_PARSER_S *)pstRead);
}

VOID BISO_DumpFileTree(IN CONST BISO_READ_S *pstRead)
{
    BISO_PARSER_S *pstParser = (BISO_PARSER_S *)pstRead;

    if (NULL != pstParser)
    {
        BISO_DUMP_ShowFileTree(1, pstParser->stDirTree.pstChild);
        BISO_DUMP_ShowFileTree(1, pstParser->stDirTree.pstFileList);
    }
}