Skip to content

Commit

Permalink
Added search path flag SPF_NO_DECEND
Browse files Browse the repository at this point in the history
ResourceNamespace search paths are now defined including a set of
flags which govern how the path will be interpreted.

SPF_NO_DECEND means that only resources in the base of the search
target will be included when populating the namespace. Otherwise,
all resources below the base of the search target will be included.
  • Loading branch information
danij-deng committed Jan 7, 2012
1 parent e90eb4e commit a3bd6b9
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 66 deletions.
26 changes: 22 additions & 4 deletions doomsday/engine/portable/include/resourcenamespace.h
Expand Up @@ -38,6 +38,13 @@ typedef enum {

#define VALID_RESOURCENAMESPACE_SEARCHPATHGROUP(g) ((g) >= SPG_OVERRIDE && (g) < SEARCHPATHGROUP_COUNT)

/**
* @defgroup searchPathFlags Search Path Flags
* @{
*/
#define SPF_NO_DECEND 0x1 /// Do not decend into branches when populating paths.
/**@}*/

/**
* Resource Namespace.
*
Expand All @@ -47,10 +54,15 @@ typedef enum {
#define RESOURCENAMESPACE_HASHSIZE 512
typedef unsigned short resourcenamespace_namehash_key_t;

typedef struct {
int flags; /// @see searchPathFlags
Uri* uri;
} resourcenamespace_searchpath_t;

typedef struct {
/// Sets of search paths known by this namespace.
/// Each set is in order of greatest-importance, right to left.
Uri** _searchPaths[SEARCHPATHGROUP_COUNT];
resourcenamespace_searchpath_t* _searchPaths[SEARCHPATHGROUP_COUNT];
uint _searchPathsCount[SEARCHPATHGROUP_COUNT];

/// Name hash table.
Expand All @@ -73,12 +85,13 @@ void ResourceNamespace_Clear(resourcenamespace_t* rnamespace);
/**
* Add a new path to this namespace.
*
* @param flags @see searchPathFlags
* @param path New unresolved path to add.
* @param group Group to add this path to. @see resourcenamespace_searchpathgroup_t
* @return @c true if the path is correctly formed and present in the namespace.
*/
boolean ResourceNamespace_AddSearchPath(resourcenamespace_t* rn, const Uri* path,
resourcenamespace_searchpathgroup_t group);
boolean ResourceNamespace_AddSearchPath(resourcenamespace_t* rn, int flags,
const Uri* path, resourcenamespace_searchpathgroup_t group);

/**
* Clear search paths in this namespace.
Expand All @@ -87,14 +100,19 @@ boolean ResourceNamespace_AddSearchPath(resourcenamespace_t* rn, const Uri* path
void ResourceNamespace_ClearSearchPaths(resourcenamespace_t* rn, resourcenamespace_searchpathgroup_t group);

/**
* Compose the list of search paths into a @a delimited string.
* Compose the list of search paths into a delimited string.
*
* @param delimiter Discreet paths will be delimited by this character.
* @return Resultant string which should be released with Str_Delete().
*/
ddstring_t* ResourceNamespace_ComposeSearchPathList2(resourcenamespace_t* rn, char delimiter);
ddstring_t* ResourceNamespace_ComposeSearchPathList(resourcenamespace_t* rn); /*delimiter= ';'*/

int ResourceNamespace_IterateSearchPaths2(resourcenamespace_t* rn,
int (*callback) (const Uri* uri, int flags, void* paramaters), void* paramaters);
int ResourceNamespace_IterateSearchPaths(resourcenamespace_t* rn,
int (*callback) (const Uri* uri, int flags, void* paramaters)); /*paramaters=NULL*/

/**
* Add a new named resource into the namespace. Multiple names for a given
* resource may coexist however duplicates are automatically pruned.
Expand Down
10 changes: 8 additions & 2 deletions doomsday/engine/portable/include/sys_reslocator.h
Expand Up @@ -139,8 +139,14 @@ resourcenamespace_t* F_CreateResourceNamespace(const char* name,
FileDirectory* directory, ddstring_t* (*composeHashNameFunc) (const ddstring_t* path),
resourcenamespace_namehash_key_t (*hashNameFunc) (const ddstring_t* name), byte flags);

boolean F_AddSearchPathToResourceNamespace(resourcenamespaceid_t rni, const Uri* uri,
resourcenamespace_searchpathgroup_t group);
/**
* @param rni Unique identifier of the namespace to add to.
* @param flags @see searchPathFlags
* @param searchPath Uri representing the search path to be added.
* @param group Group to add the new search path to.
*/
boolean F_AddSearchPathToResourceNamespace(resourcenamespaceid_t rni, int flags,
const Uri* searchPath, resourcenamespace_searchpathgroup_t group);

const ddstring_t* F_ResourceNamespaceName(resourcenamespaceid_t rni);

Expand Down
2 changes: 1 addition & 1 deletion doomsday/engine/portable/src/dd_main.c
Expand Up @@ -1503,7 +1503,7 @@ int DD_Main(void)
dir = Dir_ConstructFromPathDir(filePath);
searchPath = Uri_NewWithPath2(Dir_Path(dir), RC_PACKAGE);

F_AddSearchPathToResourceNamespace(rnId, searchPath, SPG_DEFAULT);
F_AddSearchPathToResourceNamespace(rnId, 0, searchPath, SPG_DEFAULT);

Uri_Delete(searchPath);
Dir_Delete(dir);
Expand Down
11 changes: 7 additions & 4 deletions doomsday/engine/portable/src/def_read.c
Expand Up @@ -815,12 +815,15 @@ static int DED_ReadData(ded_t* ded, const char* buffer, const char* _sourceFile)

if(ISTOKEN("ModelPath"))
{
Uri* newSearchPath;

READSTR(label);
CHECKSC;
{ Uri* newUri = Uri_NewWithPath2(label, RC_NULL);
F_AddSearchPathToResourceNamespace(F_DefaultResourceNamespaceForClass(RC_MODEL), newUri, SPG_EXTRA);
Uri_Delete(newUri);
}

newSearchPath = Uri_NewWithPath2(label, RC_NULL);
F_AddSearchPathToResourceNamespace(F_DefaultResourceNamespaceForClass(RC_MODEL),
0, newSearchPath, SPG_EXTRA);
Uri_Delete(newSearchPath);
}

if(ISTOKEN("Header"))
Expand Down
72 changes: 59 additions & 13 deletions doomsday/engine/portable/src/resourcenamespace.c
Expand Up @@ -119,7 +119,7 @@ static void appendSearchPathsInGroup(resourcenamespace_t* rn,

for(i = 0; i < rn->_searchPathsCount[group]; ++i)
{
ddstring_t* path = Uri_ComposePath(rn->_searchPaths[group][i]);
ddstring_t* path = Uri_ComposePath(rn->_searchPaths[group][i].uri);
Str_Appendf(pathList, "%s%c", Str_Text(path), delimiter);
Str_Delete(path);
}
Expand Down Expand Up @@ -190,49 +190,70 @@ void ResourceNamespace_Clear(resourcenamespace_t* rn)
clearNameHash(rn);
}

boolean ResourceNamespace_AddSearchPath(resourcenamespace_t* rn, const Uri* newUri,
resourcenamespace_searchpathgroup_t group)
boolean ResourceNamespace_AddSearchPath(resourcenamespace_t* rn, int flags,
const Uri* searchPath, resourcenamespace_searchpathgroup_t group)
{
uint i, j;
assert(rn && newUri && VALID_RESOURCENAMESPACE_SEARCHPATHGROUP(group));
assert(rn);

if(Str_IsEmpty(Uri_Path(newUri)) || !Str_CompareIgnoreCase(Uri_Path(newUri), "/"))
return false; // Not suitable.
// Is this suitable?
if(!searchPath || Str_IsEmpty(Uri_Path(searchPath)) || !Str_CompareIgnoreCase(Uri_Path(searchPath), "/"))
return false;

if(!VALID_RESOURCENAMESPACE_SEARCHPATHGROUP(group))
{
#if _DEBUG
Con_Message("ResourceNamespace::AddSearchPath: Invalid SearchPathGroup %i, ignoring.\n", (int)group);
#endif
return false;
}

// Have we seen this path already (we don't want duplicates)?

for(i = 0; i < SEARCHPATHGROUP_COUNT; ++i)
for(j = 0; j < rn->_searchPathsCount[i]; ++j)
{
if(Uri_Equality(rn->_searchPaths[i][j], newUri))
if(Uri_Equality(rn->_searchPaths[i][j].uri, searchPath))
{
rn->_searchPaths[i][j].flags = flags;
return true;
}
}

rn->_searchPaths[group] = (Uri**) realloc(rn->_searchPaths[group],
sizeof **rn->_searchPaths * ++rn->_searchPathsCount[group]);
rn->_searchPaths[group] = realloc(rn->_searchPaths[group],
sizeof(**rn->_searchPaths) * ++rn->_searchPathsCount[group]);
if(!rn->_searchPaths[group])
Con_Error("ResourceNamespace::AddExtraSearchPath: Failed on reallocation of %lu bytes for "
Con_Error("ResourceNamespace::AddSearchPath: Failed on reallocation of %lu bytes for "
"searchPath list.", (unsigned long) sizeof **rn->_searchPaths * (rn->_searchPathsCount[group]-1));

// Prepend to the path list - newer paths have priority.
if(rn->_searchPathsCount[group] > 1)
memmove(rn->_searchPaths[group] + 1, rn->_searchPaths[group],
sizeof(*rn->_searchPaths[group]) * (rn->_searchPathsCount[group]-1));
rn->_searchPaths[group][0] = Uri_NewCopy(newUri);
rn->_searchPaths[group][0].uri = Uri_NewCopy(searchPath);
rn->_searchPaths[group][0].flags = flags;

return true;
}

void ResourceNamespace_ClearSearchPaths(resourcenamespace_t* rn, resourcenamespace_searchpathgroup_t group)
{
uint i;
assert(rn && VALID_RESOURCENAMESPACE_SEARCHPATHGROUP(group));
assert(rn);

if(!VALID_RESOURCENAMESPACE_SEARCHPATHGROUP(group))
{
#if _DEBUG
Con_Message("ResourceNamespace::ClearSearchPaths: Invalid SearchPathGroup %i, ignoring.\n", (int)group);
#endif
return;
}

if(!rn->_searchPaths[group]) return;

for(i = 0; i < rn->_searchPathsCount[group]; ++i)
{
Uri_Delete(rn->_searchPaths[group][i]);
Uri_Delete(rn->_searchPaths[group][i].uri);
}
free(rn->_searchPaths[group]);
rn->_searchPaths[group] = 0;
Expand All @@ -249,6 +270,31 @@ ddstring_t* ResourceNamespace_ComposeSearchPathList(resourcenamespace_t* rn)
return ResourceNamespace_ComposeSearchPathList2(rn, ';');
}

int ResourceNamespace_IterateSearchPaths2(resourcenamespace_t* rn,
int (*callback) (const Uri* uri, int flags, void* paramaters), void* paramaters)
{
int result = 0;
assert(rn);
if(callback)
{
uint i, j;
for(i = 0; i < SEARCHPATHGROUP_COUNT; ++i)
for(j = 0; j < rn->_searchPathsCount[i]; ++j)
{
resourcenamespace_searchpath_t* path = &rn->_searchPaths[i][j];
result = callback(path->uri, path->flags, paramaters);
if(result) return result;
}
}
return result;
}

int ResourceNamespace_IterateSearchPaths(resourcenamespace_t* rn,
int (*callback) (const Uri* uri, int flags, void* paramaters))
{
return ResourceNamespace_IterateSearchPaths2(rn, callback, NULL);
}

int ResourceNamespace_Iterate2(resourcenamespace_t* rn, const ddstring_t* name,
int (*callback) (PathDirectoryNode* node, void* paramaters), void* paramaters)
{
Expand Down
90 changes: 48 additions & 42 deletions doomsday/engine/portable/src/sys_reslocator.c
Expand Up @@ -204,7 +204,8 @@ static void resetAllNamespaces(void)
}
}

static void addResourceToNamespace(resourcenamespaceinfo_t* rnInfo, PathDirectoryNode* node)
static void addResourceToNamespace(resourcenamespaceinfo_t* rnInfo,
PathDirectoryNode* node)
{
ddstring_t* name;
assert(rnInfo && node);
Expand Down Expand Up @@ -697,7 +698,7 @@ static void createPackagesResourceNamespace(void)
uint i;
for(i = 0; i < searchPathsCount; ++i)
{
ResourceNamespace_AddSearchPath(rnamespace, searchPaths[i], SPG_DEFAULT);
ResourceNamespace_AddSearchPath(rnamespace, 0, searchPaths[i], SPG_DEFAULT);
}
}

Expand All @@ -714,29 +715,40 @@ void F_CreateNamespacesForFileResourcePaths(void)
const char* name;
const char* optOverridePath;
const char* optFallbackPath;
byte flags;
const char* defaultPaths[NAMESPACEDEF_MAX_SEARCHPATHS];
byte flags; /// @see resourceNamespaceFlags
int searchPathFlags; /// @see searchPathFlags
const char* searchPaths[NAMESPACEDEF_MAX_SEARCHPATHS];
} defs[] = {
{ DEFINITIONS_RESOURCE_NAMESPACE_NAME, NULL, NULL, 0,
{ "$(Game.DefsPath)/$(Game.IdentityKey)/", "$(Game.DefsPath)/", "$(App.DefsPath)/" } },
{ GRAPHICS_RESOURCE_NAMESPACE_NAME, "-gfxdir2", "-gfxdir", 0,
{ "$(App.DataPath)/graphics/" } },
{ MODELS_RESOURCE_NAMESPACE_NAME, "-modeldir2", "-modeldir", RNF_USE_VMAP,
{ "$(Game.DataPath)/models/$(Game.IdentityKey)/", "$(Game.DataPath)/models/" } },
{ SOUNDS_RESOURCE_NAMESPACE_NAME, "-sfxdir2", "-sfxdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/sfx/$(Game.IdentityKey)/", "$(Game.DataPath)/sfx/" } },
{ MUSIC_RESOURCE_NAMESPACE_NAME, "-musdir2", "-musdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/music/$(Game.IdentityKey)/", "$(Game.DataPath)/music/" } },
{ TEXTURES_RESOURCE_NAMESPACE_NAME, "-texdir2", "-texdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/textures/$(Game.IdentityKey)/", "$(Game.DataPath)/textures/" } },
{ FLATS_RESOURCE_NAMESPACE_NAME, "-flatdir2", "-flatdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/flats/$(Game.IdentityKey)/", "$(Game.DataPath)/flats/" } },
{ PATCHES_RESOURCE_NAMESPACE_NAME, "-patdir2", "-patdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/patches/$(Game.IdentityKey)/", "$(Game.DataPath)/patches/" } },
{ LIGHTMAPS_RESOURCE_NAMESPACE_NAME, "-lmdir2", "-lmdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/lightmaps/$(Game.IdentityKey)/", "$(Game.DataPath)/lightmaps/" } },
{ FONTS_RESOURCE_NAMESPACE_NAME, "-fontdir2", "-fontdir", RNF_USE_VMAP,
{ "$(Game.DataPath)/fonts/$(Game.IdentityKey)/", "$(Game.DataPath)/fonts/", "$(App.DataPath)/fonts/" } },
{ DEFINITIONS_RESOURCE_NAMESPACE_NAME, NULL, NULL, 0, 0,
{ "$(Game.DefsPath)/$(Game.IdentityKey)/", "$(Game.DefsPath)/", "$(App.DefsPath)/" }
},
{ GRAPHICS_RESOURCE_NAMESPACE_NAME, "-gfxdir2", "-gfxdir", 0, 0,
{ "$(App.DataPath)/graphics/" }
},
{ MODELS_RESOURCE_NAMESPACE_NAME, "-modeldir2", "-modeldir", RNF_USE_VMAP, 0,
{ "$(Game.DataPath)/models/$(Game.IdentityKey)/", "$(Game.DataPath)/models/" }
},
{ SOUNDS_RESOURCE_NAMESPACE_NAME, "-sfxdir2", "-sfxdir", RNF_USE_VMAP, SPF_NO_DECEND,
{ "$(Game.DataPath)/sfx/$(Game.IdentityKey)/", "$(Game.DataPath)/sfx/" }
},
{ MUSIC_RESOURCE_NAMESPACE_NAME, "-musdir2", "-musdir", RNF_USE_VMAP, SPF_NO_DECEND,
{ "$(Game.DataPath)/music/$(Game.IdentityKey)/", "$(Game.DataPath)/music/" }
},
{ TEXTURES_RESOURCE_NAMESPACE_NAME, "-texdir2", "-texdir", RNF_USE_VMAP, SPF_NO_DECEND,
{ "$(Game.DataPath)/textures/$(Game.IdentityKey)/", "$(Game.DataPath)/textures/" }
},
{ FLATS_RESOURCE_NAMESPACE_NAME, "-flatdir2", "-flatdir", RNF_USE_VMAP, SPF_NO_DECEND,
{ "$(Game.DataPath)/flats/$(Game.IdentityKey)/", "$(Game.DataPath)/flats/" }
},
{ PATCHES_RESOURCE_NAMESPACE_NAME, "-patdir2", "-patdir", RNF_USE_VMAP, SPF_NO_DECEND,
{ "$(Game.DataPath)/patches/$(Game.IdentityKey)/", "$(Game.DataPath)/patches/" }
},
{ LIGHTMAPS_RESOURCE_NAMESPACE_NAME, "-lmdir2", "-lmdir", RNF_USE_VMAP, 0,
{ "$(Game.DataPath)/lightmaps/" }
},
{ FONTS_RESOURCE_NAMESPACE_NAME, "-fontdir2", "-fontdir", RNF_USE_VMAP, SPF_NO_DECEND,
{ "$(Game.DataPath)/fonts/$(Game.IdentityKey)/", "$(Game.DataPath)/fonts/", "$(App.DataPath)/fonts/" }
},
{ NULL }
};
Uri* uri = Uri_New();
Expand All @@ -748,20 +760,20 @@ void F_CreateNamespacesForFileResourcePaths(void)
{ size_t i;
for(i = 0; defs[i].name; ++i)
{
uint j, defaultPathCount;
uint j, searchPathCount;
struct namespacedef_s* def = &defs[i];
FileDirectory* directory = FileDirectory_New();
resourcenamespace_t* rnamespace = F_CreateResourceNamespace(def->name, directory,
F_ComposeHashNameForFilePath, F_HashKeyForFilePathHashName, def->flags);

defaultPathCount = 0;
while(def->defaultPaths[defaultPathCount] && ++defaultPathCount < NAMESPACEDEF_MAX_SEARCHPATHS)
searchPathCount = 0;
while(def->searchPaths[searchPathCount] && ++searchPathCount < NAMESPACEDEF_MAX_SEARCHPATHS)
{}

for(j = 0; j < defaultPathCount; ++j)
for(j = 0; j < searchPathCount; ++j)
{
Uri_SetUri3(uri, def->defaultPaths[j], RC_NULL);
ResourceNamespace_AddSearchPath(rnamespace, uri, SPG_DEFAULT);
Uri_SetUri3(uri, def->searchPaths[j], RC_NULL);
ResourceNamespace_AddSearchPath(rnamespace, def->searchPathFlags, uri, SPG_DEFAULT);
}

if(def->optOverridePath && ArgCheckWith(def->optOverridePath, 1))
Expand All @@ -773,18 +785,18 @@ void F_CreateNamespacesForFileResourcePaths(void)
Str_Init(&path2);
Str_Appendf(&path2, "%s/$(Game.IdentityKey)", path);
Uri_SetUri3(uri, Str_Text(&path2), RC_NULL);
ResourceNamespace_AddSearchPath(rnamespace, uri, SPG_OVERRIDE);
ResourceNamespace_AddSearchPath(rnamespace, def->searchPathFlags, uri, SPG_OVERRIDE);

Uri_SetUri3(uri, path, RC_NULL);
ResourceNamespace_AddSearchPath(rnamespace, uri, SPG_OVERRIDE);
ResourceNamespace_AddSearchPath(rnamespace, def->searchPathFlags, uri, SPG_OVERRIDE);

Str_Free(&path2);
}

if(def->optFallbackPath && ArgCheckWith(def->optFallbackPath, 1))
{
Uri_SetUri3(uri, ArgNext(), RC_NULL);
ResourceNamespace_AddSearchPath(rnamespace, uri, SPG_FALLBACK);
ResourceNamespace_AddSearchPath(rnamespace, def->searchPathFlags, uri, SPG_FALLBACK);
}
}}

