+Archive* AddPk3Dir( const char* fullpath ){
+ if ( g_numDirs == VFS_MAXDIRS ) return 0;
+
+ strncpy( g_strDirs[g_numDirs], fullpath, PATH_MAX );
+ g_strDirs[g_numDirs][PATH_MAX] = '\0';
+ g_numDirs++;
+
+ {
+ archive_entry_t entry;
+ entry.name = fullpath;
+ entry.archive = OpenArchive( fullpath );
+ entry.is_pakfile = false;
+ g_archives.push_back( entry );
+
+ return entry.archive;
+ }
+}
+
+// for unvanquished
+
+bool IsUnvanquished(){
+ return strncmp( GlobalRadiant().getGameFile(), "unvanquished", 12 ) == 0;
+}
+
+struct pakfile_path_t
+{
+ CopiedString fullpath; // full pak dir or pk3dir name
+ bool is_pakfile; // defines is it .pk3dir or .pk3 file
+};
+
+typedef std::pair<CopiedString, pakfile_path_t> PakfilePathsKV;
+typedef std::map<CopiedString, pakfile_path_t> PakfilePaths; // key must have no extension, only name
+
+static PakfilePaths g_pakfile_paths;
+
+void AddUnvPak( const char* name, const char* fullpath, bool is_pakfile ){
+ pakfile_path_t pakfile_path;
+ pakfile_path.fullpath = fullpath;
+ pakfile_path.is_pakfile = is_pakfile;
+ g_pakfile_paths.insert( PakfilePathsKV( name, pakfile_path ) );
+}
+
+// Comparaison function for version numbers
+// Implementation is based on dpkg's version comparison code (verrevcmp() and order())
+// http://anonscm.debian.org/gitweb/?p=dpkg/dpkg.git;a=blob;f=lib/dpkg/version.c;hb=74946af470550a3295e00cf57eca1747215b9311
+static int char_weight(char c){
+ if (std::isdigit(c))
+ return 0;
+ else if (std::isalpha(c))
+ return c;
+ else if (c == '~')
+ return -1;
+ else if (c)
+ return c + 256;
+ else
+ return 0;
+}
+
+static int VersionCmp(const char* a, const char* b){
+ while (*a || *b) {
+ int firstDiff = 0;
+
+ while ((*a && !std::isdigit(*a)) || (*b && !std::isdigit(*b))) {
+ int ac = char_weight(*a);
+ int bc = char_weight(*b);
+
+ if (ac != bc)
+ return ac - bc;
+
+ a++;
+ b++;
+ }
+
+ while (*a == '0')
+ a++;
+ while (*b == '0')
+ b++;
+
+ while (std::isdigit(*a) && std::isdigit(*b)) {
+ if (firstDiff == 0)
+ firstDiff = *a - *b;
+ a++;
+ b++;
+ }
+
+ if (std::isdigit(*a))
+ return 1;
+ if (std::isdigit(*b))
+ return -1;
+ if (firstDiff)
+ return firstDiff;
+ }
+
+ return false;
+}
+
+// takes name without ext, returns without ext
+static const char* GetLatestVersionOfUnvPak( const char* name ){
+ const char* maxversion = 0;
+ const char* result = 0;
+ const char* pakname;
+ const char* pakversion;
+ int namelen = string_length( name );
+
+ for ( PakfilePaths::iterator i = g_pakfile_paths.begin(); i != g_pakfile_paths.end(); ++i )
+ {
+ pakname = i->first.c_str();
+ if ( strncmp( pakname, name, namelen ) != 0 || pakname[namelen] != '_' ) continue;
+ pakversion = pakname + (namelen + 1);
+ if ( maxversion == 0 || VersionCmp( pakversion, maxversion ) > 0 ){
+ maxversion = pakversion;
+ result = pakname;
+ }
+ }
+ return result;
+}
+
+// release string after using
+static char* GetCurrentMapPakName(){
+ char* mapdir;
+ char* mapname;
+ int mapnamelen;
+ char* result = 0;
+
+ mapname = string_clone( GlobalRadiant().getMapName() );
+ mapnamelen = string_length( mapname );
+
+ mapdir = strrchr( mapname, '/' );
+ if ( mapdir ) {
+ mapdir -= 12;
+ if ( strncmp( mapdir, ".pk3dir/maps/", 13 ) == 0 ) {
+ *mapdir = '\0';
+ mapdir = strrchr( mapname, '/' );
+ if ( mapdir ) mapdir++;
+ else mapdir = mapname;
+ result = string_clone( mapdir );
+ }
+ }
+
+ string_release( mapname, mapnamelen );
+ return result;
+
+}
+
+// prevent loading duplicates or circular references
+static Archives g_loaded_unv_paks;
+
+// actual pak adding on initialise, deferred from InitDirectory
+// Unvanquished filesystem doesn't need load all paks it finds
+static void LoadPakWithDeps( const char* pakname ){
+ const char* und = strrchr( pakname, '_' );
+ if ( !und ) pakname = GetLatestVersionOfUnvPak( pakname );
+ if ( !pakname || g_loaded_unv_paks.find( pakname ) != g_loaded_unv_paks.end() ) return;
+
+ PakfilePaths::iterator i = g_pakfile_paths.find( pakname );
+ if ( i == g_pakfile_paths.end() ) return;
+
+ Archive* arc;
+ if ( i->second.is_pakfile ){
+ arc = InitPakFile( FileSystemQ3API_getArchiveModules(), i->second.fullpath.c_str() );
+ } else {
+ arc = AddPk3Dir( i->second.fullpath.c_str() );
+ }
+ g_loaded_unv_paks.insert( pakname );
+
+ ArchiveTextFile* depsFile = arc->openTextFile( "DEPS" );
+ if ( !depsFile ) return;
+
+ {
+ TextLinesInputStream<TextInputStream> istream = depsFile->getInputStream();
+
+ CopiedString line;
+ const char* c;
+ const char* p_name;
+ const char* p_name_end;
+ const char* p_version;
+ const char* p_version_end;
+ while ( line = istream.readLine(), string_length( line.c_str() ) ) {
+ c = line.c_str();
+ while ( std::isspace( *c ) && *c != '\0' ) ++c;
+ p_name = c;
+ while ( !std::isspace( *c ) && *c != '\0' ) ++c;
+ p_name_end = c;
+ while ( std::isspace( *c ) && *c != '\0' ) ++c;
+ p_version = c;
+ while ( !std::isspace( *c ) && *c != '\0' ) ++c;
+ p_version_end = c;
+
+ if ( p_name_end - p_name == 0 ) continue;
+ if ( p_version_end - p_version == 0 ) {
+ const char* p_pakname;
+ CopiedString name_final = CopiedString( StringRange( p_name, p_name_end ) );
+ p_pakname = GetLatestVersionOfUnvPak( name_final.c_str() );
+ if ( !p_pakname ) continue;
+ LoadPakWithDeps( p_pakname );
+ } else {
+ int len = ( p_name_end - p_name ) + ( p_version_end - p_version ) + 1;
+ char* p_pakname = string_new( len );
+ strncpy( p_pakname, p_name, p_name_end - p_name );
+ p_pakname[ p_name_end - p_name ] = '\0';
+ strcat( p_pakname, "_" );
+ strncat( p_pakname, p_version, p_version_end - p_version );
+ LoadPakWithDeps( p_pakname );
+ string_release( p_pakname, len );
+ }
+ }
+ }
+
+ depsFile->release();
+}
+
+// end for unvanquished
+