Browse Source

Add ResourceCache.Scan to search for files across resource dirs and packages. Add Stream wrapper for File

ResourceNameIterator added to allow passing the results to C#. A more general solution for passing collections of strings and other non-RefCounted objects. Perhaps a templated equivalent of this refcounted wrapper kept in the AtomicNETNative project.
Matt Benic 9 years ago
parent
commit
cb93fe1b7a

+ 112 - 1
Script/AtomicNET/AtomicNET/IO/File.cs

@@ -1,12 +1,123 @@
-
 using System;
+using System.IO;
 using System.Runtime.InteropServices;
 
 namespace AtomicEngine
 {
     public partial class File : AObject, Deserializer, Serializer
     {
+        private class Stream : System.IO.Stream
+        {
+            private File file;
+
+            public override bool CanRead
+            {
+                get
+                {
+                    return file.Mode == FileMode.FILE_READ || file.Mode == FileMode.FILE_READWRITE;
+                }
+            }
+
+            public override bool CanSeek
+            {
+                get
+                {
+                    return true;
+                }
+            }
+
+            public override bool CanWrite
+            {
+                get
+                {
+                    return file.Mode == FileMode.FILE_WRITE ||
+                        file.Mode == FileMode.FILE_READWRITE ||
+                        file.Mode == FileMode.FILE_APPEND;
+                }
+            }
+
+            public override long Length
+            {
+                get
+                {
+                    return file.GetSize();
+                }
+            }
+
+            public override long Position
+            {
+                get
+                {
+                    return file.GetPosition();
+                }
+
+                set
+                {
+                    file.Seek((uint)value);
+                }
+            }
 
+            public Stream(File file)
+            {
+                if (file == null)
+                    throw new ArgumentNullException(nameof(file));
+
+                this.file = file;
+            }
+
+            public override void Flush()
+            {
+                file.Flush();
+            }
+
+            public override int Read(byte[] buffer, int offset, int count)
+            {
+                if (buffer == null)
+                    throw new ArgumentNullException(nameof(buffer));
+                if (offset + count > buffer.Length)
+                    throw new IndexOutOfRangeException("buffer.Length");
+
+                byte[] readData = file.Read(count);
+                int limit = Math.Min(count, readData.Length);
+                Array.Copy(readData, 0, buffer, offset, limit);
+
+                return limit;
+            }
+
+            public override long Seek(long offset, SeekOrigin origin)
+            {
+                if (origin == SeekOrigin.Current)
+                {
+                    offset += Position;
+                }
+                else if (origin == SeekOrigin.End)
+                {
+                    offset += Length;
+                }
+
+                return file.Seek((uint)offset);
+            }
+
+            public override void SetLength(long value)
+            {
+                throw new InvalidOperationException();
+            }
+
+            public override void Write(byte[] buffer, int offset, int count)
+            {
+                if (buffer == null)
+                    throw new ArgumentNullException(nameof(buffer));
+                if (offset + count >= buffer.Length)
+                    throw new IndexOutOfRangeException("buffer.Length");
+
+                file.Write(buffer, offset, count);
+            }
+        }
+
+        public System.IO.Stream ToStream()
+        {
+            return new Stream(this);
+        }
 
         /// <summary>
         /// Read bytes from the file. Return array of bytes of the length actually read (can be 0 length)

+ 11 - 1
Script/AtomicNET/AtomicNET/Resource/ResourceCache.cs

@@ -14,6 +14,16 @@ namespace AtomicEngine
             return (T)GetResource(typeof(T).Name, path);
         }
 
-    }
+        public System.IO.Stream GetFileStream(string name, bool sendEventOnFailure = true)
+        {
+            File file = GetFile(name, sendEventOnFailure);
+            if (file != null &&
+                file.IsOpen())
+            {
+                return file.ToStream();
+            }
 
+            return null;
+        }
+    }
 }

+ 32 - 0
Script/AtomicNET/AtomicNET/Resource/ResourceNameIterator.cs

@@ -0,0 +1,32 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+
+namespace AtomicEngine
+{
+
+    public partial class ResourceNameIterator : IEnumerator<string>, IEnumerable<string>
+    {
+        object IEnumerator.Current
+        {
+            get
+            {
+                return Current;
+            }
+        }
+
+        public IEnumerator<string> GetEnumerator()
+        {
+            return this;
+        }
+
+        void IDisposable.Dispose() { }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return this;
+        }
+    }
+
+
+}

+ 1 - 1
Script/Packages/Atomic/Resource.json

