1 #ifndef COMPONENTS_FILES_ESCAPE_HPP
2 #define COMPONENTS_FILES_ESCAPE_HPP
3 
4 #include <queue>
5 
6 #include <components/files/multidircollection.hpp>
7 
8 #include <boost/iostreams/filtering_stream.hpp>
9 #include <boost/filesystem/path.hpp>
10 #include <boost/program_options.hpp>
11 
12 /**
13  * \namespace Files
14  */
15 namespace Files
16 {
17     /**
18     * \struct escape_hash_filter
19     */
20     struct escape_hash_filter : public boost::iostreams::input_filter
21     {
22         static const int sEscape;
23         static const int sHashIdentifier;
24         static const int sEscapeIdentifier;
25 
26         escape_hash_filter();
27         virtual ~escape_hash_filter();
28 
29         template <typename Source> int get(Source & src);
30 
31     private:
32         std::queue<int> mNext;
33 
34         bool mSeenNonWhitespace;
35         bool mFinishLine;
36     };
37 
38     template <typename Source>
get(Source & src)39     int escape_hash_filter::get(Source & src)
40     {
41         if (mNext.empty())
42         {
43             int character = boost::iostreams::get(src);
44             if (character == boost::iostreams::WOULD_BLOCK)
45             {
46                 mNext.push(character);
47             }
48             else if (character == EOF)
49             {
50                 mSeenNonWhitespace = false;
51                 mFinishLine = false;
52                 mNext.push(character);
53             }
54             else if (character == '\n')
55             {
56                 mSeenNonWhitespace = false;
57                 mFinishLine = false;
58                 mNext.push(character);
59             }
60             else if (mFinishLine)
61             {
62                 mNext.push(character);
63             }
64             else if (character == '#')
65             {
66                 if (mSeenNonWhitespace)
67                 {
68                     mNext.push(sEscape);
69                     mNext.push(sHashIdentifier);
70                 }
71                 else
72                 {
73                     //it's fine being interpreted by Boost as a comment, and so is anything afterwards
74                     mNext.push(character);
75                     mFinishLine = true;
76                 }
77             }
78             else if (character == sEscape)
79             {
80                 mNext.push(sEscape);
81                 mNext.push(sEscapeIdentifier);
82             }
83             else
84             {
85                 mNext.push(character);
86             }
87             if (!mSeenNonWhitespace && !isspace(character))
88                 mSeenNonWhitespace = true;
89         }
90         int retval = mNext.front();
91         mNext.pop();
92         return retval;
93     }
94 
95     struct unescape_hash_filter : public boost::iostreams::input_filter
96     {
97         unescape_hash_filter();
98         virtual ~unescape_hash_filter();
99 
100         template <typename Source> int get(Source & src);
101 
102     private:
103         bool expectingIdentifier;
104     };
105 
106     template <typename Source>
get(Source & src)107     int unescape_hash_filter::get(Source & src)
108     {
109         int character;
110         if (!expectingIdentifier)
111             character = boost::iostreams::get(src);
112         else
113         {
114             character = escape_hash_filter::sEscape;
115             expectingIdentifier = false;
116         }
117         if (character == escape_hash_filter::sEscape)
118         {
119             int nextChar = boost::iostreams::get(src);
120             int intended;
121             if (nextChar == escape_hash_filter::sEscapeIdentifier)
122                 intended = escape_hash_filter::sEscape;
123             else if (nextChar == escape_hash_filter::sHashIdentifier)
124                 intended = '#';
125             else if (nextChar == boost::iostreams::WOULD_BLOCK)
126             {
127                 expectingIdentifier = true;
128                 intended = nextChar;
129             }
130             else
131                 intended = '?';
132             return intended;
133         }
134         else
135             return character;
136     }
137 
138     /**
139     * \class EscapeHashString
140     */
141     class EscapeHashString
142     {
143     private:
144         std::string mData;
145     public:
146         static std::string processString(const std::string & str);
147 
148         EscapeHashString();
149         EscapeHashString(const std::string & str);
150         EscapeHashString(const std::string & str, size_t pos, size_t len = std::string::npos);
151         EscapeHashString(const char * s);
152         EscapeHashString(const char * s, size_t n);
153         EscapeHashString(size_t n, char c);
154         template <class InputIterator>
155         EscapeHashString(InputIterator first, InputIterator last);
156 
157         std::string toStdString() const;
158 
159         friend std::ostream & operator<< (std::ostream & os, const EscapeHashString & eHS);
160     };
161 
162     std::istream & operator>> (std::istream & is, EscapeHashString & eHS);
163 
164     struct EscapeStringVector
165     {
166         std::vector<Files::EscapeHashString> mVector;
167 
168         EscapeStringVector();
169         virtual ~EscapeStringVector();
170 
171         std::vector<std::string> toStdStringVector() const;
172     };
173 
174     //boost program options validation
175 
176     void validate(boost::any &v, const std::vector<std::string> &tokens, Files::EscapeHashString * eHS, int a);
177 
178     void validate(boost::any &v, const std::vector<std::string> &tokens, EscapeStringVector *, int);
179 
180     struct EscapePath
181     {
182         boost::filesystem::path mPath;
183 
184         static PathContainer toPathContainer(const std::vector<EscapePath> & escapePathContainer);
185     };
186 
187     typedef std::vector<EscapePath> EscapePathContainer;
188 
189     std::istream & operator>> (std::istream & istream, EscapePath & escapePath);
190 } /* namespace Files */
191 #endif /* COMPONENTS_FILES_ESCAPE_HPP */
192