//*****************************************************************************
// ReadTheFileEx.cpp : ファイル読み込み関数各種
//*****************************************************************************

#include "stdafx.h"

#define CR                      0x0D

BYTE* W_ReadTheFileEx( const char* pszPathName , DWORD allowedlen , DWORD* pdlen , int bAppendNULL=FALSE , int bValidNotFound=FALSE ) ;
BYTE* W_ReadTheFileSx( const char* pszPathName , DWORD allowedlen , DWORD* pdlen , DWORD* pfilelen , int bAppendNULL=FALSE , int bValidNotFound=FALSE ) ;
int W_ReadTheFileLimited( const char* pszPathName , BYTE* wbuf , int blen ) ;
int W_ReadTheFileArea( const char* pszPathName , int spos , int rlen , BYTE* wbuf ) ;
int GetLineStrFromFile( CString& path , CString* plstr , int lcount , int allowedlen ) ;

BYTE* W_GetUserBuf( int buflen ) ;
int GetBufLineStrMulti( BYTE* bbuf , int blen , CString* plstr , int lineno , int linecount ) ;
CString MakeStr( BYTE* buf , int blen ) ;

static const char szMemoryInsufficient[] = "メモリ不足です。" ;

//*****************************************************************************
// 機能 :指定パスのファイルからデータを読み込み、読み込んだバッファのポインタを戻す。
//  入力  :allowedlen=許される最大の長さ(ファイルの長さがこれを越えている場合は、NULLで戻る)
//          bAppendNULLがTRUEの時は、最後にNULLを付加して戻る。
//  戻り値:読み込んだデータのバッファのポインタ
//          NULLの時はエラーを意味する。 
//          *pdlen=読み込んだファイルのデータ長
//  注意  :バッファの解放は呼ぶ側で行なう。
//          バッファはファイルのデータ長+10(10:余裕分)確保される!!!
//              従って、*pdlen バイト目にNULL等を設定することも可能!!!
//*****************************************************************************
BYTE* W_ReadTheFileEx( const char* pszPathName , DWORD allowedlen , DWORD* pdlen , int bAppendNULL , int bValidNotFound )
{

    CFile file;
    CFileException fe;
    DWORD dlen ;

    if (!file.Open(pszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe))
    {
        if ( bValidNotFound && fe.m_cause == CFileException::fileNotFound )
        {
            BYTE* wbuf = W_GetUserBuf( 10 ) ;
            if ( wbuf != NULL )
                wbuf[0] = 0 ;           // set NULL 

            *pdlen = 0 ;
            return wbuf ;

        }

        return NULL ;

    }

    TRY
    {
        dlen = file.GetLength( ) ;
    }
    CATCH( CFileException , e )
    {
        file.Close( ) ;
        return NULL ;       
    }
    END_CATCH

    if ( dlen > allowedlen )
    {
        ASSERT( FALSE ) ;

        file.Close( ) ;
        return NULL ;
    }

    BYTE* wbuf = W_GetUserBuf( dlen+10 ) ;
    if ( wbuf == NULL )
    {
        AfxMessageBox( szMemoryInsufficient ) ;
        file.Close( ) ;
        return NULL ;
    }

    TRY
    {
        DWORD drbytes = file.Read( (void FAR*)wbuf , dlen+5 ) ;
        ASSERT( drbytes == dlen ) ;
        file.Close( ) ;
    }
    CATCH( CFileException , e )
    {
        file.Close( ) ;
        delete wbuf ;

        return NULL ;       
    }
    END_CATCH

    *pdlen = dlen ;

    if ( bAppendNULL )
        wbuf[dlen] = 0 ;            // Set NULL!!!

    return wbuf ;

}


