Are utf-8 std::locales missing on iOS? - c++

I'm trying to get std::locale that will be able to handle Russian symbols in my code.
std::optional< std::locale > TryGetLocale( const std::string& name )
{
try
{
std::locale res( name );
if( std::isalpha( L'ф', res ) )
return res;
else
return std::nullopt;
}
catch( ... )
{
return std::nullopt;
}
}
std::optional< std::locale > TryGenerateLocale( const std::string& name, const std::string base_name )
{
try
{
boost::locale::generator gen;
std::locale base( base_name );
auto res = std::locale( gen.generate( base, name ) );
if( std::isalpha( L'ф', res ) )
return res;
else
return std::nullopt;
}
catch( ... )
{
return std::nullopt;
}
}
std::locale TryGetLocale()
{
auto res = TryGetLocale( "ru_RU.utf8" );
if( !res )
res = TryGetLocale( "ru_RU.UTF-8" );
if( !res )
res = TryGenerateLocale( "ru_RU.UTF-8", "en_US.UTF-8" );
if( !res )
res = TryGenerateLocale( "ru_RU.UTF-8", "en_US.utf8" );
if( !res )
{
using namespace U_ICU_NAMESPACE;
int32_t count;
const Locale* list = Locale::getAvailableLocales( count );
for( size_t i = 0; i < static_cast< size_t >( count ); ++i )
{
res = TryGenerateLocale( "ru_RU.UTF-8", std::string( list[ i ].getName() ) + ".utf8" );
if( res )
break;
res = TryGenerateLocale( "ru_RU.UTF-8", std::string( list[ i ].getName() ) + ".UTF-8" );
if( res )
break;
}
}
if( !res )
{
std::terminate();
}
return *res;
}
On Android and desktops everything is ok. On iOS simulator everything is also ok, but when I try to launch this code on iOS device - I'm getting terminate, because I can't get any named std::locale. Is it normal behavior for iOS devices? Do they miss any UTF-8 c++ locales?

Related

Resume downloading from a certain position

I need to download the file after a pause. But I do not know how to implement it correctly using https://github.com/yhirose/cpp-httplib . But the problem is that when the download resumes, the server starts sending me the file first. Question: how do I tell the server the size of the piece that I have already downloaded, so that the server sends me only the necessary part?
My code:
std::string body;
httplib::Client cli( url, port );
cli.set_follow_location( true );
int file_size = is_part_of_file ? GetFileSize( result_file_name.c_str() ) : 0; // it is downloaded part of the file
int last_percent;
auto res = cli.Get(
file_path.c_str(), httplib::Headers(),
[ & ]( const httplib::Response& response )
{
( void )response;
return *is_download;
},
[ & ]( const char* data, size_t data_length )
{
body.append( data, data_length );
return *is_download;
},
[ & ]( uint64_t len, uint64_t total )
{
int percent = ( int )( len * 100 / total );
if( last_percent != percent )
{
*p_percent = ( ( float )percent / 100 );
}
last_percent = percent;
return *is_download;
} );
if( res )
{
std::ofstream out( result_file_name, std::ios::binary | std::ios::app );
out << body;
out.close();
}
else
{
if( is_part_of_file )
{
std::ofstream out( result_file_name, std::ios::binary | std::ios::app );
out << body;
out.close();
}
return false;
}

LDAP C++ why is ldap_result always busy?

