[Scummvm-git-logs] scummvm branch-2-7 -> 51ebc14811b154a8afab12ec3294ced9b8f7f70c
lephilousophe
noreply at scummvm.org
Sun Jul 9 19:59:49 UTC 2023
This automated email contains information about 3 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
7bcd28b757 COMMON: Allow to know in which archive file was found in SearchSet
36a0b83ab4 COMMON: Add normalization to Path class
51ebc14811 BACKENDS: OPENGL: Rework shader assets search
Commit: 7bcd28b757b6f7d73b8471d80f7d0e3a7eb0e039
https://github.com/scummvm/scummvm/commit/7bcd28b757b6f7d73b8471d80f7d0e3a7eb0e039
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2023-07-09T21:59:23+02:00
Commit Message:
COMMON: Allow to know in which archive file was found in SearchSet
Changed paths:
common/archive.cpp
common/archive.h
diff --git a/common/archive.cpp b/common/archive.cpp
index bb4c2c10a4e..bea7e2093d4 100644
--- a/common/archive.cpp
+++ b/common/archive.cpp
@@ -279,19 +279,27 @@ int SearchSet::listMembers(ArchiveMemberList &list) const {
return matches;
}
-const ArchiveMemberPtr SearchSet::getMember(const Path &path) const {
+const ArchiveMemberPtr SearchSet::getMember(const Path &path, Archive **container) const {
if (path.empty())
return ArchiveMemberPtr();
ArchiveNodeList::const_iterator it = _list.begin();
for (; it != _list.end(); ++it) {
- if (it->_arc->hasFile(path))
+ if (it->_arc->hasFile(path)) {
+ if (container) {
+ *container = it->_arc;
+ }
return it->_arc->getMember(path);
+ }
}
return ArchiveMemberPtr();
}
+const ArchiveMemberPtr SearchSet::getMember(const Path &path) const {
+ return getMember(path, nullptr);
+}
+
SeekableReadStream *SearchSet::createReadStreamForMember(const Path &path) const {
if (path.empty())
return nullptr;
diff --git a/common/archive.h b/common/archive.h
index 93741e547d9..09d56146605 100644
--- a/common/archive.h
+++ b/common/archive.h
@@ -326,6 +326,8 @@ public:
const ArchiveMemberPtr getMember(const Path &path) const override;
+ const ArchiveMemberPtr getMember(const Path &path, Archive **container) const;
+
/**
* Implement createReadStreamForMember from the Archive base class. The current policy is
* opening the first file encountered that matches the name.
Commit: 36a0b83ab45d593439eb5d47c88b70b3895ecf15
https://github.com/scummvm/scummvm/commit/36a0b83ab45d593439eb5d47c88b70b3895ecf15
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2023-07-09T21:59:23+02:00
Commit Message:
COMMON: Add normalization to Path class
Changed paths:
common/path.cpp
common/path.h
test/common/path.h
diff --git a/common/path.cpp b/common/path.cpp
index 7319896a6aa..5df923fb679 100644
--- a/common/path.cpp
+++ b/common/path.cpp
@@ -20,8 +20,10 @@
*/
#include "common/path.h"
-#include "common/punycode.h"
+
#include "common/hash-str.h"
+#include "common/list.h"
+#include "common/punycode.h"
const char ESCAPER = '/';
const char ESCAPE_SLASH = '+';
@@ -244,6 +246,64 @@ Path Path::join(const char *str, char separator) const {
return temp;
}
+Path Path::normalize() const {
+ if (empty()) {
+ return Path();
+ }
+
+ Common::String::const_iterator cur = _str.begin();
+ const Common::String::const_iterator end = _str.end();
+
+ Common::Path result;
+
+ // If there is a leading slash, preserve that:
+ if (cur != end &&
+ *cur == ESCAPER &&
+ *(cur + 1) == ESCAPE_SEPARATOR) {
+ result._str += DIR_SEPARATOR;
+ cur += 2;
+ // Skip over multiple leading slashes, so "//" equals "/"
+ while (cur != end && *cur == ESCAPER && *(cur + 1) == ESCAPE_SEPARATOR)
+ cur += 2;
+ }
+
+ // Scan for path components till the end of the String
+ List<String> comps;
+ while (cur != end) {
+ Common::String::const_iterator start = cur;
+
+ // Scan till the next path separator resp. the end of the string
+ while (!(*cur == ESCAPER && *(cur + 1) == ESCAPE_SEPARATOR) && cur != end)
+ cur++;
+
+ const String component(start, cur);
+
+ if (component.empty() || component == ".") {
+ // Skip empty components and dot components
+ } else if (!comps.empty() && component == ".." && comps.back() != "..") {
+ // If stack is non-empty and top is not "..", remove top
+ comps.pop_back();
+ } else {
+ // Add the component to the stack
+ comps.push_back(component);
+ }
+
+ // Skip over separator chars
+ while (cur != end && *cur == ESCAPER && *(cur + 1) == ESCAPE_SEPARATOR)
+ cur += 2;
+ }
+
+ // Finally, assemble all components back into a path
+ while (!comps.empty()) {
+ result._str += comps.front();
+ comps.pop_front();
+ if (!comps.empty())
+ result._str += DIR_SEPARATOR;
+ }
+
+ return result;
+}
+
StringArray Path::splitComponents() const {
StringArray res;
String cur;
diff --git a/common/path.h b/common/path.h
index 7cf5530f2ee..a9d89f9d039 100644
--- a/common/path.h
+++ b/common/path.h
@@ -207,6 +207,17 @@ public:
*/
bool matchPattern(const Path& pattern) const;
+ /**
+ * Normalize path to a canonical form. In particular:
+ * - trailing separators are removed: /foo/bar/ -> /foo/bar
+ * - double separators (= empty components) are removed: /foo//bar -> /foo/bar
+ * - dot components are removed: /foo/./bar -> /foo/bar
+ * - double dot components are removed: /foo/baz/../bar -> /foo/bar
+ *
+ * @return the normalized path
+ */
+ Path normalize() const;
+
/**
* Splits into path components. After every component except
* last there is an implied separator. First component is empty
diff --git a/test/common/path.h b/test/common/path.h
index d7c48f3b869..043f19dcea1 100644
--- a/test/common/path.h
+++ b/test/common/path.h
@@ -66,4 +66,33 @@ class PathTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(p2.getParent().toString('#'), "par#nt/dir/fil#");
TS_ASSERT_EQUALS(p2.getParent().getParent().toString('#'), "par#");
}
+
+ void test_normalize() {
+ TS_ASSERT_EQUALS(Common::Path("/", '/').normalize().toString(), "/");
+ TS_ASSERT_EQUALS(Common::Path("/foo/bar", '/').normalize().toString(), "/foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("/foo//bar/", '/').normalize().toString(), "/foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("/foo/./bar", '/').normalize().toString(), "/foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("/foo//./bar//", '/').normalize().toString(), "/foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("/foo//.bar//", '/').normalize().toString(), "/foo/.bar");
+
+ TS_ASSERT_EQUALS(Common::Path("", '/').normalize().toString(), "");
+ TS_ASSERT_EQUALS(Common::Path("foo/bar", '/').normalize().toString(), "foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("foo//bar/", '/').normalize().toString(), "foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("foo/./bar", '/').normalize().toString(), "foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("foo//./bar//", '/').normalize().toString(), "foo/bar");
+ TS_ASSERT_EQUALS(Common::Path("foo//.bar//", '/').normalize().toString(), "foo/.bar");
+
+ TS_ASSERT_EQUALS(Common::Path("..", '/').normalize().toString(), "..");
+ TS_ASSERT_EQUALS(Common::Path("../", '/').normalize().toString(), "..");
+ TS_ASSERT_EQUALS(Common::Path("/..", '/').normalize().toString(), "/..");
+ TS_ASSERT_EQUALS(Common::Path("../bar", '/').normalize().toString(), "../bar");
+ TS_ASSERT_EQUALS(Common::Path("foo//../", '/').normalize().toString(), "");
+ TS_ASSERT_EQUALS(Common::Path("foo/../bar", '/').normalize().toString(), "bar");
+ TS_ASSERT_EQUALS(Common::Path("foo//../bar//", '/').normalize().toString(), "bar");
+ TS_ASSERT_EQUALS(Common::Path("foo//..bar//", '/').normalize().toString(), "foo/..bar");
+
+ TS_ASSERT_EQUALS(Common::Path("foo/../../bar//", '/').normalize().toString(), "../bar");
+ TS_ASSERT_EQUALS(Common::Path("../foo/../bar", '/').normalize().toString(), "../bar");
+ TS_ASSERT_EQUALS(Common::Path("../../foo/bar/", '/').normalize().toString(), "../../foo/bar");
+ }
};
Commit: 51ebc14811b154a8afab12ec3294ced9b8f7f70c
https://github.com/scummvm/scummvm/commit/51ebc14811b154a8afab12ec3294ced9b8f7f70c
Author: Le Philousophe (lephilousophe at users.noreply.github.com)
Date: 2023-07-09T21:59:23+02:00
Commit Message:
BACKENDS: OPENGL: Rework shader assets search
Determine in which archive the shader is located and load assets from
the same archive.
When using a FSNode, use the filesystem code to build the base path.
Use a Path object to store the base path to allow proper join of
components.
Changed paths:
backends/graphics/opengl/pipelines/libretro.cpp
backends/graphics/opengl/pipelines/libretro.h
backends/graphics/opengl/pipelines/libretro/parser.cpp
backends/graphics/opengl/pipelines/libretro/parser.h
backends/graphics/opengl/pipelines/libretro/types.h
diff --git a/backends/graphics/opengl/pipelines/libretro.cpp b/backends/graphics/opengl/pipelines/libretro.cpp
index 552f3d0bb8e..e8b43906542 100644
--- a/backends/graphics/opengl/pipelines/libretro.cpp
+++ b/backends/graphics/opengl/pipelines/libretro.cpp
@@ -44,17 +44,26 @@ namespace OpenGL {
using LibRetro::UniformsMap;
template<typename DecoderType>
-static Graphics::Surface *loadViaImageDecoder(const Common::String &fileName, Common::SearchSet &archSet) {
- Common::SeekableReadStream *stream;
+static Graphics::Surface *loadViaImageDecoder(const Common::Path &fileName, Common::Archive *container, Common::SearchSet &archSet) {
+ Common::SeekableReadStream *stream = nullptr;
- // First try SearchMan, then fallback to filesystem
- if (archSet.hasFile(fileName)) {
- stream = archSet.createReadStreamForMember(fileName);
+ if (container) {
+ // Look first in our current container and fallback on archive set
+ if (container->hasFile(fileName)) {
+ stream = container->createReadStreamForMember(fileName);
+ }
+ if (!stream) {
+ stream = archSet.createReadStreamForMemberNext(fileName, container);
+ }
+ if (!stream) {
+ warning("LibRetroPipeline::loadViaImageDecoder: Invalid file path '%s'", fileName.toString().c_str());
+ return nullptr;
+ }
} else {
Common::FSNode fsnode(fileName);
if (!fsnode.exists() || !fsnode.isReadable() || fsnode.isDirectory()
|| !(stream = fsnode.createReadStream())) {
- warning("LibRetroPipeline::loadViaImageDecoder: Invalid file path '%s'", fileName.c_str());
+ warning("LibRetroPipeline::loadViaImageDecoder: Invalid file path '%s'", fileName.toString().c_str());
return nullptr;
}
}
@@ -80,7 +89,7 @@ static Graphics::Surface *loadViaImageDecoder(const Common::String &fileName, Co
struct ImageLoader {
const char *extension;
- Graphics::Surface *(*load)(const Common::String &fileName, Common::SearchSet &archSet);
+ Graphics::Surface *(*load)(const Common::Path &fileName, Common::Archive *container, Common::SearchSet &archSet);
};
static const ImageLoader s_imageLoaders[] = {
@@ -388,7 +397,7 @@ bool LibRetroPipeline::loadTextures(Common::SearchSet &archSet) {
for (LibRetro::ShaderPreset::TextureArray::const_iterator
i = _shaderPreset->textures.begin(), end = _shaderPreset->textures.end();
i != end; ++i) {
- Texture texture = loadTexture(Common::normalizePath(_shaderPreset->basePath + Common::String("/") + i->fileName, '/'), archSet);
+ Texture texture = loadTexture(_shaderPreset->basePath.join(i->fileName).normalize(), _shaderPreset->container, archSet);
texture.id = i->id;
if (!texture.textureData || !texture.glTexture) {
@@ -451,17 +460,26 @@ bool LibRetroPipeline::loadPasses(Common::SearchSet &archSet) {
for (LibRetro::ShaderPreset::PassArray::const_iterator
i = _shaderPreset->passes.begin(), end = _shaderPreset->passes.end();
i != end; ++i) {
- Common::String fileName(Common::normalizePath(_shaderPreset->basePath + Common::String("/") + i->fileName, '/'));
- Common::SeekableReadStream *stream;
+ Common::Path fileName(_shaderPreset->basePath.join(i->fileName).normalize());
+ Common::SeekableReadStream *stream = nullptr;
- // First try SearchMan, then fallback to filesystem
- if (archSet.hasFile(fileName)) {
- stream = archSet.createReadStreamForMember(fileName);
+ if (_shaderPreset->container) {
+ // Look first in our current container and fallback on archive set
+ if (_shaderPreset->container->hasFile(fileName)) {
+ stream = _shaderPreset->container->createReadStreamForMember(fileName);
+ }
+ if (!stream) {
+ stream = archSet.createReadStreamForMemberNext(fileName, _shaderPreset->container);
+ }
+ if (!stream) {
+ warning("LibRetroPipeline::loadPasses: Invalid file path '%s'", fileName.toString().c_str());
+ return false;
+ }
} else {
Common::FSNode fsnode(fileName);
if (!fsnode.exists() || !fsnode.isReadable() || fsnode.isDirectory()
|| !(stream = fsnode.createReadStream())) {
- warning("LibRetroPipeline::loadPasses: Invalid file path '%s'", fileName.c_str());
+ warning("LibRetroPipeline::loadPasses: Invalid file path '%s'", fileName.toString().c_str());
return false;
}
}
@@ -474,7 +492,7 @@ bool LibRetroPipeline::loadPasses(Common::SearchSet &archSet) {
delete stream;
if (!readSuccess) {
- warning("LibRetroPipeline::loadPasses: Could not read file '%s'", fileName.c_str());
+ warning("LibRetroPipeline::loadPasses: Could not read file '%s'", fileName.toString().c_str());
return false;
}
@@ -530,7 +548,7 @@ bool LibRetroPipeline::loadPasses(Common::SearchSet &archSet) {
shaderFileStart,
};
- if (!shader->loadFromStringsArray(fileName,
+ if (!shader->loadFromStringsArray(fileName.toString(),
ARRAYSIZE(vertexSources), vertexSources,
ARRAYSIZE(fragmentSources), fragmentSources,
g_libretroShaderAttributes)) {
@@ -722,25 +740,26 @@ void LibRetroPipeline::setShaderTexUniforms(const Common::String &prefix, Shader
shader->setUniform(prefix + "TextureSize", Math::Vector2d(texture.getWidth(), texture.getHeight()));
}
-LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fileName, Common::SearchSet &archSet) {
+LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::Path &fileName, Common::Archive *container, Common::SearchSet &archSet) {
+ Common::String baseName(fileName.getLastComponent().toString());
const char *extension = nullptr;
- for (int dotPos = fileName.size() - 1; dotPos >= 0; --dotPos) {
- if (fileName[dotPos] == '.') {
- extension = fileName.c_str() + dotPos + 1;
+ for (int dotPos = baseName.size() - 1; dotPos >= 0; --dotPos) {
+ if (baseName[dotPos] == '.') {
+ extension = baseName.c_str() + dotPos + 1;
break;
}
}
if (!extension) {
- warning("LibRetroPipeline::loadTexture: File name '%s' misses extension", fileName.c_str());
+ warning("LibRetroPipeline::loadTexture: File name '%s' misses extension", fileName.toString().c_str());
return Texture();
}
for (const ImageLoader *loader = s_imageLoaders; loader->extension; ++loader) {
if (!scumm_stricmp(loader->extension, extension)) {
- Graphics::Surface *textureData = loader->load(fileName, archSet);
+ Graphics::Surface *textureData = loader->load(fileName, container, archSet);
if (!textureData) {
- warning("LibRetroPipeline::loadTexture: Loader for '%s' could not load file '%s'", loader->extension, fileName.c_str());
+ warning("LibRetroPipeline::loadTexture: Loader for '%s' could not load file '%s'", loader->extension, fileName.toString().c_str());
return Texture();
}
@@ -751,7 +770,7 @@ LibRetroPipeline::Texture LibRetroPipeline::loadTexture(const Common::String &fi
}
}
- warning("LibRetroPipeline::loadTexture: No loader for file '%s' present", fileName.c_str());
+ warning("LibRetroPipeline::loadTexture: No loader for file '%s' present", fileName.toString().c_str());
return Texture();
}
diff --git a/backends/graphics/opengl/pipelines/libretro.h b/backends/graphics/opengl/pipelines/libretro.h
index 01dd0bba798..5db0c260096 100644
--- a/backends/graphics/opengl/pipelines/libretro.h
+++ b/backends/graphics/opengl/pipelines/libretro.h
@@ -117,7 +117,7 @@ private:
Graphics::Surface *textureData;
GLTexture *glTexture;
};
- Texture loadTexture(const Common::String &fileName, Common::SearchSet &archSet);
+ Texture loadTexture(const Common::Path &fileName, Common::Archive *container, Common::SearchSet &archSet);
typedef Common::Array<Texture> TextureArray;
TextureArray _textures;
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.cpp b/backends/graphics/opengl/pipelines/libretro/parser.cpp
index 718ffb1cb64..f66b3479e56 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.cpp
+++ b/backends/graphics/opengl/pipelines/libretro/parser.cpp
@@ -533,33 +533,42 @@ bool PresetParser::parseParameters() {
return true;
}
-ShaderPreset *parsePreset(const Common::String &shaderPreset, Common::SearchSet &archSet) {
+ShaderPreset *parsePreset(const Common::Path &shaderPreset, Common::SearchSet &archSet) {
Common::SeekableReadStream *stream;
+ Common::Archive *container = nullptr;
+ Common::Path basePath;
// First try SearchMan, then fallback to filesystem
if (archSet.hasFile(shaderPreset)) {
- stream = archSet.createReadStreamForMember(shaderPreset);
+ Common::ArchiveMemberPtr member = archSet.getMember(shaderPreset, &container);
+ stream = member->createReadStream();
+ basePath = shaderPreset.getParent();
} else {
Common::FSNode fsnode(shaderPreset);
if (!fsnode.exists() || !fsnode.isReadable() || fsnode.isDirectory()
|| !(stream = fsnode.createReadStream())) {
- warning("LibRetro Preset Parsing: Invalid file path '%s'", shaderPreset.c_str());
+ warning("LibRetro Preset Parsing: Invalid file path '%s'", shaderPreset.toString().c_str());
return nullptr;
}
+#if defined(WIN32)
+ static const char delimiter = '\\';
+#else
+ static const char delimiter = '/';
+#endif
+ basePath = Common::Path(fsnode.getParent().getPath(), delimiter);
}
- Common::String basePath(Common::firstPathComponents(shaderPreset, '/'));
-
PresetParser parser;
ShaderPreset *shader = parser.parseStream(*stream);
delete stream;
if (!shader) {
- warning("LibRetro Preset Parsing: Error while parsing file '%s': %s", shaderPreset.c_str(), parser.getErrorDesc().c_str());
+ warning("LibRetro Preset Parsing: Error while parsing file '%s': %s", shaderPreset.toString().c_str(), parser.getErrorDesc().c_str());
return nullptr;
}
+ shader->container = container;
shader->basePath = basePath;
return shader;
}
diff --git a/backends/graphics/opengl/pipelines/libretro/parser.h b/backends/graphics/opengl/pipelines/libretro/parser.h
index 8f5b076cfc6..c76792155fd 100644
--- a/backends/graphics/opengl/pipelines/libretro/parser.h
+++ b/backends/graphics/opengl/pipelines/libretro/parser.h
@@ -30,7 +30,7 @@
namespace OpenGL {
namespace LibRetro {
-ShaderPreset *parsePreset(const Common::String &shaderPreset, Common::SearchSet &archSet);
+ShaderPreset *parsePreset(const Common::Path &shaderPreset, Common::SearchSet &archSet);
} // End of namespace LibRetro
} // End of namespace OpenGL
diff --git a/backends/graphics/opengl/pipelines/libretro/types.h b/backends/graphics/opengl/pipelines/libretro/types.h
index 0fcb5f41a00..92054566600 100644
--- a/backends/graphics/opengl/pipelines/libretro/types.h
+++ b/backends/graphics/opengl/pipelines/libretro/types.h
@@ -113,7 +113,8 @@ struct ShaderPass {
};
struct ShaderPreset {
- Common::String basePath;
+ Common::Archive *container;
+ Common::Path basePath;
typedef Common::Array<ShaderTexture> TextureArray;
TextureArray textures;
More information about the Scummvm-git-logs
mailing list