//*****************************************************************************
// 機能 :指定パスのファイルからデータを読み込み、読み込んだバッファのポインタを戻す。
//  入力  :allowedlen=許される最大の長さ(ファイルの長さがこれを越えている場合は、NULLで戻る)
//          bAppendNULLがTRUEの時は、最後にNULLを付加して戻る。
//  戻り値:読み込んだデータのバッファのポインタ
//          NULLの時はエラーを意味する。 
//          *pdlen=読み込んだファイルのデータ長
//  注意  :バッファの解放は呼ぶ側で行なう。
//          バッファはファイルのデータ長+10(10:余裕分)確保される!!!
//              従って、*pdlen バイト目にNULL等を設定することも可能!!!
//
//          W_ReadTheFileEx とは、次の点が異なる!!!
//              ・allowedlenを越えている場合は、allowedlenまでのサイズを読み込んで戻す!!!
//              ・ファイルサイズを、*pfilelenに戻す!!!
//*****************************************************************************
BYTE* W_ReadTheFileSx( const char* pszPathName , DWORD allowedlen , DWORD* pdlen , DWORD* pfilelen , int bAppendNULL , int bValidNotFound )
{
    *pfilelen = 0 ;

    CFile file;
    CFileException fe;
    DWORD dlen ;

    if (!file.Open(pszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe))
    {
        if ( bValidNotFound && fe.m_cause == CFileException::fileNotFound )
        {
            BYTE* wbuf = W_GetUserBuf( 10 ) ;
            if ( wbuf != NULL )
                wbuf[0] = 0 ;           // set NULL 

            *pdlen = 0 ;
            return wbuf ;

        }

        return NULL ;

    }

    TRY
    {
        dlen = file.GetLength( ) ;
    }
    CATCH( CFileException , e )
    {
        file.Close( ) ;
        return NULL ;       
    }
    END_CATCH

    DWORD lentoberead ;
    if ( dlen > allowedlen )
        lentoberead = allowedlen ;
    else
        lentoberead = dlen ;

    BYTE* wbuf = W_GetUserBuf( lentoberead+10 ) ;
    if ( wbuf == NULL )
    {
        AfxMessageBox( szMemoryInsufficient ) ;
        file.Close( ) ;
        return NULL ;
    }

    TRY
    {
        DWORD drbytes = file.Read( (void FAR*)wbuf , lentoberead ) ;
        ASSERT( drbytes == lentoberead ) ;
        file.Close( ) ;
    }
    CATCH( CFileException , e )
    {
        file.Close( ) ;
        delete wbuf ;

        return NULL ;       
    }
    END_CATCH

    *pdlen = lentoberead ;
    *pfilelen = dlen ; 

    if ( bAppendNULL )
        wbuf[lentoberead] = 0 ;         // Set NULL!!!

    return wbuf ;

}


//*****************************************************************************
// 機能 :指定パスのファイルからデータを指定バッファに読み込む。
//  入力  :blen=バッファの長さ
//  戻り値:読み込んだデータの長さ
//  注意  :エラー発生時は0を戻す(サイズ0の場合との区別は無し)
//          ファイルサイズがblenを越えている場合には、blen分のみ読み込む!!!
//          (この点はW_ReadTheFileExと違う)
//*****************************************************************************
int W_ReadTheFileLimited( const char* pszPathName , BYTE* wbuf , int blen )
{

    CFile file;
    CFileException fe;

    if (!file.Open(pszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe))
    {
        return 0 ;
    }

    UINT rbytes ;
    TRY
    {
        rbytes = file.Read( (void FAR*)wbuf , blen ) ;
        file.Close( ) ;
    }
    CATCH( CFileException , e )
    {
        file.Close( ) ;
        return 0 ;      
    }
    END_CATCH

    return (int)rbytes ;

}



//*****************************************************************************
// 機能 :指定パスファイル指定位置から指定サイズ分のデータを指定バッファに読み込む。
//  入力  :
//  戻り値:読み込んだデータの長さ
//  注意  :エラー発生時は0を戻す(サイズ0の場合との区別は無し)
//          wbufはrlen以上あること!!!
//*****************************************************************************
int W_ReadTheFileArea( const char* pszPathName , int spos , int rlen , BYTE* wbuf )
{

    CFile file;
    CFileException fe;

    if (!file.Open(pszPathName, CFile::modeRead | CFile::shareDenyWrite, &fe))
    {
        return 0 ;
    }

    UINT rbytes ;
    TRY
    {
        DWORD dlen = file.GetLength( ) ;
        if ( spos >= (int)dlen )
        {
            file.Close( ) ;
            return 0 ;

        }

        file.Seek( (LONG)spos , CFile::begin ) ;

        rbytes = file.Read( (void FAR*)wbuf , rlen ) ;
        file.Close( ) ;

    }
    CATCH( CFileException , e )
    {
        file.Close( ) ;
        return 0 ;      
    }
    END_CATCH

    return (int)rbytes ;

}


//*****************************************************************************
// 機能 :指定のpathから、指定行数分のデータを読みこみ戻す
//  戻り値:設定した個数
//  注意  :ファイルサイズがallowedlenを越えている場合は、0で戻る!!!
//          戻り値に関わらず、plstr[]は、emptyにされて戻る!!!
//          ファイルの内容は文字データであることが前提
//*****************************************************************************
int GetLineStrFromFile( CString& path , CString* plstr , int lcount , int allowedlen )
{
    if ( lcount == 0 )
        return 0 ;

    int i ;
    for ( i = 0 ; i < lcount ; i++ )
        plstr[i] = "" ;

    if ( allowedlen <= 0 )
        return 0 ;

    int rlen ;
    BYTE* buf = W_ReadTheFileEx( (const char*)path , allowedlen , (DWORD*)(&rlen) ) ;

    if ( buf == NULL )
        return 0 ;          // ファイルが存在しない場合も含む!!!

                            // bufの解放を忘れるな!!!

    if ( rlen == 0 )
    {
        delete buf ;        // bufの解放を忘れるな!!!
        return 0 ;

    }

    int gcount = GetBufLineStrMulti( buf , rlen , plstr , 0 , lcount ) ;

    if ( gcount > lcount )
    {
        ASSERT( FALSE ) ;
        gcount = lcount ;

    }
    
    delete buf ;            // bufの解放を忘れるな!!!

    for ( i = 0 ; i < gcount ; i++ )
    {
        CString wstr = plstr[i] ;

        int k ;
        for ( k = 0 ; k < wstr.GetLength( ) ; k++ )
        {
            if ( ((BYTE)wstr[k]) < 0x20 )
                wstr.SetAt( k , 0x20 ) ;

        }

        plstr[i] = wstr ;

    }

    return gcount ;


}

