1 /*
2 Open Asset Import Library (assimp)
3 ----------------------------------------------------------------------
4 
5 Copyright (c) 2006-2012, assimp team
6 All rights reserved.
7 
8 Redistribution and use of this software in source and binary forms,
9 with or without modification, are permitted provided that the
10 following conditions are met:
11 
12 * Redistributions of source code must retain the above
13   copyright notice, this list of conditions and the
14   following disclaimer.
15 
16 * Redistributions in binary form must reproduce the above
17   copyright notice, this list of conditions and the
18   following disclaimer in the documentation and/or other
19   materials provided with the distribution.
20 
21 * Neither the name of the assimp team, nor the names of its
22   contributors may be used to endorse or promote products
23   derived from this software without specific prior
24   written permission of the assimp team.
25 
26 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 
38 ----------------------------------------------------------------------
39 */
40 
41 /** @file  LineSplitter.h
42  *  @brief LineSplitter, a helper class to iterate through all lines
43  *    of a file easily. Works with StreamReader.
44  */
45 #ifndef INCLUDED_LINE_SPLITTER_H
46 #define INCLUDED_LINE_SPLITTER_H
47 
48 #include <stdexcept>
49 
50 #include "StreamReader.h"
51 #include "ParsingUtils.h"
52 
53 namespace Assimp {
54 
55 // ------------------------------------------------------------------------------------------------
56 /** Usage:
57 @code
58 for(LineSplitter splitter(stream);splitter;++splitter) {
59 
60 	if (*splitter == "hi!") {
61 	   ...
62 	}
63     else if (splitter->substr(0,5) == "hello") {
64 	   ...
65 	   // access the third token in the line (tokens are space-separated)
66 	   if (strtol(splitter[2]) > 5) { .. }
67 	}
68 
69 	std::cout << "Current line is: " << splitter.get_index() << std::endl;
70 }
71 @endcode */
72 // ------------------------------------------------------------------------------------------------
73 class LineSplitter
74 {
75 public:
76 
77 	typedef size_t line_idx;
78 
79 public:
80 
81 	// -----------------------------------------
82 	/** construct from existing stream reader
83 	note: trim is *always* assumed true if skyp_empty_lines==true
84 	*/
85 	LineSplitter(StreamReaderLE& stream, bool skip_empty_lines = true, bool trim = true)
stream(stream)86 		: stream(stream)
87 		, swallow()
88 		, skip_empty_lines(skip_empty_lines)
89 		, trim(trim)
90 	{
91 		cur.reserve(1024);
92 		operator++();
93 
94 		idx = 0;
95 	}
96 
97 public:
98 
99 	// -----------------------------------------
100 	/** pseudo-iterator increment */
101 	LineSplitter& operator++() {
102 		if(swallow) {
103 			swallow = false;
104 			return *this;
105 		}
106 
107 		if (!*this) {
108 			throw std::logic_error("End of file, no more lines to be retrieved.");
109 		}
110 
111 		char s;
112 
113 		cur.clear();
114 		while(stream.GetRemainingSize() && (s = stream.GetI1(),1)) {
115 			if (s == '\n' || s == '\r') {
116 				if (skip_empty_lines) {
117 					while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\r' || s == '\n'));
118 					if (stream.GetRemainingSize()) {
119 						stream.IncPtr(-1);
120 					}
121 				}
122 				else {
123 					// skip both potential line terminators but don't read past this line.
124 					if (stream.GetRemainingSize() && (s == '\r' && stream.GetI1() != '\n')) {
125 						stream.IncPtr(-1);
126 					}
127 
128 					if (trim) {
129 						while (stream.GetRemainingSize() && ((s = stream.GetI1()) == ' ' || s == '\t'));
130 						if (stream.GetRemainingSize()) {
131 							stream.IncPtr(-1);
132 						}
133 					}
134 				}
135 
136 				break;
137 			}
138 			cur += s;
139 		}
140 
141 		++idx;
142 		return *this;
143 	}
144 
145 	// -----------------------------------------
146 	LineSplitter& operator++(int) {
147 		return ++(*this);
148 	}
149 
150 	// -----------------------------------------
151 	/** get a pointer to the beginning of a particular token */
152 	const char* operator[] (size_t idx) const {
153 		const char* s = operator->()->c_str();
154 
155 		SkipSpaces(&s);
156 		for(size_t i = 0; i < idx; ++i) {
157 
158 			for(;!IsSpace(*s); ++s) {
159 				if(IsLineEnd(*s)) {
160 					throw std::range_error("Token index out of range, EOL reached");
161 				}
162 			}
163 			SkipSpaces(&s);
164 		}
165 		return s;
166 	}
167 
168 	// -----------------------------------------
169 	/** extract the start positions of N tokens from the current line*/
170 	template <size_t N>
get_tokens(const char * (& tokens)[N])171 	void get_tokens(const char* (&tokens)[N]) const {
172 		const char* s = operator->()->c_str();
173 
174 		SkipSpaces(&s);
175 		for(size_t i = 0; i < N; ++i) {
176 			if(IsLineEnd(*s)) {
177 				throw std::range_error("Token count out of range, EOL reached");
178 			}
179 			tokens[i] = s;
180 
181 			for(;*s && !IsSpace(*s); ++s);
182 			SkipSpaces(&s);
183 		}
184 	}
185 
186 	// -----------------------------------------
187 	/** member access */
188 	const std::string* operator -> () const {
189 		return &cur;
190 	}
191 
192 	std::string operator* () const {
193 		return cur;
194 	}
195 
196 	// -----------------------------------------
197 	/** boolean context */
198 	operator bool() const {
199 		return stream.GetRemainingSize()>0;
200 	}
201 
202 	// -----------------------------------------
203 	/** line indices are zero-based, empty lines are included */
line_idx()204 	operator line_idx() const {
205 		return idx;
206 	}
207 
get_index()208 	line_idx get_index() const {
209 		return idx;
210 	}
211 
212 	// -----------------------------------------
213 	/** access the underlying stream object */
get_stream()214 	StreamReaderLE& get_stream() {
215 		return stream;
216 	}
217 
218 	// -----------------------------------------
219 	/** !strcmp((*this)->substr(0,strlen(check)),check) */
match_start(const char * check)220 	bool match_start(const char* check) {
221 		const size_t len = strlen(check);
222 
223 		return len <= cur.length() && std::equal(check,check+len,cur.begin());
224 	}
225 
226 
227 	// -----------------------------------------
228 	/** swallow the next call to ++, return the previous value. */
swallow_next_increment()229 	void swallow_next_increment() {
230 		swallow = true;
231 	}
232 
233 private:
234 
235 	line_idx idx;
236 	std::string cur;
237 	StreamReaderLE& stream;
238 	bool swallow, skip_empty_lines, trim;
239 };
240 
241 }
242 #endif // INCLUDED_LINE_SPLITTER_H
243