// This mfunction creates 'numPlayers' player entries // with username and password 'bot_X'. bool CdbInterface::createTestPlayers(int numPlayers) { bool rc = true; for (int i = 0; i < numPlayers; i++) { char buf[17]; sprintf(buf, "bot_%i", i + 1); // First check that the player is not already there! char query[MAXQUERYSIZE]; sprintf(query, "SELECT username FROM pokeruser where username='******';", buf); if (!dbase_->dbQuery(query)) { Sys_LogError("Query to create test player failed(0)."); return false; } const char* fetched = dbase_->dbFetchRow(); if (fetched == NULL) { // Okay now create the player MD5 context; context.update((unsigned char*)buf, strlen(buf)); context.finalize(); sprintf(query, "INSERT INTO customers (username, password, cc1_type, cc1_number, spam) VALUES ('%s', '%s', 'asiV', '1', 1);", buf, context.hex_digest()); if (!dbase_->dbQuery(query)) { Sys_LogError("Query to create test player failed(1)."); return false; } sprintf(query, "INSERT INTO pokeruser (username, password) VALUES ('%s', '%s');", buf, context.hex_digest()); if (!dbase_->dbQuery(query)) { Sys_LogError("Query to create test player failed(2)."); return false; } } } return true; }
const wxString wxMD5::GetDigest() { MD5 context; context.update((unsigned char*)m_szText.mb_str().data(), m_szText.Len()); context.finalize(); wxString md5(context.hex_digest()); md5.MakeUpper(); return md5; }
bool CdbInterface::authenticate(const char* username, const char* password) { SingleLock l(&dbMutex_); if (!l.lock()) return false; ReadLockSQLTable sqlLock(dbase_, "pokeruser"); if (!sqlLock.success_) return false; char query[MAXQUERYSIZE]; char* dbPassword = NULL; MD5 context; string u = sqlfy(username); context.update((unsigned char *)password, (int)strlen(password)); context.finalize(); memset(query, 0x0, MAXQUERYSIZE); sprintf(query, "SELECT password FROM pokeruser WHERE username='******'", u.c_str()); if (!dbase_->dbQuery(query)) { if (DEBUG & DEBUG_DATABASE) { printf("Query to authenticate %s failed!\n", username); printf("Reason: %s\n", mysql_error(dbase_->mySQLQuery_)); } return false; } dbPassword = dbase_->dbFetchRow(); if (dbPassword == NULL) { char s[200]; sprintf(s, "CTable::tableLogin: User %s does not exist in database!", username); Sys_LogError(s); return false; } else if (strcmp(dbPassword, context.hex_digest())) { char s[200]; sprintf(s, "CTable::tableLogin: wrong password %s for user %s.", password, username); Sys_LogError(s); return false; } return true; };
bool CdbInterface::authenticate(const char* username, const char* password) { ReadLockSQLTable sqlLock(dbase_, "pokeruser"); CStrOut query; char* dbPassword = NULL; string u = sqlfy(username); MD5 context; context.update((unsigned char*)password, strlen(password)); context.finalize(); query << "SELECT password FROM pokeruser WHERE username='******'\''; if (!dbase_->dbQuery(query.str())) { if (DEBUG & DEBUG_DATABASE) { printf("Query to authenticate %s failed!\n", username); } return false; } dbPassword = dbase_->dbFetchRow(); if (dbPassword == NULL) { if (DEBUG & DEBUG_DATABASE) { printf("User %s does not exist in database!\n", username); } return false; } else if (strcmp(dbPassword, context.hex_digest())) { if (DEBUG & DEBUG_DATABASE) { printf("User supplied password and password on file don't match!\n"); } return false; } return true; };
int main( int argc, char* argv[ ] ) { int first_arg = 0; bool prune = false; bool recurse = false; bool invalid = false; bool is_quiet = false; bool use_zlib = true; bool is_delete = false; bool is_quieter = false; string open_mode( "wb" ); #ifndef ZLIB_SUPPORT encoding_type encoding = e_encoding_type_esc; #else encoding_type encoding = e_encoding_type_raw; #endif if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-0" ) { ++first_arg; open_mode += "0"; } else if( string( argv[ first_arg + 1 ] ) == "-1" ) { ++first_arg; open_mode += "1"; } else if( string( argv[ first_arg + 1 ] ) == "-9" ) { ++first_arg; open_mode += "9"; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-d" ) { ++first_arg; is_delete = true; } } if( !is_delete ) { if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-r" ) { ++first_arg; recurse = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-p" ) { ++first_arg; prune = true; if( !recurse ) invalid = true; } } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-q" ) { ++first_arg; is_quiet = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-qq" ) { ++first_arg; is_quiet = true; is_quieter = true; } } if( argc > first_arg + 1 ) { // NOTE: Ignore '-y' for compatibility with zip. if( string( argv[ first_arg + 1 ] ) == "-y" ) ++first_arg; } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-b64" ) { ++first_arg; encoding = e_encoding_type_b64; } else if( string( argv[ first_arg + 1 ] ) == "-esc" ) { ++first_arg; encoding = e_encoding_type_esc; } } #ifdef ZLIB_SUPPORT if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-ngz" ) { ++first_arg; use_zlib = false; } } #endif if( !is_quiet ) cout << "bundle v0.1e\n"; if( invalid || ( argc - first_arg < 2 ) || string( argv[ 1 ] ) == "?" || string( argv[ 1 ] ) == "/?" || string( argv[ 1 ] ) == "-?" ) { #ifndef ZLIB_SUPPORT cout << "usage: bundle [-0|-1|-9] [-d]|[-r [-p]] [-q[q]] [-b64|-esc] <fname> [<fspec1> [<fspec2> [...]]] [-x <fspec1> [...]]" << endl; #else cout << "usage: bundle [-0|-1|-9] [-d]|[-r [-p]] [-q[q]] [-b64|-esc] [-ngz] <fname> [<fspec1> [<fspec2> [...]]] [-x <fspec1> [...]]" << endl; #endif cout << "\nwhere: -0/-1/-9 is used for setting zero/fastest/best compression level" << endl; cout << " and: -d is to delete matching files which exist in an existing bundle" << endl; cout << " and: -r is to recurse sub-directories (-p to prune empty directories)" << endl; cout << " and: -q for quiet mode (-qq to suppress all output apart from errors)" << endl; cout << " and: -b64/-esc stores file data using b64/esc encoding for text lines" << endl; #ifdef ZLIB_SUPPORT cout << " and: -ngz in order to not preform zlib compression" << endl; #endif cout << " also: -x identifies one or more filespecs that are to be excluded" << endl; return 0; } try { g_cwd = get_cwd( ); string::size_type pos; #ifdef _WIN32 while( ( pos = g_cwd.find( '\\' ) ) != string::npos ) g_cwd[ pos ] = '/'; #endif pos = g_cwd.find_last_of( '/' ); if( is_root_path( g_cwd ) ) throw runtime_error( "cannot created a bundle in the root directory" ); map< string, vector< string > > all_filespecs; map< string, vector< string > > all_exclude_filespecs; string filename( argv[ first_arg + 1 ] ); if( !filename.empty( ) && filename[ 0 ] == '-' ) throw runtime_error( "unknown or bad option '" + filename + "' use -? to see options" ); string ext( c_default_extension ); if( use_zlib ) ext += c_zlib_extension; if( filename.find( ext ) == string::npos ) filename += ext; bool get_exclude_filespecs = false; string directory = g_cwd.substr( pos + 1 ); if( !is_delete ) { for( int i = first_arg + 2; i < argc; i++ ) { string next( argv[ i ] ); if( !next.empty( ) && next[ 0 ] == '-' ) { if( next == "-x" && !get_exclude_filespecs ) { next.erase( ); get_exclude_filespecs = true; } else throw runtime_error( "unknown or bad option '" + next + "' use -? to see options" ); } if( !next.empty( ) ) { string::size_type wpos = next.find_first_of( "?*" ); string filespec_path; if( wpos == 0 ) { filespec_path = g_cwd + "/" + next; wpos = string::npos; } else { if( !absolute_path( next.substr( 0, wpos ), filespec_path ) ) throw runtime_error( "unable to determine absolute path for '" + next + "'" ); } #ifdef _WIN32 string::size_type pos; while( ( pos = filespec_path.find( '\\' ) ) != string::npos ) filespec_path[ pos ] = '/'; #endif if( is_root_path( filespec_path ) ) throw runtime_error( "cannot bundle directory '" + next + "' (need to specify a non-root directory)" ); if( wpos != string::npos ) #ifdef _WIN32 filespec_path += next.substr( wpos ); #else filespec_path += "/" + next.substr( wpos ); #endif string::size_type rpos = filespec_path.find_last_of( '/' ); string filename_filter; if( rpos != string::npos ) { filename_filter = filespec_path.substr( rpos + 1 ); filespec_path.erase( rpos ); } if( recurse == true && filespec_path.length( ) > g_cwd.length( ) && filespec_path.find( g_cwd ) == 0 ) { filename_filter = filespec_path.substr( g_cwd.length( ) + 1 ) + "/" + filename_filter; filespec_path = g_cwd; } if( !get_exclude_filespecs ) all_filespecs[ filespec_path ].push_back( filename_filter ); else all_exclude_filespecs[ filespec_path ].push_back( filename_filter ); } } if( all_filespecs.empty( ) ) all_filespecs[ g_cwd ].push_back( "*" ); } int num_deleted = 0; set< string > file_names; set< string > matched_filters; bool is_append = false; if( file_exists( filename ) ) is_append = true; if( is_delete && first_arg + 2 >= argc ) throw runtime_error( "cannot delete files without specifying at least one filespec" ); if( is_delete && !is_append ) throw runtime_error( "no bundle file '" + filename + "' was found" ); string output_filename( filename ); if( is_append ) output_filename = output_filename + ".tmp"; // NOTE: Empty code block for scope purposes. { #ifndef ZLIB_SUPPORT ofstream outf( output_filename.c_str( ) ); if( !outf ) throw runtime_error( "unable to open file '" + output_filename + "' for output" ); #else gzFile gzf; ofstream outf; if( !use_zlib ) outf.open( output_filename.c_str( ) ); else gzf = gzopen( output_filename.c_str( ), open_mode.c_str( ) ); if( ( use_zlib && !gzf ) || ( !use_zlib && !outf ) ) throw runtime_error( "unable to open file '" + output_filename + "' for output" ); #endif if( !is_quiet ) { if( !is_append ) cout << "==> started bundling '" << filename << "'\n"; else cout << "==> continue bundling '" << filename << "'\n"; } absolute_path( filename, g_bundle_file_name ); absolute_path( output_filename, g_output_file_name ); string header( "B " ); header += to_string( c_format_version ); switch( encoding ) { case e_encoding_type_b64: header += " B64"; break; case e_encoding_type_esc: header += " ESC"; break; case e_encoding_type_raw: header += " RAW"; break; } #ifndef ZLIB_SUPPORT outf << header << '\n'; #else if( !use_zlib ) outf << header << '\n'; else write_zlib_line( gzf, header ); #endif if( !is_delete ) { for( map< string, vector< string > >::iterator i = all_filespecs.begin( ); i != all_filespecs.end( ); ++i ) { string filespec_path( i->first ); vector< string >& filename_filters( i->second ); vector< string >* p_filename_exclusions = 0; if( all_exclude_filespecs.count( i->first ) ) p_filename_exclusions = &all_exclude_filespecs[ i->first ]; #ifndef ZLIB_SUPPORT process_directory( directory, filespec_path, filename_filters, p_filename_exclusions, matched_filters, file_names, recurse, prune, is_quieter, is_append, encoding, outf ); #else process_directory( directory, filespec_path, filename_filters, p_filename_exclusions, matched_filters, file_names, recurse, prune, is_quieter, is_append, encoding, outf, use_zlib, gzf ); #endif if( !is_quieter ) { for( size_t i = 0; i < filename_filters.size( ); i++ ) { if( matched_filters.count( filename_filters[ i ] ) == 0 ) cout << "warning: found no files matching '" << filename_filters[ i ] << "'" << endl; } } } } if( is_append ) { #ifdef ZLIB_SUPPORT gzFile igzf; ifstream inpf; if( !use_zlib ) inpf.open( filename.c_str( ) ); else igzf = gzopen( filename.c_str( ), "rb" ); if( ( use_zlib && !igzf ) || ( !use_zlib && !inpf ) ) throw runtime_error( "unable to open file '" + filename + "' for input" ); #else ifstream inpf( filename.c_str( ) ); if( !inpf ) throw runtime_error( "unable to open file '" + filename + "' for input" ); #endif encoding_type old_encoding; #ifndef ZLIB_SUPPORT check_file_header( inpf, filename, old_encoding ); #else check_file_header( inpf, filename, old_encoding, use_zlib, igzf ); #endif if( old_encoding != encoding ) throw runtime_error( "*** cannot combine different bundle data encoding types ***" ); string next; int line = 0; int count = 0; int line_size = 0; int file_data_lines = 0; int64_t raw_file_size = 0; bool skip_existing_file = false; string current_sub_path; while( true ) { if( raw_file_size ) { if( skip_existing_file ) { #ifdef ZLIB_SUPPORT if( use_zlib ) gzseek( igzf, raw_file_size, SEEK_CUR ); else inpf.seekg( raw_file_size, ios::cur ); #else inpf.seekg( raw_file_size, ios::cur ); #endif raw_file_size = 0; } else { int64_t chunk = 0; while( raw_file_size > 0 ) { char buffer[ c_buffer_size ]; int count = c_buffer_size; if( raw_file_size < c_buffer_size ) count = raw_file_size; #ifdef ZLIB_SUPPORT if( use_zlib ) { if( !gzread( igzf, buffer, count ) ) throw runtime_error( "reading zlib input" ); } else { if( inpf.rdbuf( )->sgetn( buffer, count ) != count ) throw runtime_error( "reading file input" ); } #else if( inpf.rdbuf( )->sgetn( buffer, count ) != count ) throw runtime_error( "reading file input" ); #endif if( !is_quieter && ++chunk % c_progress_lines == 0 ) { if( line == c_progress_lines ) cout << ' '; cout << '.'; cout.flush( ); } #ifndef ZLIB_SUPPORT outf.rdbuf( )->sputn( buffer, count ); if( !outf.good( ) ) throw runtime_error( "unexpected bad output file stream" ); #else if( !use_zlib ) { outf.rdbuf( )->sputn( buffer, count ); if( !outf.good( ) ) throw runtime_error( "unexpected bad output file stream" ); } else if( !gzwrite( gzf, buffer, count ) ) throw runtime_error( "writing zlib block" ); #endif raw_file_size -= count; } if( !is_quieter ) cout << endl; continue; } } #ifdef ZLIB_SUPPORT if( use_zlib ) { if( !read_zlib_line( igzf, next, false ) ) break; } else if( !getline( inpf, next ) ) break; #else if( !getline( inpf, next ) ) break; #endif ++line; if( file_data_lines ) { --file_data_lines; if( count == 0 ) line_size = unescaped( next ).size( ); // NOTE: If skipping a file then there is no need to actually // read the data so by determining the line size of the first // line (after unescaping) it is safe to "seek" one byte less // forwards and then read the remainder of the line (the size // of this will depend upon how much escaping is being used). if( skip_existing_file && line_size && file_data_lines > 1 ) { #ifdef ZLIB_SUPPORT if( use_zlib ) gzseek( igzf, line_size - 1, SEEK_CUR ); else inpf.seekg( line_size - 1, ios::cur ); #else inpf.seekg( line_size - 1, ios::cur ); #endif } if( ++count % c_progress_lines == 0 && !is_quieter && !skip_existing_file ) { if( count == c_progress_lines ) cout << ' '; cout << '.'; cout.flush( ); } if( !is_quieter && !skip_existing_file && file_data_lines == 0 ) cout << endl; if( !skip_existing_file ) { #ifndef ZLIB_SUPPORT outf << line << '\n'; #else if( !use_zlib ) outf << next << '\n'; else write_zlib_line( gzf, next ); #endif } } else { string::size_type pos = next.find( ' ' ); if( pos != 1 ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); char type( next[ 0 ] ); string next_line( next ); if( type == c_type_file ) { next.erase( 0, 2 ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); if( encoding == e_encoding_type_raw ) raw_file_size = unformat_bytes( next.substr( 0, pos ) ); else { int num_lines( atoi( next.substr( 0, pos ).c_str( ) ) ); if( num_lines < 0 ) throw runtime_error( "invalid number of lines " + to_string( num_lines ) + " specified in line #" + to_string( line ) ); file_data_lines = num_lines; } next.erase( 0, pos + 1 ); string::size_type pos = next.find_last_of( " " ); if( pos == string::npos ) throw runtime_error( "unexpected file entry format in line #" + to_string( line ) ); string check = next.substr( pos + 1 ); next.erase( pos ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected file entry format in line #" + to_string( line ) ); string rwx_perms( next.substr( 0, pos ) ); next.erase( 0, pos + 1 ); count = 0; if( is_delete ) { bool matched = false; vector< string >& exprs( all_filespecs[ c_delete_dummy_path ] ); string next_path( current_sub_path + '/' + next ); for( size_t i = 0; i < exprs.size( ); i++ ) { if( wildcard_match( exprs[ i ], next_path ) ) { if( !is_quieter ) cout << "*kill* \"" << next << "\"" << endl; ++num_deleted; matched = true; break; } } if( matched ) { skip_existing_file = true; continue; } } pos = current_sub_path.find( '/' ); if( pos != string::npos ) next = current_sub_path.substr( pos + 1 ) + '/' + next; if( file_names.count( next ) ) { skip_existing_file = true; continue; } else { skip_existing_file = false; if( !is_quieter ) cout << "append \"" << next << "\""; file_names.insert( next ); g_md5.update( ( unsigned char* )check.c_str( ), check.length( ) ); } } else if( type == c_type_directory ) { next.erase( 0, 2 ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); string::size_type cpos = next.find_last_of( ' ' ); if( cpos == pos || cpos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); string check( next.substr( cpos + 1 ) ); next.erase( cpos ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); int next_level( atoi( next.substr( 0, pos ).c_str( ) ) ); next.erase( 0, pos + 1 ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); string rwx_perms( next.substr( 0, pos ) ); next.erase( 0, pos + 1 ); if( is_delete && all_filespecs.empty( ) ) { for( int i = first_arg + 2; i < argc; i++ ) all_filespecs[ c_delete_dummy_path ].push_back( next + '/' + string( argv[ i ] ) ); } current_sub_path = next; if( file_names.count( next ) ) continue; else { pos = next.find( '/' ); if( !is_quieter && pos != string::npos ) cout << "append \"" << next.substr( pos + 1 ) << "/\"\n"; file_names.insert( next ); g_md5.update( ( unsigned char* )check.c_str( ), check.length( ) ); } } else if( type == c_type_checksum ) break; else throw runtime_error( "unexpected entry type '" + to_string( type ) + "' found in line #" + to_string( line ) ); #ifndef ZLIB_SUPPORT outf << next_line << '\n'; #else if( !use_zlib ) outf << next_line << '\n'; else write_zlib_line( gzf, next_line ); #endif } } #ifdef ZLIB_SUPPORT if( use_zlib ) gzclose( igzf ); #endif } g_md5.finalize( ); ostringstream osstr; auto_ptr< char > ap_digest( g_md5.hex_digest( ) ); osstr << "C " << ap_digest.get( ); #ifndef ZLIB_SUPPORT outf << osstr.str( ) << '\n'; #else if( !use_zlib ) outf << osstr.str( ) << '\n'; else write_zlib_line( gzf, osstr.str( ) ); #endif #ifdef ZLIB_SUPPORT if( use_zlib ) gzclose( gzf ); #endif if( !use_zlib ) { outf.flush( ); if( !outf.good( ) ) throw runtime_error( "unexpected write failure for output file '" + filename + "'" ); } } if( is_append ) { if( !file_remove( filename ) || rename( output_filename.c_str( ), filename.c_str( ) ) != 0 ) throw runtime_error( "unable to replace original '" + filename + "' with '" + output_filename + "'" ); if( is_delete && !is_quieter && num_deleted == 0 ) cout << "warning: found no matching files to delete" << endl; } else if( matched_filters.empty( ) ) { file_remove( filename ); throw runtime_error( "*** nothing to do ***" ); } if( !is_quiet ) cout << "==> finished bundling '" << filename << "'" << endl; } catch( exception& x ) { cerr << "error: " << x.what( ) << endl; return 1; } return 0; }
int main( int argc, char* argv[ ] ) { int first_arg = 0; bool junk = false; bool prune = false; bool include = false; bool use_zlib = false; bool is_quiet = false; bool list_only = false; bool overwrite = false; bool is_quieter = false; if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-i" ) { ++first_arg; junk = true; } else if( string( argv[ first_arg + 1 ] ) == "-j" ) { ++first_arg; include = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-l" ) { ++first_arg; list_only = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-o" ) { ++first_arg; overwrite = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-p" ) { ++first_arg; prune = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-q" ) { ++first_arg; is_quiet = true; } } if( argc > first_arg + 1 ) { if( string( argv[ first_arg + 1 ] ) == "-qq" ) { ++first_arg; is_quiet = true; is_quieter = true; } } if( !is_quiet ) cout << "unbundle v0.1d\n"; if( ( argc - first_arg < 2 ) || string( argv[ 1 ] ) == "?" || string( argv[ 1 ] ) == "/?" || string( argv[ 1 ] ) == "-?" ) { cout << "usage: unbundle [-i|-j] [-l] [-o] [-p] [-q[q]] <fname> [<fspec1> [<fspec2> [...]]] [-x <fspec1> [...]] [-d <directory>]" << endl; cout << "\nwhere: -i to include top level directory and -j to junk all directories" << endl; cout << " and: -l to list rather than create all matching files and directories" << endl; cout << " and: -o to overwrite existing files and -p to prune empty directories" << endl; cout << " and: -q for quiet mode (-qq to suppress all output apart from errors)" << endl; cout << " and: -x identifies one or more filespecs that are to be excluded" << endl; cout << " also: -d <directory> to set a directory origin for output" << endl; return 0; } #ifdef __GNUG__ umask( DEFAULT_UMASK ); #endif try { string filename( argv[ first_arg + 1 ] ); if( !filename.empty( ) && filename[ 0 ] == '-' ) throw runtime_error( "unknown or bad option '" + filename + "' use -? to see options" ); if( filename.length( ) > 3 && filename.substr( filename.length( ) - 3 ) == string( c_zlib_extension ) ) { #ifdef ZLIB_SUPPORT use_zlib = true; #else throw runtime_error( "this program has not been compiled with ZLIB support" ); #endif } string::size_type pos = filename.find( '.' ); if( pos == string::npos || _access( filename.c_str( ), 0 ) != 0 ) filename += c_default_extension; #ifdef ZLIB_SUPPORT if( _access( filename.c_str( ), 0 ) != 0 ) { use_zlib = true; filename += c_zlib_extension; } gzFile gzf; ifstream inpf; if( !use_zlib ) inpf.open( filename.c_str( ) ); else gzf = gzopen( filename.c_str( ), "rb" ); if( ( use_zlib && !gzf ) || ( !use_zlib && !inpf ) ) throw runtime_error( "unable to open file '" + filename + "' for input" ); #else ifstream inpf( filename.c_str( ) ); if( !inpf ) throw runtime_error( "unable to open file '" + filename + "' for input" ); #endif if( !is_quiet && !list_only ) cout << "==> started unbundling '" << filename << "'\n"; bool get_exclude_filespecs = false; string destination_directory; bool get_destination_directory = false; vector< string > filename_filters; vector< string > exclude_filename_filters; for( int i = first_arg + 2; i < argc; i++ ) { string next( argv[ i ] ); if( !next.empty( ) && next[ 0 ] == '-' ) { if( next == "-d" && !get_destination_directory ) { next.erase( ); get_destination_directory = true; } else if( next == "-x" && !get_exclude_filespecs ) { next.erase( ); get_exclude_filespecs = true; } else throw runtime_error( "unknown or bad option '" + next + "' use -? to see options" ); } if( !next.empty( ) ) { if( get_destination_directory && destination_directory.empty( ) ) { destination_directory = next; #ifndef _WIN32 if( destination_directory[ destination_directory.size( ) - 1 ] != '/' ) destination_directory += '/'; #else if( destination_directory[ destination_directory.size( ) - 1 ] != '/' && destination_directory[ destination_directory.size( ) - 1 ] != '\\' && destination_directory[ destination_directory.size( ) - 1 ] != ':' ) destination_directory += '/'; replace( destination_directory, "\\", "/" ); #endif } else if( get_exclude_filespecs ) exclude_filename_filters.push_back( next ); else filename_filters.push_back( next ); } } int level = -1; bool is_first = false; string next_file; string rwx_perms; int line_size = 0; int file_data_lines = 0; int64_t raw_file_size = 0; stack< string > paths; deque< string > create_directories; map< string, string > directory_perms; set< string > created; set< string > matched_filters; auto_ptr< ofstream > ap_ofstream; MD5 md5; string next; string next_md5; size_t line = 1; size_t count = 0; bool finished = false; bool replace_all = false; bool replace_none = false; encoding_type encoding; string top_level_directory; int progress = c_progress_lines; #ifndef ZLIB_SUPPORT check_file_header( inpf, filename, encoding ); #else check_file_header( inpf, filename, encoding, use_zlib, gzf ); #endif while( true ) { if( raw_file_size ) { if( !ap_ofstream.get( ) ) { #ifdef ZLIB_SUPPORT if( use_zlib ) gzseek( gzf, raw_file_size, SEEK_CUR ); else inpf.seekg( raw_file_size, ios::cur ); #else inpf.seekg( raw_file_size, ios::cur ); #endif raw_file_size = 0; } else { int64_t chunk = 0; while( raw_file_size > 0 ) { char buffer[ c_buffer_size ]; int count = c_buffer_size; if( raw_file_size < c_buffer_size ) count = raw_file_size; #ifdef ZLIB_SUPPORT if( use_zlib ) { if( !gzread( gzf, buffer, count ) ) throw runtime_error( "reading zlib input" ); } else { if( inpf.rdbuf( )->sgetn( buffer, count ) != count ) throw runtime_error( "reading file input" ); } #else if( inpf.rdbuf( )->sgetn( buffer, count ) != count ) throw runtime_error( "reading file input" ); #endif if( !is_quieter && ++chunk % c_progress_lines == 0 ) { if( line == c_progress_lines ) cout << ' '; cout << '.'; cout.flush( ); } md5.update( ( unsigned char* )buffer, count ); ap_ofstream->rdbuf( )->sputn( buffer, count ); if( !ap_ofstream->good( ) ) throw runtime_error( "unexpected bad output file stream" ); raw_file_size -= count; } md5.finalize( ); auto_ptr< char > ap_digest( md5.hex_digest( ) ); if( next_md5 != string( ap_digest.get( ) ) ) cerr << "*** error: file '" << next_file << "' failed MD5 digest check ***" << endl; ap_ofstream.reset( ); file_perms( next_file, rwx_perms ); if( !is_quieter ) cout << endl; continue; } } #ifdef ZLIB_SUPPORT if( use_zlib ) { if( !read_zlib_line( gzf, next ) ) break; } else if( !getline( inpf, next ) ) break; #else if( !getline( inpf, next ) ) break; #endif ++line; if( next.empty( ) ) throw runtime_error( "unexpected empty line #" + to_string( line ) ); if( file_data_lines ) { --file_data_lines; if( count == 0 ) { line_size = unescaped( next ).size( ); if( line_size >= 1048576 ) // i.e. 1 MB progress = 2; else progress = c_progress_lines; } // NOTE: If skipping a file then there is no need to actually // read the data so by determining the line size of the first // line (after unescaping) it is safe to "seek" one byte less // forwards and then read the remainder of the line (the size // of this will depend upon how much escaping is being used). if( !ap_ofstream.get( ) && line_size && file_data_lines > 1 ) { #ifdef ZLIB_SUPPORT if( use_zlib ) gzseek( gzf, line_size - 1, SEEK_CUR ); else inpf.seekg( line_size - 1, ios::cur ); #else inpf.seekg( line_size - 1, ios::cur ); #endif } if( ++count % progress == 0 && !is_quieter && ap_ofstream.get( ) ) { if( count == progress ) cout << ' '; cout << '.'; cout.flush( ); } if( !is_quieter && ap_ofstream.get( ) && file_data_lines == 0 ) cout << endl; if( ap_ofstream.get( ) ) { string fdata; if( use_zlib ) fdata = next; else if( encoding != e_encoding_type_b64 ) fdata = unescaped_line( next ); else fdata = base64::decode( next ); if( ap_ofstream->rdbuf( )->sputn( fdata.c_str( ), fdata.length( ) ) != ( int )fdata.length( ) ) throw runtime_error( "write failed for file '" + next_file + "'" ); md5.update( ( unsigned char* )fdata.c_str( ), fdata.length( ) ); if( file_data_lines == 0 ) { ap_ofstream->flush( ); if( !ap_ofstream->good( ) ) throw runtime_error( "flush failed for file '" + next_file + "'" ); ap_ofstream->close( ); ap_ofstream.reset( ); file_perms( next_file, rwx_perms ); md5.finalize( ); auto_ptr< char > ap_digest( md5.hex_digest( ) ); if( next_md5 != string( ap_digest.get( ) ) ) cerr << "*** error: file '" << next_file << "' failed MD5 digest check ***" << endl; } } continue; } if( finished ) throw runtime_error( "unexpected end of file not found at line #" + to_string( line ) ); string::size_type pos = next.find( ' ' ); if( pos != 1 ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); char type( next[ 0 ] ); if( type == c_type_file ) { if( is_first ) throw runtime_error( "unexpected file entry in line #" + to_string( line ) ); md5.init( ); next.erase( 0, 2 ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); if( encoding == e_encoding_type_raw ) raw_file_size = unformat_bytes( next.substr( 0, pos ) ); else { int num_lines( atoi( next.substr( 0, pos ).c_str( ) ) ); if( num_lines < 0 ) throw runtime_error( "invalid number of lines " + to_string( num_lines ) + " specified in line #" + to_string( line ) ); file_data_lines = num_lines; } next.erase( 0, pos + 1 ); string::size_type pos = next.find_last_of( " " ); if( pos == string::npos ) throw runtime_error( "unexpected file entry format in line #" + to_string( line ) ); next_md5 = next.substr( pos + 1 ); next.erase( pos ); g_md5.update( ( unsigned char* )next_md5.c_str( ), next_md5.length( ) ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected file entry format in line #" + to_string( line ) ); rwx_perms = next.substr( 0, pos ); next.erase( 0, pos + 1 ); string test_file( next ); if( !paths.empty( ) ) test_file = paths.top( ) + "/" + next; if( junk ) next_file = destination_directory + next; else next_file = destination_directory + test_file; md5.update( ( unsigned char* )rwx_perms.c_str( ), rwx_perms.length( ) ); md5.update( ( unsigned char* )next.c_str( ), next.length( ) ); bool matched = false; if( filename_filters.empty( ) ) matched = true; else { for( size_t i = 0; i < filename_filters.size( ); i++ ) { string wildcard( filename_filters[ i ] ); string::size_type pos = wildcard.find( "/" ); if( pos == string::npos ) { pos = test_file.find_last_of( "/" ); if( pos != string::npos ) test_file.erase( 0, pos + 1 ); } else if( junk ) { if( wildcard.find( top_level_directory + "/" ) != 0 ) wildcard = top_level_directory + "/" + wildcard; } if( wildcard_match( wildcard, test_file ) ) { matched = true; matched_filters.insert( filename_filters[ i ] ); break; } } } if( !exclude_filename_filters.empty( ) ) { for( size_t i = 0; i < exclude_filename_filters.size( ); i++ ) { string wildcard( exclude_filename_filters[ i ] ); string::size_type pos = wildcard.find( "/" ); if( pos == string::npos ) { pos = test_file.find_last_of( "/" ); if( pos != string::npos ) test_file.erase( 0, pos + 1 ); } else if( junk ) { if( wildcard.find( top_level_directory + "/" ) != 0 ) wildcard = top_level_directory + "/" + wildcard; } if( wildcard_match( wildcard, test_file ) ) { matched = false; break; } } } if( matched && !list_only && !overwrite && !replace_all && file_exists( next_file ) ) { bool replace = false; if( !is_quiet && !replace_none ) { char ch; string prompt( "File '" + next_file + "' already exists. Replace [y/n/A/N]? " ); while( true ) { ch = get_char( prompt.c_str( ) ); if( ch == 'A' ) replace_all = true; else if( ch == 'N' ) replace_none = true; if( ch == 'y' || ch == 'A' ) replace = true; if( replace || replace_all || replace_none || ch == 'n' ) { cout << ch << '\n'; break; } } } if( !replace ) { matched = false; if( is_quieter ) cerr << "*** error: file '" << next_file << "' already exists ***" << endl; } } count = 0; if( matched ) create_all_directories( create_directories, directory_perms, destination_directory, list_only, is_quieter ); if( !matched ) ap_ofstream.reset( ); else if( list_only ) { ap_ofstream.reset( ); cout << next_file << endl; } else { if( !is_quieter ) cout << "extracting \"" << next_file << "\""; ap_ofstream = auto_ptr< ofstream >( new ofstream( next_file.c_str( ), ios::out | ios::binary ) ); if( !*ap_ofstream.get( ) ) throw runtime_error( "unable to open file '" + next_file + "' for output" ); } } else if( type == c_type_directory ) { next.erase( 0, 2 ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); string::size_type cpos = next.find_last_of( ' ' ); if( cpos == pos || cpos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); string check( next.substr( cpos + 1 ) ); next.erase( cpos ); int next_level( atoi( next.substr( 0, pos ).c_str( ) ) ); if( next_level > level ) { if( next_level != level + 1 ) throw runtime_error( "expecting level " + to_string( level + 1 ) + " but found " + to_string( next_level ) + " in line #" + to_string( line ) ); level = next_level; } else { if( next_level < 0 ) throw runtime_error( "invalid level " + to_string( next_level ) + " found in line #" + to_string( line ) ); if( !include || create_directories.size( ) > 1 ) { size_t test_level( next_level ); if( next_level > 0 && !include ) --test_level; while( create_directories.size( ) > test_level ) create_directories.pop_back( ); } level = next_level; while( ( int )paths.size( ) > level ) paths.pop( ); } next.erase( 0, pos + 1 ); pos = next.find( ' ' ); if( pos == string::npos ) throw runtime_error( "unexpected format in line #" + to_string( line ) ); string rwx_perms( next.substr( 0, pos ) ); next.erase( 0, pos + 1 ); string path_name( next ); if( top_level_directory.empty( ) ) top_level_directory = path_name; MD5 md5; md5.update( ( unsigned char* )rwx_perms.c_str( ), rwx_perms.length( ) ); md5.update( ( unsigned char* )path_name.c_str( ), path_name.length( ) ); md5.finalize( ); auto_ptr< char > ap_digest( md5.hex_digest( ) ); if( check != string( ap_digest.get( ) ) ) cerr << "*** error: directory '" << path_name << "' failed MD5 digest check ***" << endl; g_md5.update( ( unsigned char* )ap_digest.get( ), 32 ); if( include || level > 0 ) { if( !include ) { string::size_type pos = path_name.find( '/' ); if( pos == string::npos ) throw runtime_error( "unexpected path_name '" + path_name + " found in line #" + to_string( line ) ); path_name.erase( 0, pos + 1 ); } if( !junk && !created.count( path_name ) ) { created.insert( path_name ); create_directories.push_back( path_name ); directory_perms.insert( make_pair( path_name, rwx_perms ) ); if( !prune ) create_all_directories( create_directories, directory_perms, destination_directory, list_only, is_quieter ); } paths.push( path_name ); } is_first = false; } else if( type == c_type_checksum ) { g_md5.finalize( ); auto_ptr< char > ap_digest( g_md5.hex_digest( ) ); next.erase( 0, 2 ); if( next != string( ap_digest.get( ) ) ) cerr << "*** error: bundle file failed MD5 digest check ***" << endl; finished = true; } else throw runtime_error( "unexpected entry type '" + to_string( type ) + "' found in line #" + to_string( line ) ); } if( !is_quieter ) { for( size_t i = 0; i < filename_filters.size( ); i++ ) { if( matched_filters.count( filename_filters[ i ] ) == 0 ) cout << "warning: found no files matching '" << filename_filters[ i ] << "'" << endl; } } if( !finished ) cerr << "*** error: final MD5 digest not found (file truncated?) ***" << endl; #ifdef ZLIB_SUPPORT if( use_zlib && !gzeof( gzf ) ) throw runtime_error( "unexpected error occurred whilst reading '" + filename + "' for input" ); #endif if( !use_zlib && !inpf.eof( ) ) throw runtime_error( "unexpected error occurred whilst reading '" + filename + "' for input" ); if( !is_quiet && !list_only ) cout << "==> finished unbundling '" << filename << "'" << endl; } catch( exception& x ) { cerr << "error: " << x.what( ) << endl; return 1; } return 0; }