Expand Down Expand Up @@ -892,26 +904,20 @@ resourcenamespace_t* F_CreateResourceNamespace(const char* name, FileDirectory*
return rn;
}

boolean F_AddSearchPathToResourceNamespace(resourcenamespaceid_t rni, const Uri* uri,
resourcenamespace_searchpathgroup_t group)
boolean F_AddSearchPathToResourceNamespace(resourcenamespaceid_t rni, int flags,
const Uri* searchPath, resourcenamespace_searchpathgroup_t group)
{
resourcenamespaceinfo_t* info;
errorIfNotInited("F_AddSearchPathToResourceNamespace");
info = getNamespaceInfoForId(rni);
if(ResourceNamespace_AddSearchPath(info->rnamespace, uri, group))
if(ResourceNamespace_AddSearchPath(info->rnamespace, flags, searchPath, group))
{
info->flags |= RNF_IS_DIRTY;
return true;
}
return false;
}

void F_AddResourceToNamespace(resourcenamespaceid_t rni, PathDirectoryNode* node)
{
errorIfNotInited("F_AddResourceToNamespace");
addResourceToNamespace(getNamespaceInfoForId(rni), node);
}

const ddstring_t* F_ResourceNamespaceName(resourcenamespaceid_t rni)
{
return &(getNamespaceInfoForId(rni))->name;
Expand Down

0 comments on commit a3bd6b9

Please sign in to comment.