//*****************************************************************************
// ListUpAllSubDir.cpp : 指定パス内の指定ディレクトリをサブディレクトリも含めて
//                       全てリストアップする(複数パス指定は不可)
//*****************************************************************************
#include "stdafx.h"

int ListUpAllSubDir( char* ppath , char*bufp , int bufsize ) ;
CString ExcludeQuot( CString& ostr ) ;
static char* GetNextPointerForSubDir( char* cp , int ccount ) ;
int ListUpSubDir( char* ppath , char*bufp , int bufsize ) ;
int GetTheSubDirFirst( char* ppath , char* psubdirpath ) ;
int GetTheSubDirNext( char* psubdirpath ) ;
void GetTheSubDirLast( ) ;
static int GetErrorCode( ) ;
void AddQuotForSpace( char* buf , int bPreLast=FALSE ) ;


//*****************************************************************************
// 機能 : 指定のパス下のサブディレクトリをそのネストも含めて全てリストアップする(全段対応)。
//  入力 :  ppath = 絶対パス名("x:\xxx\xxx\*.*"形式)
//            bufp = サブディレクトリの絶対パス名を格納する領域へのポインタ
//            bufsize = bufpのサイズ(INT_MAX以下であること)
//  戻り値: サブディレクトリの個数、-1の時はバッファオーバー。
//  注意 : bufpへの格納形式は次の通り。
//              x:\xxx\xxx\(NULL)  : データの最後は\で次がNULL
//              ----------------
//*****************************************************************************
int ListUpAllSubDir( char* ppath , char*bufp , int bufsize )
{
    int i ;
    int count ;
    int len ;
    char* nextbufp ;
    char* nextnamep ;
    int restsize ;
    int tcount ;

    ASSERT( bufsize <= INT_MAX && bufsize >= _MAX_PATH+1 ) ;

    CString wkstr = (const char*)ppath ;
    CString realpath = ExcludeQuot( wkstr ) ;

    count = ListUpSubDir( (char*)(const char*)realpath , bufp , bufsize ) ;

    if ( count == -1 || count == 0 )
        return count ;

    nextbufp = GetNextPointerForSubDir( bufp , count ) ;
    restsize = bufsize - (int)(nextbufp-bufp) ;
    tcount = count ;
    nextnamep = bufp ;

    for ( i = 0 ; i < tcount ; i++ )
    {
        len = strlen( (const char*)nextnamep ) ;

        CString wkstr = (const char*)nextnamep ;
        CString realpath = ExcludeQuot( wkstr ) ;
        realpath += "*.*" ;

        nextnamep += len ;
        nextnamep++ ;               // NULLの分

        count = ListUpSubDir( (char*)(const char*)realpath , nextbufp , restsize ) ;
        if ( count == -1 )
            return -1 ;                 //<-----------------------エラー処理!!!!!
        if ( count > 0 )
        {       
            nextbufp = GetNextPointerForSubDir( nextbufp , count ) ;
            restsize = bufsize - (int)(nextbufp-bufp) ;
            tcount += count ;
        }
    }
    return tcount ;
}



//******************************************************************************
// 機能 :指定の文字列から「"」を取り除いたものを戻す。
//  注意  :ostrのサイズは_MAX_PATH以下であること!!!
//******************************************************************************
CString ExcludeQuot( CString& ostr )
{
    if ( ostr.Find( '\"' ) == -1 )
        return ostr ;

    int len = ostr.GetLength( ) ;
    
    if ( len > _MAX_PATH )
    {
        ASSERT( FALSE ) ;
        return ostr ;

    }

    BYTE buf[_MAX_PATH+1+10] ;          // 10:余裕分

    int i ;
    int k ;
    for ( i = 0 , k = 0 ; i < len ; i++ )
    {
        BYTE bt = (BYTE)ostr[i] ;
        if ( bt == '\"' )
            continue ;

        buf[k] = bt ;
        k++ ;

    }

    buf[k] = 0 ;            // set NULL!!!

    CString tstr = (const char*)buf ;

    return tstr ;

}


//*****************************************************************************
// 機能 : 指定の現在の位置と個数から次にサブディレクトリを格納すべき位置を求める。
//*****************************************************************************
static char* GetNextPointerForSubDir( char* cp , int ccount )
{
    int i ;

    char* nextp = cp ;
    for ( i = 0 ; i < ccount ; i++ )
    {
        nextp = strchr( (const char*)nextp , '\0' ) ;
        ASSERT( nextp != NULL ) ;
        nextp++ ;
    }
    return nextp ;
}


//*****************************************************************************
// 機能 : 指定のパス下のサブディレクトリを全てリストアップする(ただし1段のみ)。
//  入力 :  ppath = 絶対パス名("x:\xxx\xxx\*.*"形式)
//            bufp = サブディレクトリの絶対パス名を格納する領域へのポインタ
//            bufsize = bufpのサイズ(INT_MAX以下であること)
//  戻り値: サブディレクトリの個数、-1の時はバッファオーバー。
//  注意 : bufpへの格納形式は次の通り。
//              x:\xxx\xxx\(NULL)  : データの最後は\で次がNULL
//              ----------------
//*****************************************************************************
int ListUpSubDir( char* ppath , char*bufp , int bufsize )
{
    int i ;
    int count ;
    int len ;

    ASSERT( bufsize <= INT_MAX && bufsize >= _MAX_PATH+1 ) ;

    if ( GetTheSubDirFirst( ppath , bufp ) != 0 )
        return 0 ;


    for ( i = 0 , count = 0 ; ; )
    {
        len = strlen( (const char*)&bufp[i] ) ;
        if ( len >= 3 && bufp[len-2] == '.' && bufp[len-3] == '\\' )
        {
            NULL ;              // 自分自身は除く
        }
        else if ( len >= 4 && bufp[len-2] == '\"' && bufp[len-3] == '.' && bufp[len-4] == '\\' )
        {
            NULL ;              // 自分自身は除く
        }
        else if ( len >= 4 && bufp[len-2] == '.' && bufp[len-3] == '.' && bufp[len-4] == '\\' )
        {
            NULL ;              // 自分の親の除く
        }
        else if ( len >= 5 && bufp[len-2] == '\"' && bufp[len-3] == '.' && bufp[len-4] == '.' && bufp[len-5] == '\\' )
        {
            NULL ;              // 自分の親の除く
        }
        else
        {
            i += len+1 ;
            count++ ;
        }
        
        if ( i >= bufsize-(_MAX_PATH+1) )
        {
            GetTheSubDirLast( ) ;
            break ;
        }
        if ( GetTheSubDirNext( &bufp[i] ) != 0)
            break ;
    }

    if ( i >= bufsize-(_MAX_PATH+1) )
        return -1 ;
    else
        return count ;
}