I tried copying this example: https://docs.oracle.com/cd/E19957-01/817-6707/search.html
I am trying to get the DN to bind to a user. But when searching ldap_result always says that the server is busy. Is there something else I need to do to get this to work?
LDAP *ld = NULL;
int iDebug = session.ini["ldap_debug_level"].Int32();
string sHostIP = session.ini["ldap_host"];
string sPort = session.ini["ldap_port"];
string sURL = sHostIP+":"+sPort;
int iErr;
iErr = ldap_initialize( &ld, sURL.c_str() );
if( iErr != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
int iVersion = LDAP_VERSION3;
if( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &iVersion ) != LDAP_OPT_SUCCESS )
{
ldap_unbind(ld);
return false;
}
string sLDAPPW = session.ini["ldap_server_pw"];
struct berval pServerPassword = { 0, NULL };
pServerPassword.bv_val = ber_strdup( &sLDAPPW[0] );
pServerPassword.bv_len = strlen( pServerPassword.bv_val );
//mysterious code required to prevent crashing
int nsctrls = 0;
LDAPControl c;
c.ldctl_oid = LDAP_CONTROL_PASSWORDPOLICYREQUEST;
c.ldctl_value.bv_val = NULL;
c.ldctl_value.bv_len = 0;
c.ldctl_iscritical = 0;
LDAPControl sctrl[3];
sctrl[nsctrls] = c;
LDAPControl *sctrls[4];
sctrls[nsctrls] = &sctrl[nsctrls];
sctrls[++nsctrls] = NULL;
LDAPControl **sctrlsp = NULL;
if ( nsctrls )
{
sctrlsp = sctrls;
}
string sBindDN = session.ini["ldap_bind_dn"];
ber_int_t iMsgid;
iErr = ldap_sasl_bind( ld, sBindDN.c_str(), LDAP_SASL_SIMPLE, &pServerPassword, sctrlsp, NULL, &iMsgid );
ber_memfree( pServerPassword.bv_val );
if( iErr != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
string sBaseDN = session.ini["ldap_base_dn"];
string sFilters = "(uid="+sUserName+")";
LDAPMessage *res;
iErr = ldap_search_ext(ld, // LDAP * ld
&sBaseDN[0], // char * base
LDAP_SCOPE_SUBORDINATE,// int scope
&sFilters[0], // char * filter
NULL, // char * attrs[]
0, // int attrsonly
NULL, // LDAPControl ** serverctrls
NULL, // LDAPControl ** clientctrls
NULL, //struct timeval *timeoutp
LDAP_NO_LIMIT, //int sizelimit
&iMsgid //ber_int_t iMsgid
);
if (iErr != LDAP_SUCCESS)
{
ldap_unbind(ld);
return false;
}
struct timeval zerotime;
zerotime.tv_sec = zerotime.tv_usec = 0L;
int i, parse_rc, finished = 0, num_entries = 0, num_refs = 0;
char *a, *dn, *matched_msg = NULL, *error_msg = NULL;
BerElement *ber;
char **vals, **referrals;
LDAPControl **serverctrls;
while ( !finished )
{
iErr = ldap_result( ld, iMsgid, LDAP_MSG_ONE, &zerotime, &res );
switch ( iErr )
{
case -1:
Log(1, "BasicAuthenticate: error in ldap_result:{}", ldap_err2string(iErr));
ldap_unbind(ld);
return false;
break;
case 0:
// The timeout period specified by zerotime was exceeded keep polling
Log(1, "BasicAuthenticate: server busy: keep polling");
sleep(1);
break;
case LDAP_RES_SEARCH_ENTRY:
num_entries++;
//Get and print the DN of the entry.
if (( dn = ldap_get_dn( ld, res )) != NULL )
{
Log (1, "ldap_get_dn: {}", dn );
ldap_memfree( dn );
}
for ( a = ldap_first_attribute( ld, res, &ber ); a != NULL; a = ldap_next_attribute( ld, res, ber ) )
{
// Get and print all values for each attribute.
if (( vals = ldap_get_values( ld, res, a )) != NULL )
{
for ( i = 0; vals[ i ] != NULL; i++ )
{
Log (1, "ldap_get_values: {}:{}", a, vals[ i ] );
}
ldap_value_free( vals );
}
ldap_memfree( a );
}
if ( ber != NULL )
{
ber_free( ber, 0 );
}
ldap_msgfree( res );
break;
case LDAP_RES_SEARCH_REFERENCE:
num_refs++;
parse_rc = ldap_parse_reference( ld, res, &referrals, NULL, 1 );
if ( parse_rc != LDAP_SUCCESS )
{
ldap_unbind(ld);
return false;
}
if ( referrals != NULL )
{
for ( i = 0; referrals[ i ] != NULL; i++ )
{
Log(1, "BasicAuthenticate: Search reference:{}", referrals[ i ]);
}
ldap_value_free( referrals );
}
break;
case LDAP_RES_SEARCH_RESULT:
finished = 1;
parse_rc = ldap_parse_result( ld, res, &iErr, &matched_msg, &error_msg, NULL, &serverctrls, 1 );
if ( parse_rc != LDAP_SUCCESS )
{
kDebugLog(1, "BasicAuthenticate: error in ldap_parse_result:{}", ldap_err2string(parse_rc));
ldap_unbind(ld);
return false;
}
break;
default:
break;
}
}
The error I get is:
BasicAuthenticate: server busy keep polling
BasicAuthenticate: error in ldap_parse_result:Server is busy
Am I missing a line of code so the server won't be busy? Is there some sort of incompatibility with the methods I'm using?

Libtorrent Session_Status not updating

Im trying to get Session_Status updated but for whatever reason the values of the structure never update, session is started like so:
using namespace libtorrent;
session* Session;
session_status* Session_Status;
session_settings* Session_Settings;
bool Start_Client_Sess ( )
{
using namespace libtorrent;
Session = new session;
Session_Status = new session_status;
Session_Settings = new session_settings;
Session->settings ( );
Session->set_settings ( *Session_Settings );
Session->add_extension ( create_ut_pex_plugin );
Session->add_extension ( create_ut_metadata_plugin );
Session->add_extension ( create_lt_trackers_plugin );
Session->add_extension ( create_smart_ban_plugin );
Session->start_upnp ( );
Session->start_natpmp ( );
Session->start_dht ( );
Session->start_lsd ( );
error_code e;
Session->listen_on ( std::make_pair ( 6881 , 6889 ) , e );
if ( e )
{
return false;
}
return true;
}
then on a Windows 1 second timer I'm doing this:
void RunTimer ( )
{
using namespace libtorrent;
Session->status ( );
if ( Session->is_listening ( ) )
{
if ( Session_Status->has_incoming_connections )
{
INT x = 2;
std::cout << x << "\n";
}
else
{
INT x = 1;
std::cout << x << "\n";
}
}
else
{
INT x = 0;
std::cout << x << "\n";
}
}
but no matter what the session is always listening even if the firewall is blocking Libtorrent and there is always connections even if the internet is off.
I believe you meant to assign the session status to your Session_Status object:
*Session_Status = Session->status();
I would suggest you don't heap allocate the session_status nor session_settings objects.

Reading a config file

I'm trying to read a config file like this:
rawfile=input.raw
encfile=encoded.enc
decfile=decoded.raw
width=512
height=512
rle=1
quantfile=matrix.txt
logfile=log.txt
Having this function:
void Compression::readConfigFile(char * input)
{
string lineBuf;
string optionBuf;
std::ifstream confFile(input);
if ( confFile.is_open() )
{
while ( getline( confFile, lineBuf ) )
{
optionBuf = "rawfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->rawfile = lineBuf.c_str();
}
optionBuf = "encfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->encfile = lineBuf.c_str();
}
optionBuf = "decfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->encfile = lineBuf.c_str();
}
optionBuf = "width=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->width = atoi( lineBuf.c_str() );
}
optionBuf = "height=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->height = atoi( lineBuf.c_str() );
}
optionBuf = "rle=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->rle = atoi( lineBuf.c_str() );
}
optionBuf = "quantfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length());
this->matrix = lineBuf.c_str();
}
optionBuf = "logfile=";
if ( ( ( int )lineBuf.find(optionBuf) ) != -1 )
{
lineBuf.erase( 0, optionBuf.length() );
this->logfile = lineBuf.c_str();
}
confFile.close();
}
}
else
cout << "Can't open file: " << input << endl;
}
But it doesn't work. My ints are 0 or some big number. My strings are still empty.
Can someone help me please?
Kind regards,
shouldn't you rather close the file outside of the while loop ?
while() {
...
}
confFile.close();

