1 // © 2018 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 
4 #ifndef __FILTERRB_H__
5 #define __FILTERRB_H__
6 
7 #include <list>
8 #include <map>
9 #include <memory>
10 #include <ostream>
11 #include <string>
12 
13 #include "unicode/utypes.h"
14 
15 
16 /**
17  * Represents an absolute path into a resource bundle.
18  * For example: "/units/length/meter"
19  */
20 class ResKeyPath {
21 public:
22     /** Constructs an empty path (top of tree) */
23     ResKeyPath();
24 
25     /** Constructs from a string path */
26     ResKeyPath(const std::string& path, UErrorCode& status);
27 
28     void push(const std::string& key);
29     void pop();
30 
31     const std::list<std::string>& pieces() const;
32 
33   private:
34     std::list<std::string> fPath;
35 };
36 
37 std::ostream& operator<<(std::ostream& out, const ResKeyPath& value);
38 
39 
40 /**
41  * Interface used to determine whether to include or reject pieces of a
42  * resource bundle based on their absolute path.
43  */
44 class PathFilter {
45 public:
46     enum EInclusion {
47         INCLUDE,
48         PARTIAL,
49         EXCLUDE
50     };
51 
52     static const char* kEInclusionNames[];
53 
54     virtual ~PathFilter();
55 
56     /**
57      * Returns an EInclusion on whether or not the given path should be included.
58      *
59      * INCLUDE = include the whole subtree
60      * PARTIAL = recurse into the subtree
61      * EXCLUDE = reject the whole subtree
62      */
63     virtual EInclusion match(const ResKeyPath& path) const = 0;
64 };
65 
66 
67 /**
68  * Implementation of PathFilter for a list of inclusion/exclusion rules.
69  *
70  * The wildcard pattern "*" means that the subsequent filters are applied to
71  * every other tree sharing the same parent.
72  *
73  * For example, given this list of filter rules:
74  */
75 //     -/alabama
76 //     +/alabama/alaska/arizona
77 //     -/fornia/hawaii
78 //     -/mississippi
79 //     +/mississippi/michigan
80 //     +/mississippi/*/maine
81 //     -/mississippi/*/iowa
82 //     +/mississippi/louisiana/iowa
83 /*
84  * You get the following structure:
85  *
86  *     SimpleRuleBasedPathFilter {
87  *       included: PARTIAL
88  *       alabama: {
89  *         included: EXCLUDE
90  *         alaska: {
91  *           included: PARTIAL
92  *           arizona: {
93  *             included: INCLUDE
94  *           }
95  *         }
96  *       }
97  *       fornia: {
98  *         included: PARTIAL
99  *         hawaii: {
100  *           included: EXCLUDE
101  *         }
102  *       }
103  *       mississippi: {
104  *         included: EXCLUDE
105  *         louisiana: {
106  *           included: PARTIAL
107  *           iowa: {
108  *             included: INCLUDE
109  *           }
110  *           maine: {
111  *             included: INCLUDE
112  *           }
113  *         }
114  *         michigan: {
115  *           included: INCLUDE
116  *           iowa: {
117  *             included: EXCLUDE
118  *           }
119  *           maine: {
120  *             included: INCLUDE
121  *           }
122  *         }
123  *         * {
124  *           included: PARTIAL
125  *           iowa: {
126  *             included: EXCLUDE
127  *           }
128  *           maine: {
129  *             included: INCLUDE
130  *           }
131  *         }
132  *       }
133  *     }
134  */
135 class SimpleRuleBasedPathFilter : public PathFilter {
136 public:
137     void addRule(const std::string& ruleLine, UErrorCode& status);
138     void addRule(const ResKeyPath& path, bool inclusionRule, UErrorCode& status);
139 
140     EInclusion match(const ResKeyPath& path) const override;
141 
142     void print(std::ostream& out) const;
143 
144 private:
145     struct Tree {
146 
147         Tree() = default;
148 
149         /** Copy constructor */
150         Tree(const Tree& other);
151 
152         /**
153          * Information on the USER-SPECIFIED inclusion/exclusion.
154          *
155          * INCLUDE = this path exactly matches a "+" rule
156          * PARTIAL = this path does not match any rule, but subpaths exist
157          * EXCLUDE = this path exactly matches a "-" rule
158          */
159         EInclusion fIncluded = PARTIAL;
160         std::map<std::string, Tree> fChildren;
161         std::unique_ptr<Tree> fWildcard;
162 
163         void applyRule(
164             const ResKeyPath& path,
165             std::list<std::string>::const_iterator it,
166             bool inclusionRule,
167             UErrorCode& status);
168 
169         bool isLeaf() const;
170 
171         void print(std::ostream& out, int32_t indent) const;
172     };
173 
174     Tree fRoot;
175 };
176 
177 std::ostream& operator<<(std::ostream& out, const SimpleRuleBasedPathFilter& value);
178 
179 
180 #endif //__FILTERRB_H__
181