Resume downloading from a certain position - c++

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;
}

Related

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

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?

Streaming file from aws s3 through boost socket

I'm trying to connect via boost ssl socket to aws s3.
It works but when I read, I had several problem.
Corrupted files on the same file but not others.
File not corrupted (md5filter got all the data) but the data sent to the buffer are not good. Meaning there is a problem between the different layers of read somewhere but can't figure out where.
Sometimes the program get stuck in the S3_client::read function and loop thousands of times in the do-while loop calling read. But it never reaches md5filter read.
It get stuck between filterStream.read() and md5filter.read() which is not called. I don't know if it gzip or filterStream. But it only happens if there is no call to the lower layers of read for a while.
Can you help spot the problem in my code ?
#ifndef BTLOOP_AWSCLIENT_H
#define BTLOOP_AWSCLIENT_H
#include "boost/iostreams/filter/gzip.hpp"
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filtering_streambuf.hpp>
#include <boost/iostreams/categories.hpp>
#include <boost/iostreams/stream.hpp>
#include <string>
#include <set>
#include <map>
#include <openssl/md5.h>
#include <sstream>
#include <fstream>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include "Logger.h"
namespace io = boost::iostreams;
namespace asio = boost::asio;
namespace ssl = boost::asio::ssl;
typedef ssl::stream<asio::ip::tcp::socket> ssl_socket;
namespace S3Reader
{
class MD5Filter
{
public:
typedef char char_type;
struct category :
io::multichar_input_filter_tag{};
MD5Filter( std::streamsize n );
~MD5Filter();
template<typename Source>
std::streamsize read( Source& src, char* s, std::streamsize n );
void setBigFileMode() { _bigFileMode = true; }
std::string close();
void setFileName( std::string fileName ) { _fileName = fileName; };
inline std::streamsize writtenBytes() {std::streamsize res = _writtenBytes; _writtenBytes= 0; return res;};
inline bool eof(){return _eof;};
private:
void computeMd5( char* buffer, size_t size, bool force = false );
private:
bool _bigFileMode;
int _blockCount;
std::vector<unsigned char> _bufferMD5;
MD5_CTX _mdContext;
unsigned char _hashMd5[MD5_DIGEST_LENGTH];
std::string _fileName;
std::streamsize _writtenBytes;
int _totalSize;
bool _eof;
};
class Ssl_wrapper : public io::device<io::bidirectional>
{
public:
Ssl_wrapper( ssl_socket* sock, std::streamsize n ) :
_sock( sock ),_totalSize(0) { };
std::streamsize read( char_type* s, std::streamsize n )
{
boost::system::error_code ec;
size_t rval = _sock->read_some( asio::buffer( s, n ), ec );
_totalSize +=rval;
LOG_AUDIT( " wrapperR: " << rval << " " << _totalSize << " "<<ec.message());
if ( !ec )
{
return rval;
}
else if ( ec == asio::error::eof )
return -1;
else
throw boost::system::system_error( ec, "Wrapper read_some" );
}
std::streamsize write( const char* s, std::streamsize n )
{
boost::system::error_code ec;
size_t rval = _sock->write_some( asio::buffer( s, n ), ec );
if ( !ec )
{
return rval;
}
else if ( ec == asio::error::eof )
return -1;
else
throw boost::system::system_error( ec, " Wrapper read_some" );
}
private:
ssl_socket* _sock;
int _totalSize;
};
class S3_client
{
public:
S3_client( const std::string& key_id, const std::string& key_secret, const std::string& bucket );
virtual ~S3_client();
bool open( const std::string& fileName );
int read( char* buffer, size_t size );
int readLine( char* buffer, size_t size );
void close();
bool eof() { return _filterStream.eof(); }
std::string authorize( const std::string request );
bool connectSocket( std::string url, std::string port, std::string auth );
private :
std::string _key_id;
std::string _key_secret;
std::string _bucket;
std::string _fileName;
io::gzip_decompressor _gzip;
MD5Filter _md5Filter;
boost::posix_time::seconds _timeout;
ssl_socket* _sock;
Ssl_wrapper* _wrapper;
io::stream<Ssl_wrapper>* _sockstream;
std::map<std::string, std::string> _headerMap;
io::filtering_istream _filterStream;
int _totalSize;
};
}
#endif //BTLOOP_AWSCLIENT_H
S3Client.cpp
#include "S3_client.h"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/iostreams/filter/counter.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <system/ArmError.h>
namespace io = boost::iostreams;
namespace asio = boost::asio;
namespace ssl = boost::asio::ssl;
namespace S3Reader
{
static const size_t s3_block_size = 8 * 1024 * 1024;
static const std::string base64_chars =
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789+/";
static inline bool is_base64( unsigned char c )
{
return (isalnum( c ) || (c == '+') || (c == '/'));
}
std::string url_encode( const std::string& value )
{
std::ostringstream escaped;
escaped.fill( '0' );
escaped << std::hex;
for ( auto i = value.begin(), n = value.end(); i != n; ++i )
{
auto c = *i;
if ( isalnum( c ) || c == '-' || c == '_' || c == '.' || c == '~' )
{
escaped << c;
continue;
}
escaped << std::uppercase;
escaped << '%' << std::setw( 2 ) << int((unsigned char) c );
escaped << std::nouppercase;
}
return escaped.str();
}
std::string base64_encode( unsigned char const* bytes_to_encode, unsigned int in_len )
{
std::string ret;
int i = 0;
int j = 0;
unsigned char char_array_3[3];
unsigned char char_array_4[4];
while ( in_len-- )
{
char_array_3[i++] = *(bytes_to_encode++);
if ( i == 3 )
{
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for ( i = 0; (i < 4); i++ )
ret += base64_chars[char_array_4[i]];
i = 0;
}
}
if ( i )
{
for ( j = i; j < 3; j++ )
char_array_3[j] = '\0';
char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
char_array_4[3] = char_array_3[2] & 0x3f;
for ( j = 0; (j < i + 1); j++ )
ret += base64_chars[char_array_4[j]];
while ((i++ < 3))
ret += '=';
}
return ret;
}
std::string to_hex( const uint8_t* buffer, size_t buffer_size )
{
std::stringstream sst;
for ( uint i = 0; i < buffer_size; i++ )
{
sst << std::setw( 2 ) << std::setfill( '0' ) << std::hex << int( buffer[i] );
}
return sst.str();
}
std::string getDateForHeader( bool amzFormat )
{
time_t lt;
time( &lt );
struct tm* tmTmp;
tmTmp = gmtime( &lt );
char buf[50];
if ( amzFormat )
{
strftime( buf, 50, "Date: %a, %d %b %Y %X +0000", tmTmp );
return std::string( buf );
}
else
{
tmTmp->tm_hour++;
//strftime( buf, 50, "%a, %d %b %Y %X +0000", tmTmp );
std::stringstream ss;
ss << mktime( tmTmp );
return ss.str();
}
}
MD5Filter::MD5Filter( std::streamsize n ) :
_bigFileMode( false ), _blockCount( 0 ), _writtenBytes(0), _totalSize( 0 )
{
MD5_Init( &_mdContext );
memset( _hashMd5, 0, MD5_DIGEST_LENGTH );
}
MD5Filter::~MD5Filter()
{
close();
}
template<typename Source>
std::streamsize MD5Filter::read( Source& src, char* s, std::streamsize n )
{
int result =0;
try
{
if ((result = io::read( src, s, n )) == -1 )
{
_eof=true;
LOG_AUDIT( _fileName << " md5R: " << result << " " << _totalSize );
return -1;
}
}
catch ( boost::exception& ex)
{
LOG_ERROR( _fileName <<" "<< boost::diagnostic_information(ex)<< " " << result );
}
computeMd5( s, (size_t) result );
_totalSize += result;
_writtenBytes = result;
LOG_AUDIT( _fileName << " md5R: " << result << " " << _totalSize );
return result;
}
void MD5Filter::computeMd5( char* buffer, size_t size, bool force )
{
size_t realSize = s3_block_size;
uint8_t blockMd5[MD5_DIGEST_LENGTH];
if ( !_bigFileMode )
{
MD5_Update( &_mdContext, buffer, size );
return;
}
if ( size > 0 )
{
_bufferMD5.insert( _bufferMD5.end(), &buffer[0], &buffer[size] );
}
if ((_bufferMD5.size() < s3_block_size) && !force )
return;
if ( force )
realSize = _bufferMD5.size();
MD5( &_bufferMD5[0], realSize, blockMd5 );
MD5_Update( &_mdContext, blockMd5, MD5_DIGEST_LENGTH );
_blockCount++;
if ( _bufferMD5.size() == s3_block_size )
{
_bufferMD5.clear();
return;
}
if ( force )
return;
memcpy( &_bufferMD5[0], &_bufferMD5[s3_block_size], _bufferMD5.size() - s3_block_size );
_bufferMD5.erase( _bufferMD5.begin() + s3_block_size, _bufferMD5.end());
}
std::string MD5Filter::close()
{
std::string mdOutput;
computeMd5( NULL, 0, true );
MD5_Final( _hashMd5, &_mdContext );
mdOutput = to_hex( _hashMd5, MD5_DIGEST_LENGTH );
if ( _bigFileMode )
{
mdOutput += "-" + boost::lexical_cast<std::string>( _blockCount );
}
return mdOutput;
}
std::string S3_client::authorize( const std::string request )
{
unsigned char* digest;
digest = HMAC( EVP_sha1(), _key_secret.c_str(), (int) _key_secret.size(), (unsigned char*) request.c_str(), (int) request.size(), NULL, NULL );
std::string signature( url_encode( base64_encode( digest, 20 )));
return "?AWSAccessKeyId=" + _key_id + "&Expires=" + getDateForHeader( false ) + "&Signature=" + signature;
}
S3_client::S3_client( const std::string& key_id, const std::string& key_secret, const std::string& bucket ) :
_key_id( key_id ), _key_secret( key_secret ), _bucket( bucket ), _gzip( io::gzip::default_window_bits, 1024 * 1024 )
, _md5Filter( s3_block_size ), _timeout( boost::posix_time::seconds( 1 )), _totalSize( 0 ) { }
S3_client::~S3_client()
{
close();
}
bool S3_client::connectSocket( std::string url, std::string port, std::string auth )
{
std::string amzDate = getDateForHeader( true );
std::string host = "url";
boost::asio::io_service io_service;
boost::asio::ip::tcp::resolver resolver( io_service );
boost::asio::ip::tcp::resolver::query query( url, "https" );
auto endpoint = resolver.resolve( query );
// Context with default path
ssl::context ctx( ssl::context::sslv23 );
ctx.set_default_verify_paths();
_sock = new ssl_socket( io_service, ctx );
boost::asio::socket_base::keep_alive option( true );
_wrapper = new Ssl_wrapper( _sock, s3_block_size );
_sockstream = new io::stream<Ssl_wrapper>( boost::ref( *_wrapper ));
asio::connect( _sock->lowest_layer(), endpoint );
_sock->set_verify_mode( ssl::verify_peer );
_sock->set_verify_callback( ssl::rfc2818_verification( url ));
_sock->handshake( ssl_socket::client );
_sock->lowest_layer().set_option( option );
std::stringstream ss;
ss << "GET " << _fileName << auth << " HTTP/1.1\r\n" << "Host: " << host << "\r\nAccept: */*\r\n\r\n";
_sockstream->write( ss.str().c_str(), ss.str().size());
_sockstream->flush();
std::string http_version;
int status_code = 0;
(*_sockstream) >> http_version;
(*_sockstream) >> status_code;
if ( !_sockstream || http_version.substr( 0, 5 ) != "HTTP/" )
{
std::cout << "Invalid response: " << http_version << " " << status_code << std::endl;
return false;
}
if ( status_code != 200 )
{
std::cout << "Response returned with status code " << http_version << " " << status_code << std::endl;
return false;
}
return true;
}
bool S3_client::open( const std::string& fileName )
{
std::string port = "443";
std::string url = "bucket";
std::stringstream authRequest;
std::string date = getDateForHeader( false );
_fileName = fileName;
authRequest << "GET\n\n\n" << date << "\n/" << _bucket << "" << fileName;
std::string auth = authorize( authRequest.str());
if ( !connectSocket( url, port, auth ))
THROW( "Failed to open socket" );
std::string header;
while ( std::getline( *_sockstream, header ) && header != "\r" )
{
std::vector<std::string> vectLine;
boost::split( vectLine, header, boost::is_any_of( ":" ));
if ( vectLine.size() < 2 )
continue;
boost::erase_all( vectLine[1], "\"" );
boost::erase_all( vectLine[1], "\r" );
boost::erase_all( vectLine[1], " " );
_headerMap[vectLine[0]] = vectLine[1];
}
if ( _headerMap.find( "Content-Length" ) == _headerMap.end())
return false;
if ( _headerMap.find( "Content-Type" ) == _headerMap.end())
return false;
if ((uint) std::atoi( _headerMap.at( "Content-Length" ).c_str()) > s3_block_size )
_md5Filter.setBigFileMode();
_md5Filter.setFileName( _fileName );
if ( _headerMap["Content-Type"] == "binary/octet-stream" )
_filterStream.push( _gzip, s3_block_size );
_filterStream.push( boost::ref( _md5Filter ), s3_block_size );
_filterStream.push( boost::ref( *_sockstream ), s3_block_size );
return true;
}
void S3_client::close()
{
std::string localMD5 = _md5Filter.close();
std::string headerMD5 = _headerMap["ETag"];
if ( localMD5 != headerMD5 )
THROW ( "Corrupted file " << _fileName << " " << localMD5 << " " << headerMD5 << "." );
else
LOG_AUDIT( "Close S3: " << _fileName << " " << localMD5 << " " << headerMD5 << "." );
}
int S3_client::readLine( char* buffer, size_t size )
{
_filterStream.getline( buffer, size );
return _filterStream.gcount();
}
int S3_client::read( char* buffer, size_t size )
{
std::streamsize sizeRead = 0;
do
{
_filterStream.read( buffer, size );
sizeRead = _md5Filter.writtenBytes();
_totalSize += sizeRead;
LOG_AUDIT( _fileName << " s3R: " << sizeRead << " " << _totalSize );
}
while( sizeRead ==0 && !_md5Filter.eof() && !_sockstream->eof() && _filterStream.good() && _sock->next_layer().is_open());
return sizeRead;
}
}
int main( int argc, char** argv )
{
S3Reader::S3_client client( key_id, key_secret, s3_bucket );
client.open("MyFile");
while (client.read(buffer, bufferSize) >0 ) {}
}

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.

