summaryrefslogtreecommitdiff
path: root/source/core/slang-archive-file-system.h
blob: 6b4fe9e5162cf68094c7b51d70ace4ecb2b6b7c9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#ifndef SLANG_ARCHIVE_FILE_SYSTEM_H
#define SLANG_ARCHIVE_FILE_SYSTEM_H

#include "slang-basic.h"

#include "../../slang-com-ptr.h"

#include "slang-compression-system.h"

#include "slang-string-slice-pool.h"

namespace Slang
{

class ArchiveFileSystem : public RefObject, public ISlangMutableFileSystem
{
public:
        /// Loads an archive. 
    virtual SlangResult loadArchive(const void* archive, size_t archiveSizeInBytes) = 0;
        /// Get as an archive (that can be saved to disk)
        /// NOTE! If the blob is not owned, it's contents can be invalidated by any call to a method of the file system or loss of scope
    virtual SlangResult storeArchive(bool blobOwnsContent, ISlangBlob** outBlob) = 0;
        /// Set the compression - used for any subsequent items added
    virtual void setCompressionStyle(const CompressionStyle& style) = 0;
};

/* Maps an UnownedStringSlice to an index. All substrings are held internally in a StringSlicePool, and so
owned by the type. */
class StringSliceIndexMap
{
public:
        /// An index that identifies a key value pair. 
    typedef Index CountIndex;

        /// Adds a key, value pair. Returns the CountIndex of the pair.
        /// If there is already a value stored for the key it is replaced.
    CountIndex add(const UnownedStringSlice& key, Index valueIndex);

        /// Finds or adds the slice. If the slice is added the defaultValueIndex is set.
        /// If not the index associated with the slice remains the same.
        /// Returns the CountIndex where the key,value pair are stored
    CountIndex findOrAdd(const UnownedStringSlice& key, Index defaultValueIndex);

        /// Gets the index associated with the key. Returns -1 if there is no associated index.
    SLANG_FORCE_INLINE Index getValue(const UnownedStringSlice& key);

        /// Get the amount of pairs in the map
    Index getCount() const { return m_indexMap.getCount(); }

        /// Get the slice and the index at the specified index
    SLANG_INLINE KeyValuePair<UnownedStringSlice, Index> getAt(CountIndex countIndex) const;
    
        /// Clear the contents of the map
    void clear();

        /// Get the key at the specified index
    UnownedStringSlice getKeyAt(CountIndex index) const { return m_pool.getSlice(StringSlicePool::Handle(index)); }
        /// Get the value at the specified index
    Index& getValueAt(CountIndex index) { return m_indexMap[index]; }

        /// Get the amount of key,value pairs
    Index getCount() { return m_indexMap.getCount(); }

        /// Ctor
    StringSliceIndexMap() :
        m_pool(StringSlicePool::Style::Empty)
    {
    }

protected:
    StringSlicePool m_pool;     ///< Pool holds the substrings
    List<Index> m_indexMap;     ///< Maps a pool index to the output index
};

// ---------------------------------------------------------------------------
Index StringSliceIndexMap::getValue(const UnownedStringSlice& key)
{
    const Index poolIndex = m_pool.findIndex(key);
    return (poolIndex >= 0) ? m_indexMap[poolIndex] : -1;
}

// ---------------------------------------------------------------------------
KeyValuePair<UnownedStringSlice, Index> StringSliceIndexMap::getAt(CountIndex countIndex) const
{
    KeyValuePair<UnownedStringSlice, Index> pair;
    pair.Key = m_pool.getSlice(StringSlicePool::Handle(countIndex));
    pair.Value = m_indexMap[countIndex];
    return pair;
}


/* This class helps to find the contents and/or existence of an implicit directory.This finds the contents of a directory.

This is achieved by using a path prefix that any contained path must at least match. If the remainder of the path contains a folder
 - detectable because it's not a leaf and so contains a delimiter - that directory is added. As a sub folder may contain many
 files, and the directory itself may also be defined, it is necessary to dedup. The deduping is handled by the StringSliceIndexMap. */
class ImplicitDirectoryCollector
{
public:
    
    enum class State
    {
        None,                   ///< Neither the directory or content have been found
        DirectoryExists,        ///< The directory exists
        HasContent,             ///< If it has content, the directory must exist
    };

        /// Get the current state
    State getState() const { return (m_map.getCount() > 0) ? State::HasContent : (m_directoryExists ? State::DirectoryExists : State::None); }
        /// True if collector at least has the specified state
    bool hasState(State state) { return Index(getState()) >= Index(state); }

        /// Set that it exists
    void setDirectoryExists(bool directoryExists) { m_directoryExists = directoryExists; }
        /// Get if it exists (implicitly or explicitly)
    bool getDirectoryExists() const { return m_directoryExists || m_map.getCount() > 0; }

        /// True if the path matches the prefix
    bool hasPrefix(const UnownedStringSlice& path) const { return path.startsWith(m_prefix.getUnownedSlice()); }

        /// True if the directory has content
    bool hasContent() const { return m_map.getCount() > 0; }

        /// Gets the remainder or path after the prefix
    UnownedStringSlice getRemainder(const UnownedStringSlice& path) const
    {
        SLANG_ASSERT(hasPrefix(path));
        return UnownedStringSlice(path.begin() + m_prefix.getLength(), path.end());
    }

        /// Add a remaining path
    void addRemainingPath(SlangPathType pathType, const UnownedStringSlice& inPathRemainder);
        /// Add a path
    void addPath(SlangPathType pathType, const UnownedStringSlice& canonicalPath);
        /// Enumerate the contents
    SlangResult enumerate(FileSystemContentsCallBack callback, void* userData);

        /// Ctor
    ImplicitDirectoryCollector(const String& canonicalPath, bool directoryExists = false);

    protected:
    StringSliceIndexMap m_map;
    String m_prefix;
    bool m_directoryExists;
};


SlangResult loadArchiveFileSystem(const void* data, size_t dataSizeInBytes, RefPtr<ArchiveFileSystem>& outFileSystem);
SlangResult createArchiveFileSystem(SlangArchiveType type, RefPtr<ArchiveFileSystem>& outFileSystem);

}

#endif