Can the key of a line in an .inf file be retrieved using the SetupAPI?

I'm using the function SetupGetLineText ( http://msdn.microsoft.com/en-us/library/aa377388(v=VS.85).aspx ) from the Setup API to read a line from a section in an inf file.
Lines are in the format:
key=value
SetupGetLineText appears to return the value part. That's fine, but I also want to know what the key is for the current context I'm reading. There doesn't seem to be a function in the Setup API for reading the key.
Any help in working out how to retrieve the key would be appreciated.
Here is a class I use to handle inf files using SetupAPI.
#ifndef SETUP_INF_PARSER_H_INC_
#define SETUP_INF_PARSER_H_INC_
#include <string>
#include <vector>
namespace win32
{
namespace inf
{
class line
{
public:
line() { ZeroMemory( &_ctx, sizeof( _ctx ) ); }
line( const INFCONTEXT& ctx ) : _ctx( ctx ) {}
bool operator==( const line& op2 ) const
{
return memcmp( &_ctx, &op2._ctx, sizeof( _ctx ) ) == 0;
}
bool operator!=( const line& op2 ) const
{
return memcmp( &_ctx, &op2._ctx, sizeof( _ctx ) ) != 0;
}
bool operator<( const line& op2 ) const
{
std::wstring str0, str1;
if( string_at( 0, str0 ) && op2.string_at( 0, str1 ) )
return str0 < str1;
return memcmp( &_ctx, &op2._ctx, sizeof( _ctx ) ) < 0;
}
bool isValid() const
{
return *this != line();
}
bool string_at( unsigned int idx, std::wstring& str ) const
{
wchar_t buf[4096];
DWORD size_needed = 0;
if( SetupGetStringField( (PINFCONTEXT) &_ctx, idx, buf, sizeof( buf ), &size_needed ) )
{
str = buf;
return true;
}
return false;
}
std::vector<std::wstring> contents()
{
std::vector<std::wstring> lst;
for( unsigned int idx = 0; true; ++idx )
{
std::wstring str;
if( !string_at( idx, str ) )
{
break;
}
lst.push_back( str );
}
return lst;
}
operator INFCONTEXT*() { return &_ctx; }
private:
INFCONTEXT _ctx;
};
class section
{
public:
section()
{
ZeroMemory( &_ctx, sizeof( _ctx ) );
}
section( HINF hInf, const std::wstring& section_name )
: _Name( section_name )
{
ZeroMemory( &_ctx, sizeof( _ctx ) );
SetupFindFirstLine( hInf, section_name.c_str(), 0, &_ctx );
}
~section()
{
}
class iterator : public std::iterator<std::forward_iterator_tag,line>
{
friend section;
public:
iterator()
{
ZeroMemory( &_ctx, sizeof( _ctx ) );
}
iterator& operator++()
{
INFCONTEXT tmpCtx;
if( SetupFindNextLine( _ctx, &tmpCtx ) )
{
_ctx = tmpCtx;
}
else
{
_ctx = line();
}
return *this;
}
line operator*()
{
return _ctx;
}
line* operator->()
{
return &_ctx;
}
bool operator==( const iterator& op2 ) const
{
return _ctx == op2._ctx;
}
bool operator!=( const iterator& op2 ) const
{
return _ctx != op2._ctx;
}
private:
iterator( INFCONTEXT& ctx )
: _ctx( ctx )
{}
line _ctx;
};
bool operator<( const section& op2 ) const
{
return _Name < op2._Name;
}
iterator begin()
{
return iterator( _ctx );
}
iterator end()
{
return iterator();
}
private:
std::wstring _Name;
INFCONTEXT _ctx;
};
class inf_file
{
public:
inf_file( const std::wstring& str )
{
UINT err_line = 0;
_inf = SetupOpenInfFile( str.c_str(), 0, INF_STYLE_WIN4, &err_line );
if( _inf == INVALID_HANDLE_VALUE )
{
DWORD err = GetLastError();
// do something ..
throw std::invalid_argument( "failed to open inf file" );
}
}
~inf_file()
{
SetupCloseInfFile( _inf );
}
section get_section( const std::wstring& section_name )
{
return section( _inf, section_name );
}
class iterator : public std::iterator<std::forward_iterator_tag,section>
{
friend inf_file;
public:
iterator() : _hInf( 0 ), _idx( 0 ) {}
iterator& operator++()
{
if( _idx < 0 )
_idx = 0;
else
++_idx;
init_at( _idx );
return *this;
}
const section& operator*() const
{
return _Section;
}
section* operator->()
{
return &_Section;
}
bool operator==( const iterator& op2 ) const
{
return _idx == op2._idx;
}
bool operator!=( const iterator& op2 ) const
{
return !(*this == op2);
}
private:
void init_at( int idx )
{
if( _hInf != 0 && _hInf != INVALID_HANDLE_VALUE )
{
wchar_t buf[128] = { 0 };
UINT sizeNeeded = 0;
if( SetupEnumInfSectionsW( _hInf, _idx, buf, ARRAYSIZE( buf ), &sizeNeeded ) )
{
_Section = section( _hInf, buf );
return;
}
}
_Section = section();
}
iterator( HINF& ctx )
: _idx( 0 ), _hInf( ctx )
{}
section _Section;
HINF _hInf;
int _idx;
};
iterator begin()
{
return iterator( _inf );
}
iterator end()
{
return iterator();
}
struct VersionInfo
{
std::wstring signature;
std::wstring class_name;
GUID class_guid;
std::wstring provider;
std::wstring date;
std::wstring version;
};
bool parseVersionInfo( VersionInfo& info )
{
section s( _inf, L"Version" );
for( section::iterator i = s.begin(); i != s.end(); ++i )
{
std::vector<std::wstring> str_list = i->contents();
if( str_list.size() > 1 )
{
std::wstring& entry = str_list[0];
std::wstring& entry1 = str_list[1];
if( entry == L"Signature" )
{
info.signature = entry1;
}
else if( entry == L"Class" )
{
info.class_name = entry1;
}
else if( entry == L"ClassGUID" )
{
IIDFromString( const_cast<wchar_t*>( entry1.c_str() ), &info.class_guid );
}
else if( entry == L"Provider" )
{
info.provider = entry1;
}
else if( entry == L"DriverVer" )
{
info.date = entry1;
info.version = str_list[2];
}
}
}
return true;
}
private:
inf_file( const inf_file& );
inf_file& operator=( const inf_file& );
HINF _inf;
};
};
};
#endif // SETUP_INF_PARSER_H_INC_
A long shot:
BOOL SetupGetStringField(
__in PINFCONTEXT Context,
__in DWORD FieldIndex,
__inout PTSTR ReturnBuffer,
__in DWORD ReturnBufferSize,
__out PDWORD RequiredSize
);
with
FieldIndex [in]
The 1-based index of
the field within the specified line
from which the string should be
retrieved. Use a FieldIndex of 0 to
retrieve a string key, if present.