//*****************************************************************************
//  機能  :指定サイズのバッファを確保して戻す。
//  戻り値:NULLの時は、確保できなかったことを意味する。
//  注意  :バッファの解放は呼ぶ側で行なうこと。
//*****************************************************************************
BYTE* W_GetUserBuf( int buflen )
{

    BYTE* wbuf ;

    TRY
    {
        wbuf = new BYTE[buflen] ;
    }
    CATCH( CMemoryException , e )
    {
        AfxMessageBox( szMemoryInsufficient ) ;
        return NULL ;

    }
    END_CATCH

    return wbuf ;

}


//*****************************************************************************
// 機能 :指定の文字列バッファ内の指定の行から指定行数分の行文字列を戻す。
//  入力  :lineno : 0から
//  戻り値:設定した行数、plstr[] = 行文字列(CRLFは含まない)
//  注意  :plstr[]の要素はlinecount以上あること
//          改行はCRLF前提
//*****************************************************************************
int GetBufLineStrMulti( BYTE* bbuf , int blen , CString* plstr , int lineno , int linecount )
{
    int i ;
    for ( i = 0 ; i < linecount ; i++ )
        plstr[i] = "" ;                     // まず、各要素をEmptyにする

    CString lstr = "" ;
    
    if ( blen == 0 )
        return 0 ;

    int crcount = 0 ;

    int spos ;
    if ( lineno == 0 )
        spos = 0 ;
    else
    {

        for ( i = 0 ; i < blen ; i++ )
        {
            if ( bbuf[i] == CR )
                crcount++ ;

            if ( crcount == lineno )
                break ;

        }

        if ( i == blen )
            return 0 ;

        spos = i + 2 ;      // 2:CRLF分

    }

    if ( spos >= blen )
        return 0 ;


    int k ;
    for ( k = 0 ; k < linecount && spos < blen ; )
    {
        for ( i = spos ; i < blen ; i++ )
        {
            if ( bbuf[i] == CR )
                break ;
        }

        int npos = i ;

        if ( npos <= spos )
            plstr[k] = "" ;
        else
            plstr[k] = MakeStr( &bbuf[spos] , npos-spos ) ;

        k++ ;
        spos = npos+2 ;     // CRLFの分

    }

    return k ;

}

//***************************************************************************
//  機能 :指定バッファの指定文字数(バイト数)を CString形式で戻す。
//***************************************************************************
CString MakeStr( BYTE* buf , int blen )
{
    CString tstr( (const char*)buf , blen ) ;

    return tstr ;

}


//*****************************************************************************
// ReadTheFileEx.cpp : Ver1.00  2007/01/03
// Example :
//  CString path = "d:\\example\\example.exe" ;
//  DWORD allowedlen = 1024*1024*10 ; 
//  DWORD blen ;
//  BYTE* buf = W_ReadTheFileEx( (const char*)path , allowedlen , &blen ) ; // 解放を忘れるな!!!
//  if ( buf == NULL )
//  {
//      AfxMessageBox( "Error" ) ;
//      return ;
//
//  }
//  delete buf ;
//
//  allowedlen = 1024*1024 ;
//  DWORD flen ;
//  buf = W_ReadTheFileSx( (const char*)path , allowedlen , &blen , &flen ) ;
//  if ( buf == NULL )
//  {
//      AfxMessageBox( "Error" ) ;
//      return ;
//
//  }
//  delete buf ;
//
//  BYTE wbuf[1024+10] ; 
//  int rlen = W_ReadTheFileLimited( (const char*)path , &wbuf[0] , 1024 ) ;
//
//  int spos = 100 ;
//  int glen = 1024 ;
//  rlen = W_ReadTheFileArea( (const char*)path , spos , glen , &wbuf[0] ) ;
//
//  path = "d:\\example\\example.txt" ;
//  int lcount = 100 ;
//  CString* plstr = new CString[lcount] ;
//  allowedlen = 1024*1024*10 ;
//  int gcount = GetLineStrFromFile( path , plstr , lcount , allowedlen ) ;
//  delete [] plstr ;
//
// Copyright(C) Edcom Inc. (http://www.edcom.jp/) All rights reserved. 
//*****************************************************************************