C++ Implementing SFML InputStream

I'm trying to implement a custom InputStream but I'm having trouble doing so.
I seem to be opening the zip file just fine, and the library I'm using (https://bitbucket.org/wbenny/ziplib/wiki/Home) automatically gives me an istream* to the
data.
Yet I keep failing when I try to load the image file texture with the stream through:
sf::Texture::loadFromStream(sf::InputStream)
Any ideas as to what I'm doing incorrectly?
sf::InputStream
sf::Texture::loadFromStream
Here's my implementation:
Header)
#include <ZipFile.h>
namespace lvn
{
class NStream : public sf::InputStream
{
private:
ZipArchiveEntry::Ptr m_entry;
std::shared_ptr<std::istream> m_File = nullptr;
std::string m_filename;
//bool m_file_is_open = false;
public:
static bool ReadTxtFile( std::string filepath, tstring& textbuffer );
NStream( std::string pathName="" );
virtual ~NStream();
bool isOpen() const;
bool open( std::string pathName );
void close();
virtual sf::Int64 read( void* data, sf::Int64 size );
virtual sf::Int64 seek( sf::Int64 position );
virtual sf::Int64 tell();
virtual sf::Int64 getSize();
};
}
CPP)
#include <ZipFile.h>
#include "NStream.h"
namespace lvn
{
NStream::NStream( std::string pathName )
//: m_File( 0x00 )
{
using namespace std;
open( pathName );
}
NStream::~NStream( )
{
close( );
}
bool NStream::isOpen( ) const
{
//return (m_File != 0x0);
return ( m_File != nullptr );
}
//Ex. Images//albert.png
bool NStream::open( std::string pathName )
{
using namespace std;
close( );
auto archive_name = pathName.substr( 0, pathName.find( "/" ) ) + (".vndat"); //need to add the archive extension to the name
ZipArchive::Ptr archive = ZipFile::Open( archive_name );
m_entry = archive->GetEntry( pathName );
if ( m_entry == nullptr )
return false;
m_File = make_shared<istream>( nullptr );
m_File->rdbuf( m_entry->GetDecompressionStream()->rdbuf() );
m_filename = pathName;
return isOpen( );
}
void NStream::close( )
{
m_File.reset( );
}
sf::Int64 NStream::read( void* data, sf::Int64 size )
{
if ( !isOpen( ) )
return -1;
auto posPrev = tell();
m_File->read( static_cast<char *>( data ), size );
auto cur = tell();
return tell() - posPrev;
}
sf::Int64 NStream::seek( sf::Int64 position )
{
if ( !isOpen( ) )
return -1;
m_File->seekg( position );
return tell( );
}
sf::Int64 NStream::tell( )
{
if ( !isOpen( ) )
return -1;
// istream returns the offset in bytes or -1 on error just like SFML wants.
return m_File->tellg( );
}
sf::Int64 NStream::getSize( )
{
if ( !isOpen( ) )
return -1;
//get length of file (by seeking to end), then restore original offset
const auto originalIdx = tell( );
m_File->seekg( 0, m_File->end );
const sf::Int64 length = tell( );
seek( originalIdx );
// tell returns length of file or -1 on error just like SFML wants.
return length;
}
}
Example usage (should work but doesn't: loadFromStream fails):
auto pTextureStream = make_shared<NStream>();
pTextureStream->open( "Images/image.png" );
auto pTexture = make_shared<sf::Texture>();
pTexture->loadFromStream( *pTextureStream );
This is my implementation, I hope you find it useful
class StreamSFML : public sf::InputStream
{
std::shared_ptr<std::istream> m_source;
public:
explicit StreamSFML(std::shared_ptr<std::istream> stream) : m_source(stream) {}
sf::Int64 read(void* data, sf::Int64 size) override
{
m_source->read(static_cast<char*>(data), size);
return m_source->gcount();
}
sf::Int64 seek(sf::Int64 position) override
{
m_source->seekg(position, m_source->beg);
return m_source->gcount();
}
sf::Int64 tell() override
{
return m_source->tellg();
}
sf::Int64 getSize() override
{
auto curr = m_source->tellg();
m_source->seekg(0, m_source->end);
sf::Int64 pos = static_cast<sf::Int64>(m_source->tellg());
m_source->seekg(curr, m_source->beg);
return pos;
}
};

Splitting strings C++ [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Splitting a string in C++
I have a program that copies files.
I have a string which is a directory path, however it could be just a file name. For example:
rootdirname\childdirname\filename.ini
or it could be:
filename.ini
Im still quite new to C++, I need to split the string on \ and create directories with MKDir.
Any one know how to split the string??
I'm not sure how you are defining your string but if it is a char* you can use strtok. http://www.cplusplus.com/reference/clibrary/cstring/strtok/
You can use this C solution:
http://www.cplusplus.com/reference/clibrary/cstring/strtok/
This allows you to split a string in many tokens. You slip the string on "/" like you want.
There is also this answer here in Stackoverflow which I think it will help:
How do I tokenize a string in C++?
reinvented the wheel on linux
#include <string>
#include <sys/statfs.h>
bool existsDir( const std::string& dir ) {
return existsFile( dir );
}
bool existsFile( const std::string& file ) {
struct stat fileInfo;
int error = stat( file.c_str(), &fileInfo );
if( error == 0 ){
return true;
} else {
return false;
}
}
bool createDir( std::string dir, int mask = S_IRWXU | S_IRWXG | S_IRWXO ) {
if( !existsDir( dir ) ) {
mkdir( dir.c_str(), mask );
return existsDir( dir );
} else {
return true;
}
}
bool createPath( std::string path, int mask = S_IRWXU | S_IRWXG | S_IRWXO ) {
if( path.at( path.length()-1 ) == '/' ){
path.erase( path.length()-1 );
}
std::list<std::string> pathParts;
int slashPos = 0;
while( true ) {
slashPos = path.find_first_of( "/", slashPos+1 );
if( slashPos < 0)
break;
std::string pp( path.substr( 0, slashPos ) );
pathParts.push_back( pp );
}
std::list<std::string>::const_iterator pp_cit;
for( pp_cit=pathParts.begin(); pp_cit!=pathParts.end(); ++pp_cit ){
createDir( (*pp_cit), mask );
}
createDir( path, mask );
return existsDir( path );
}