@@ -1,7 +1,7 @@
 {
 	"name" : "Resource",
 	"sources" : ["Source/Atomic/Resource"],
-	"classes" : ["Resource", "ResourceCache", "XMLFile", "PListFile", "JSONFile", "Image"],
+	"classes" : ["Resource", "ResourceCache", "XMLFile", "PListFile", "JSONFile", "Image", "ResourceNameIterator"],
 	"overloads": {
 		"Image": {
 			"GetPixel": ["int", "int"],

+ 29 - 0
Source/Atomic/IO/PackageFile.cpp

@@ -22,6 +22,7 @@
 
 #include "../Precompiled.h"
 
+#include "../IO/FileSystem.h"
 #include "../IO/File.h"
 #include "../IO/Log.h"
 #include "../IO/PackageFile.h"
@@ -155,4 +156,32 @@ const PackageEntry* PackageFile::GetEntry(const String& fileName) const
     return 0;
 }
 
+// ATOMIC BEGIN
+void PackageFile::Scan(Vector<String>& result, const String& pathName, const String& filter, bool recursive) const
+{
+    result.Clear();
+
+    String sanitizedPath = GetSanitizedPath(pathName);
+    String filterExtension = filter.Substring(filter.FindLast('.'));
+    if (filterExtension.Contains('*'))
+        filterExtension.Clear();
+
+    const StringVector& entryNames = GetEntryNames();
+    for (StringVector::ConstIterator i = entryNames.Begin(); i != entryNames.End(); ++i)
+    {
+        String entryName = GetSanitizedPath(*i);
+        if ((filterExtension.Empty() || entryName.EndsWith(filterExtension)) &&
+            entryName.StartsWith(sanitizedPath))
+        {
+            String fileName = entryName.Substring(sanitizedPath.Length());
+            if (fileName.StartsWith("\\") || fileName.StartsWith("/"))
+                fileName = fileName.Substring(1, fileName.Length() - 1);
+            if (!recursive && (fileName.Contains("\\") || fileName.Contains("/")))
+                continue;
+
+            result.Push(fileName);
+        }
+    }
+}
+// ATOMIC END
 }

+ 6 - 0
Source/Atomic/IO/PackageFile.h

@@ -85,6 +85,12 @@ public:
     /// Return list of file names in the package.
     const Vector<String> GetEntryNames() const { return entries_.Keys(); }
 
+    // ATOMIC BEGIN
+    
+    /// Scan package for specified files.
+    void Scan(Vector<String>& result, const String& pathName, const String& filter, bool recursive) const;
+    
+    // ATOMIC END
 private:
     /// File entries.
     HashMap<String, PackageEntry> entries_;

+ 50 - 0
Source/Atomic/Resource/ResourceCache.cpp

@@ -1196,4 +1196,54 @@ void RegisterResourceLibrary(Context* context)
     XMLFile::RegisterObject(context);
 }
 
+// ATOMIC BEGIN
+ResourceNameIterator::ResourceNameIterator()
+{
+    Reset();
+}
+
+const String& ResourceNameIterator::GetCurrent()
+{
+    return (index_ < filenames_.Size()) ?
+        filenames_[index_] :
+        String::EMPTY;
+}
+
+bool ResourceNameIterator::MoveNext()
+{
+    return ++index_ < filenames_.Size();
+}
+
+void ResourceNameIterator::Reset()
+{
+    index_ = -1;
+}
+
+void ResourceCache::Scan(Vector<String>& result, const String& pathName, const String& filter, unsigned flags, bool recursive) const
+{
+    Vector<String> interimResult;
+
+    for (unsigned i = 0; i < packages_.Size(); ++i)
+    {
+        packages_[i]->Scan(interimResult, pathName, filter, recursive);
+        result.Insert(result.End(), interimResult);
+    }
+
+    FileSystem* fileSystem = GetSubsystem<FileSystem>();
+    for (unsigned i = 0; i < resourceDirs_.Size(); ++i)
+    {
+        fileSystem->ScanDir(interimResult, resourceDirs_[i] + pathName, filter, flags, recursive);
+        result.Insert(result.End(), interimResult);
+    }
+}
+
+SharedPtr<ResourceNameIterator> ResourceCache::Scan(const String& pathName, const String& filter, unsigned flags, bool recursive) const
+{
+    SharedPtr<ResourceNameIterator> enumerator(new ResourceNameIterator());
+    Scan(enumerator->filenames_, pathName, filter, flags, recursive);
+
+    return enumerator;
+}
+// ATOMIC END
+
 }

+ 22 - 0
Source/Atomic/Resource/ResourceCache.h

@@ -79,6 +79,23 @@ public:
     /// Process the resource request and optionally modify the resource name string. Empty name string means the resource is not found or not allowed.
     virtual void Route(String& name, StringHash type, ResourceRequest requestType) = 0;
 };
+
+/// Helper class to expose resource iteration to script
+class ResourceNameIterator : public RefCounted
+{
+    ATOMIC_REFCOUNTED(ResourceNameIterator);
+public:
+    ResourceNameIterator();
+
+    const String& GetCurrent();
+    bool MoveNext();
+    void Reset();
+
+    Vector<String> filenames_;
+private:
+    unsigned index_;
+};
+
 // ATOMIC END
 
 /// %Resource cache subsystem. Loads resources on demand and stores them for later access.
@@ -222,6 +239,11 @@ public:
     unsigned GetNumResourceDirs() const { return resourceDirs_.Size(); }
     /// Get resource directory at a given index
     const String& GetResourceDir(unsigned index) const { return index < resourceDirs_.Size() ? resourceDirs_[index] : String::EMPTY; }
+    
+    /// Scan for specified files.
+    void Scan(Vector<String>& result, const String& pathName, const String& filter, unsigned flags, bool recursive) const;
+    /// Scan specified files, returning them as an iterator
+    SharedPtr<ResourceNameIterator> Scan(const String& pathName, const String& filter, unsigned flags, bool recursive) const;
 
     // ATOMIC END