Files
2026-06-01 12:46:52 +02:00

339 lines
10 KiB
C++

//
// File: nfl.h
//
// Contents: wrapper of iconv unicode library and some other utility
//
// Functions: bool nfl::dir( *vector, path, wildcard, dir_flag )
// vector nfl::dir( path, wildcard, dir_flag )
// bool nfl::dir( *vector, wildcard, dir_flag )
// vector nfl::dir( wildcard, dir_flag )
// size_t nfl::file_size( filename )
// bool nfl::is_exist( filename )
// bool nfl::is_file( filename )
// bool nfl::is_directory( filename )
// bool nfl::readfile( *container, path )
// bool nfl::textfile( *vector, path )
// bool nfl::textfile( *str, path )
// str nfl::textfile( path )
// str nfl::checksum( *data, size )
// str nfl::checksum( path )
//
// Author: Kang, KiHyun ( testors@nflavor.com )
//
#pragma once
#include "nsl.h"
#include <string>
#include <vector>
#include <io.h>
#include <wchar.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
namespace nl
{
namespace file
{
enum
{
DEFAULT_IO_SIZE = 65535,
};
namespace path { using namespace nsl::path; };
enum dir_flag
{
DOT_DIRECTORY = 0x01, // . , ..
SUB_DIRECTORY = 0x02,
FILE = 0x04,
RECURSIVE = 0x08,
DIRECTORY = ( DOT_DIRECTORY | SUB_DIRECTORY ),
DEFAULT = ( SUB_DIRECTORY | FILE ),
ALL = ( DIRECTORY | FILE ),
};
template< typename _Elem > struct fs_api {};
template<>
struct fs_api< char >
{
typedef _finddata_t find_data;
static const char* wildcard_all() { return "*"; }
static ::FILE* fopen( const char* fn, const char* mode )
{
::FILE* fp = NULL;
::fopen_s( &fp, fn, mode );
return fp;
}
static int open( const char *fn, int of, int pm )
{
int fh = 0;
_sopen_s( &fh, fn, of, _SH_DENYWR, pm );
return fh;
}
static int stat( const char *path, struct _stat * buf ) { return _stat( path, buf ); }
static intptr_t findfirst( const char *f, find_data * p ) { return _findfirst( f, p ); }
static intptr_t findnext( intptr_t h, find_data * p ) { return _findnext( h, p ); }
};
template<>
struct fs_api< wchar_t >
{
typedef _wfinddata_t find_data;
static const wchar_t* wildcard_all() { return L"*"; }
static ::FILE* fopen( const wchar_t* fn, const wchar_t* mode )
{
::FILE* fp = NULL;
_wfopen_s( &fp, fn, mode );
return fp;
}
static int open( const wchar_t *fn, int of, int pm )
{
int fh = 0;
_wsopen_s( &fh, fn, of, _SH_DENYWR, pm );
return fh;
}
static int stat( const wchar_t *path, struct _stat * buf ) { return _wstat( path, buf ); }
static intptr_t findfirst( const wchar_t *f, find_data * p ) { return _wfindfirst( f, p ); }
static intptr_t findnext( intptr_t h, find_data * p ) { return _wfindnext( h, p ); }
};
struct file
{
file() : fp( 0 ), ref_count( 0 ) {}
file( const char* fn, const char* mode ) { fp = fs_api< char >::fopen( fn, mode ); ref_count = new int(1); }
file( const wchar_t* fn, const wchar_t* mode ) { fp = fs_api< wchar_t >::fopen( fn, mode ); ref_count = new int(1); }
file( ::FILE* f, bool bAutoRelease = false ) { fp = f; if( bAutoRelease ) ref_count = new int(1); else ref_count = 0; }
file( const file & rh ) { copy_from( rh ); }
size_t write( const void* buf, size_t size, size_t count ) { return fwrite( buf, size, count, fp ); }
size_t write( const void* buf, size_t size ) { return fwrite( buf, size, 1, fp ); }
size_t read( void* buf, size_t size, size_t count ) { return fread( buf, size, count, fp ); }
size_t read( void* buf, size_t size ) { return fread( buf, size, 1, fp ); }
file & operator<<( const char* str ) { write( str, nsl::strlen< char >( str ) ); return *this; }
file & operator<<( const wchar_t* str ) { write( str, nsl::strlen< wchar_t >( str ) * sizeof( wchar_t ) ); return *this; }
struct SEEK_MODE
{
enum { CUR = SEEK_CUR, END = SEEK_END, SET = SEEK_SET };
};
long tell() { return ftell( fp ); }
long seek( long offset, int seek_mode ) { return fseek( fp, offset, seek_mode ); }
bool is_valid() { return fp != 0; }
bool close() { if( !fp ) return false;
fclose( fp ); fp = 0; ref_count = 0; return true; }
bool flush() { return fflush( fp ) == 0; }
file & operator=( const file & rh ) { copy_from( rh ); return *this; }
void copy_from( const file & rh ) { ref_count = rh.ref_count; fp = rh.fp; if( ref_count ) ++(*ref_count); }
~file()
{
if( ref_count )
{
if( --(*ref_count) == 0 ) close();
}
}
::FILE* & operator*() { return fp; }
private:
int* ref_count;
::FILE* fp;
};
template< typename _Elem >
inline bool dir( std::vector< std::basic_string< _Elem > > * result, const _Elem * path, const _Elem * wildcard, int flag = ALL )
{
std::basic_string< _Elem > strParent = path::normalize( path );
std::basic_string< _Elem > strWildcard = path::join( strParent, std::basic_string< _Elem >( fs_api< _Elem >::wildcard_all() ) );
fs_api< _Elem >::find_data c_file;
intptr_t hFile;
if( (hFile = fs_api< _Elem >::findfirst( strWildcard.c_str(), &c_file )) == -1L ) return false;
do {
bool bAdd = false;
bool bIsFile = !( c_file.attrib & _A_SUBDIR );
bool bIsDirectory = !bIsFile;
bool bDotDirectory = ( c_file.name[0] == '.' && c_file.name[1] == 0 ) || ( c_file.name[0] == '.' && c_file.name[1] == '.' && c_file.name[2] == 0 );
if( bIsFile && ( flag & FILE ) ) bAdd = true;
if( bDotDirectory && ( flag & DOT_DIRECTORY ) ) bAdd = true;
if( bIsDirectory && !bDotDirectory && ( flag & SUB_DIRECTORY ) ) bAdd = true;
std::basic_string< _Elem > strFileName = path::join( strParent, std::basic_string< _Elem >( c_file.name ) );
if( bAdd && nsl::wildcmp( wildcard, c_file.name, true ) ) result->push_back( strFileName );
if( bIsDirectory && !bDotDirectory && ( flag & RECURSIVE ) )
{
dir( result, strFileName.c_str(), wildcard, flag );
}
} while( fs_api< _Elem >::findnext( hFile, &c_file ) == 0 );
_findclose( hFile );
return true;
}
template< typename _Elem >
inline bool dir( std::vector< std::basic_string< _Elem > > * result, const _Elem * wildcard, int flag = ALL )
{
return dir( result, std::basic_string< _Elem >().c_str(), wildcard, flag );
}
template< typename _Elem >
inline std::vector< std::basic_string< _Elem > > dir( const _Elem * path, const _Elem * wildcard, int flag = ALL )
{
std::vector< std::basic_string< _Elem > > vList;
dir( &vList, path, wildcard, flag );
return vList;
}
template< typename _Elem >
inline std::vector< std::basic_string< _Elem > > dir( const _Elem * wildcard, int flag = ALL )
{
std::vector< std::basic_string< _Elem > > vList;
dir( &vList, wildcard, flag );
return vList;
}
template< typename _Elem >
inline size_t file_size( const _Elem* filename )
{
struct _stat st;
if( fs_api< _Elem >::stat( filename, &st ) == -1 ) return -1;
return st.st_size;
}
template< typename _Elem >
inline bool is_exist( const _Elem* filename )
{
struct _stat st;
return ( fs_api< _Elem >::stat( filename, &st ) != -1 );
}
template< typename _Elem >
inline bool is_file( const _Elem* filename )
{
struct _stat st;
if( fs_api< _Elem >::stat( filename, &st ) == -1 ) return false;
return !(st.st_mode & _S_IFDIR);
}
template< typename _Elem >
inline bool is_directory( const _Elem* filename )
{
struct _stat st;
if( fs_api< _Elem >::stat( filename, &st ) == -1 ) return false;
return st.st_mode & _S_IFDIR;
}
template< typename _Elem, typename _FileNameElem, typename _Container >
inline bool readfile( _Container * data, const _FileNameElem *path )
{
size_t size = file_size( path );
if( size == -1 ) return false;
int fd = fs_api< _FileNameElem >::open( path, _O_RDONLY | _O_BINARY, 0 );
if( fd == -1 ) return false;
data->reserve( size );
_Elem buf[ DEFAULT_IO_SIZE ];
size_t cur = 0;
while( size )
{
int rtn = _read( fd, buf, (unsigned int )( size > sizeof(buf) ? sizeof(buf) : size ) );
if( rtn <= 0 ) break;
size -= rtn;
data->insert( data->end(), buf, buf + rtn/sizeof(_Elem) );
}
_close( fd );
return true;
}
template< typename _Elem, typename _FileNameElem >
inline bool writefile( const _FileNameElem *path, const _Elem * data, size_t size )
{
int fd = fs_api< _FileNameElem >::open( path, _O_WRONLY | _O_CREAT | _O_BINARY | _O_TRUNC, _S_IREAD | _S_IWRITE );
if( fd == -1 ) return false;
size_t offset = 0;
while( size )
{
int rtn = _write( fd, &data[offset], (unsigned int)( size > DEFAULT_IO_SIZE ? sizeof(_Elem)*DEFAULT_IO_SIZE : sizeof(_Elem)*size ) );
if( rtn <= 0 ) break;
size -= rtn/sizeof(_Elem);
offset += rtn/sizeof(_Elem);
}
_close( fd );
return true;
}
template< typename _Elem, typename _FileNameElem >
inline bool textfile( std::basic_string< _Elem > *str, const _FileNameElem *path )
{
str->clear();
return readfile< _Elem, _FileNameElem, std::basic_string< _Elem > >( str, path );
}
template< typename _Elem, typename _FileNameElem >
inline bool textfile( std::vector< _Elem > *list, const _FileNameElem *path )
{
std::string str;
if( !readfile< _Elem, _FileNameElem, std::basic_string< _Elem > >( &str, path ) ) return false;
nsl::split( str.c_str(), list, "\r\n", false );
return true;
}
template< typename _Elem, typename _FileNameElem >
inline std::basic_string< _Elem > textfile( const _FileNameElem *path )
{
std::basic_string< _Elem > str;
textfile( &str, path );
return str;
}
template< typename _Elem >
inline std::basic_string< _Elem > checksum( const void *data, size_t size )
{
unsigned int checksum = 0;
for( size_t i = 0; i < size; ++i )
{
checksum += reinterpret_cast< const unsigned char* >( data )[i];
}
_Elem fmt[5] = { '%', '0', '8', 'X', '\0' };
return nsl::format( fmt, checksum );
}
template< typename _Elem, typename _FileNameElem >
inline std::basic_string< _Elem > checksum( const _FileNameElem *path )
{
std::vector< char > file;
if( !readfile< char >( &file, path ) ) return std::basic_string< _Elem >();
return checksum< _Elem >( &(*file.begin()), file.size() );
}
};
};
namespace nfl
{
using namespace nl::file;
namespace path { using namespace nl::str::path; };
};