WIN32_FIND_DATA ffindt ;
HANDLE hffind ;

static char ppathsave[_MAX_PATH+1] ;
//*****************************************************************************
// 機能 : 指定のパスの最初のサブディレクトリを見つけて戻す。
//  入力 : ppath = 絶対パス("x:\xxx\xxx\*.*"形式であること)
//            psubdirpath = (見つかればここに、"x:\xxx\xxx\yyy\"形式で戻る)
//  戻り値: 0:OK , 1:ない , 2:エラー発生
//*****************************************************************************
int GetTheSubDirFirst( char* ppath , char* psubdirpath )
{
    int len = strlen( (const char*)ppath ) ;

    ASSERT( len > 3 && strcmp( (const char*)&ppath[len-3] , "*.*" ) == 0 ) ;

    strcpy( ppathsave , (const char*)ppath ) ;

    hffind = FindFirstFile( ppathsave , &ffindt ) ;

    if ( hffind == INVALID_HANDLE_VALUE )
        return GetErrorCode( ) ;

    for ( ; ; )
    {
        if ( ffindt.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            break ;

        if ( !FindNextFile( hffind , &ffindt ) )
        {
            FindClose( hffind ) ;
            return GetErrorCode( ) ;
        }

    }

    strncpy( psubdirpath , ppath , len-3 ) ;
    strcpy( &psubdirpath[len-3] , ffindt.cFileName ) ;
    AddQuotForSpace( psubdirpath ) ;
    
    len = strlen( psubdirpath ) ;
    psubdirpath[len] = '\\' ;
    psubdirpath[len+1] = 0 ;
    return 0 ;
}

                
//*****************************************************************************
// 機能 : 指定のパスの次のサブディレクトリを見つけて戻す。
//  入力 : psubdirpath = (見つかればここに、"x:\xxx\xxx\yyy\"形式で戻る)
//  戻り値: 0:OK , 1:ない , 2:エラー発生
//  注意 : GetTheSubDirFirstを事前に呼び、成功していること。
//*****************************************************************************
int GetTheSubDirNext( char* psubdirpath )
{
    int len = strlen( (const char*)ppathsave ) ;

    if ( !FindNextFile( hffind , &ffindt ) )
    {
        FindClose( hffind ) ;
        return GetErrorCode( ) ;
    }

    for ( ; ; )
    {
        if ( ffindt.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
            break ;

        if ( !FindNextFile( hffind , &ffindt ) )
        {
            FindClose( hffind ) ;
            return GetErrorCode( ) ;
        }

    }

    strncpy( psubdirpath , ppathsave , len-3 ) ;
    strcpy( &psubdirpath[len-3] , ffindt.cFileName ) ;
    AddQuotForSpace( psubdirpath ) ;

    len = strlen( psubdirpath ) ;
    psubdirpath[len] = '\\' ;
    psubdirpath[len+1] = 0 ;
    return 0 ;
}


//*****************************************************************************
// 機能 : hffindの解放
//*****************************************************************************
void GetTheSubDirLast( )
{
    FindClose( hffind ) ;
}


//*****************************************************************************
// 機能 :単に1を戻すだけ、for debug 
//*****************************************************************************
static int GetErrorCode( )
{
    DWORD errord = GetLastError( ) ;
    return 1 ;

}

//*****************************************************************************
// 機能 :指定のバッファ中に半角空白があった場合、その文字列全体を" "で囲む。
//  注意  :バッファは""を加えても、十分な大きさがあること。
//          bufの文字列の最後はNULLであること。
//          bPreLastがTRUEの時は、最後の文字の(半角前提!!!)の前に、"を付ける
//              (例)x:\x xx\xxx\ ---> "x:\x xx\xxx"\
//*****************************************************************************
void AddQuotForSpace( char* buf , int bPreLast )
{
    int len = strlen( (const char*)buf ) ;
    if ( len == 0 )
        return ;

    if ( strchr( (const char*)buf , 0x20 ) == NULL )
        return ;

    CString wkstr = "\"" ;
    wkstr += (const char*)buf ;
    if ( bPreLast )
    {
        len = wkstr.GetLength( ) ;
        CString prestr = wkstr.Left( len-1 ) ;
        prestr += "\"" ;
        prestr += wkstr.Right( 1 ) ;
        wkstr = prestr ;

    }
    else
    {
        wkstr += "\"" ;
        
    }

    strcpy( buf , (const char*)wkstr ) ;

}

//*****************************************************************************
// ListUpAllSubDir.cpp : Ver1.00  2006/12/26
// Example : int count = ListUpAllSubDir( "d:\\wk\\*.*" , pc , 1024*500 ) ;
//
// Copyright(C) Edcom Inc. (http://www.edcom.jp/) All rights reserved. 
//*****************************************************************************