1 /*
2  * Copyright (C) 2011-2020 Daniel Scharrer
3  *
4  * This software is provided 'as-is', without any express or implied
5  * warranty.  In no event will the author(s) be held liable for any damages
6  * arising from the use of this software.
7  *
8  * Permission is granted to anyone to use this software for any purpose,
9  * including commercial applications, and to alter it and redistribute it
10  * freely, subject to the following restrictions:
11  *
12  * 1. The origin of this software must not be misrepresented; you must not
13  *    claim that you wrote the original software. If you use this software
14  *    in a product, an acknowledgment in the product documentation would be
15  *    appreciated but is not required.
16  * 2. Altered source versions must be plainly marked as such, and must not be
17  *    misrepresented as being the original software.
18  * 3. This notice may not be removed or altered from any source distribution.
19  */
20 
21 #include "setup/version.hpp"
22 
23 #include <cstring>
24 #include <algorithm>
25 #include <istream>
26 #include <ostream>
27 
28 #include <boost/version.hpp>
29 #include <boost/static_assert.hpp>
30 #include <boost/lexical_cast.hpp>
31 #include "boost/algorithm/string.hpp"
32 #include <boost/range/begin.hpp>
33 #include <boost/range/end.hpp>
34 #include <boost/range/size.hpp>
35 
36 #include "util/load.hpp"
37 #include "util/log.hpp"
38 
39 namespace setup {
40 
41 namespace {
42 
43 typedef char stored_legacy_version[12];
44 
45 struct known_legacy_version {
46 
47 	char name[13]; // terminating 0 byte is ignored
48 
49 	version_constant version;
50 	version::flags variant;
51 
operator version_constantsetup::__anon124d1def0111::known_legacy_version52 	operator version_constant() const { return version; }
53 
54 };
55 
56 const known_legacy_version legacy_versions[] = {
57 	{ "i1.2.10--16\x1a", INNO_VERSION(1, 2, 10), version::Bits16 },
58 	{ "i1.2.10--32\x1a", INNO_VERSION(1, 2, 10), 0 },
59 };
60 
61 typedef char stored_version[64];
62 
63 struct known_version {
64 
65 	stored_version name;
66 
67 	version_constant version;
68 	version::flags variant;
69 
operator version_constantsetup::__anon124d1def0111::known_version70 	operator version_constant() const { return version; }
71 
72 };
73 
74 const known_version versions[] = {
75 	{ "Inno Setup Setup Data (1.3.3)",                      INNO_VERSION_EXT(1, 3,  3, 0), 0 },
76 	{ "Inno Setup Setup Data (1.3.9)",                      INNO_VERSION_EXT(1, 3,  9, 0), 0 },
77 	{ "Inno Setup Setup Data (1.3.10)",                     INNO_VERSION_EXT(1, 3, 10, 0), 0 },
78 	{ "Inno Setup Setup Data (1.3.10) with ISX (1.3.10)",   INNO_VERSION_EXT(1, 3, 10, 0), version::ISX },
79 	{ "Inno Setup Setup Data (1.3.12) with ISX (1.3.12.1)", INNO_VERSION_EXT(1, 3, 12, 1), version::ISX },
80 	{ "Inno Setup Setup Data (1.3.21)",     /* ambiguous */ INNO_VERSION_EXT(1, 3, 21, 0), 0 },
81 	{ "Inno Setup Setup Data (1.3.21) with ISX (1.3.17)",   INNO_VERSION_EXT(1, 3, 21, 0), version::ISX },
82 	{ "Inno Setup Setup Data (1.3.24)",                     INNO_VERSION_EXT(1, 3, 24, 0), 0 },
83 	{ "Inno Setup Setup Data (1.3.21) with ISX (1.3.24)",   INNO_VERSION_EXT(1, 3, 24, 0), version::ISX },
84 	{ "Inno Setup Setup Data (1.3.25)",                     INNO_VERSION_EXT(1, 3, 25, 0), 0 },
85 	{ "Inno Setup Setup Data (1.3.25) with ISX (1.3.25)",   INNO_VERSION_EXT(1, 3, 25, 0), version::ISX },
86 	{ "Inno Setup Setup Data (2.0.0)",                      INNO_VERSION_EXT(2, 0,  0, 0), 0 },
87 	{ "Inno Setup Setup Data (2.0.1)",      /* ambiguous */ INNO_VERSION_EXT(2, 0,  1, 0), 0 },
88 	{ "Inno Setup Setup Data (2.0.2)",                      INNO_VERSION_EXT(2, 0,  2, 0), 0 },
89 	{ "Inno Setup Setup Data (2.0.5)",                      INNO_VERSION_EXT(2, 0,  5, 0), 0 },
90 	{ "Inno Setup Setup Data (2.0.6a)",                     INNO_VERSION_EXT(2, 0,  6, 0), 0 },
91 	{ "Inno Setup Setup Data (2.0.6a) with ISX (2.0.3)",    INNO_VERSION_EXT(2, 0,  6, 0), version::ISX },
92 	{ "Inno Setup Setup Data (2.0.7)",                      INNO_VERSION_EXT(2, 0,  7, 0), 0 },
93 	{ "Inno Setup Setup Data (2.0.8)",                      INNO_VERSION_EXT(2, 0,  8, 0), 0 },
94 	{ "Inno Setup Setup Data (2.0.8) with ISX (2.0.3)",     INNO_VERSION_EXT(2, 0,  8, 0), version::ISX },
95 	{ "Inno Setup Setup Data (2.0.8) with ISX (2.0.10)",    INNO_VERSION_EXT(2, 0, 10, 0), version::ISX },
96 	{ "Inno Setup Setup Data (2.0.11)",                     INNO_VERSION_EXT(2, 0, 11, 0), 0 },
97 	{ "Inno Setup Setup Data (2.0.11) with ISX (2.0.11)",   INNO_VERSION_EXT(2, 0, 11, 0), version::ISX },
98 	{ "Inno Setup Setup Data (2.0.17)",                     INNO_VERSION_EXT(2, 0, 17, 0), 0 },
99 	{ "Inno Setup Setup Data (2.0.17) with ISX (2.0.11)",   INNO_VERSION_EXT(2, 0, 17, 0), version::ISX },
100 	{ "Inno Setup Setup Data (2.0.18)",                     INNO_VERSION_EXT(2, 0, 18, 0), 0 },
101 	{ "Inno Setup Setup Data (2.0.18) with ISX (2.0.11)",   INNO_VERSION_EXT(2, 0, 18, 0), version::ISX },
102 	{ "Inno Setup Setup Data (3.0.0a)",                     INNO_VERSION_EXT(3, 0,  0, 0), 0 },
103 	{ "Inno Setup Setup Data (3.0.1)",                      INNO_VERSION_EXT(3, 0,  1, 0), 0 },
104 	{ "Inno Setup Setup Data (3.0.1) with ISX (3.0.0)",     INNO_VERSION_EXT(3, 0,  1, 0), version::ISX },
105 	{ "Inno Setup Setup Data (3.0.3)",      /* ambiguous */ INNO_VERSION_EXT(3, 0,  3, 0), 0 },
106 	{ "Inno Setup Setup Data (3.0.3) with ISX (3.0.3)",     INNO_VERSION_EXT(3, 0,  3, 0), version::ISX },
107 	{ "Inno Setup Setup Data (3.0.4)",                      INNO_VERSION_EXT(3, 0,  4, 0), 0 },
108 	{ "My Inno Setup Extensions Setup Data (3.0.4)",        INNO_VERSION_EXT(3, 0,  4, 0), version::ISX },
109 	{ "Inno Setup Setup Data (3.0.5)",                      INNO_VERSION_EXT(3, 0,  5, 0), 0 },
110 	{ "My Inno Setup Extensions Setup Data (3.0.6.1)",      INNO_VERSION_EXT(3, 0,  6, 1), version::ISX },
111 	{ "Inno Setup Setup Data (4.0.0a)",                     INNO_VERSION_EXT(4, 0,  0, 0), 0 },
112 	{ "Inno Setup Setup Data (4.0.1)",                      INNO_VERSION_EXT(4, 0,  1, 0), 0 },
113 	{ "Inno Setup Setup Data (4.0.3)",                      INNO_VERSION_EXT(4, 0,  3, 0), 0 },
114 	{ "Inno Setup Setup Data (4.0.5)",                      INNO_VERSION_EXT(4, 0,  5, 0), 0 },
115 	{ "Inno Setup Setup Data (4.0.9)",                      INNO_VERSION_EXT(4, 0,  9, 0), 0 },
116 	{ "Inno Setup Setup Data (4.0.10)",                     INNO_VERSION_EXT(4, 0, 10, 0), 0 },
117 	{ "Inno Setup Setup Data (4.0.11)",                     INNO_VERSION_EXT(4, 0, 11, 0), 0 },
118 	{ "Inno Setup Setup Data (4.1.0)",                      INNO_VERSION_EXT(4, 1,  0, 0), 0 },
119 	{ "Inno Setup Setup Data (4.1.2)",                      INNO_VERSION_EXT(4, 1,  2, 0), 0 },
120 	{ "Inno Setup Setup Data (4.1.3)",                      INNO_VERSION_EXT(4, 1,  3, 0), 0 },
121 	{ "Inno Setup Setup Data (4.1.4)",                      INNO_VERSION_EXT(4, 1,  4, 0), 0 },
122 	{ "Inno Setup Setup Data (4.1.5)",                      INNO_VERSION_EXT(4, 1,  5, 0), 0 },
123 	{ "Inno Setup Setup Data (4.1.6)",                      INNO_VERSION_EXT(4, 1,  6, 0), 0 },
124 	{ "Inno Setup Setup Data (4.1.8)",                      INNO_VERSION_EXT(4, 1,  8, 0), 0 },
125 	{ "Inno Setup Setup Data (4.2.0)",                      INNO_VERSION_EXT(4, 2,  0, 0), 0 },
126 	{ "Inno Setup Setup Data (4.2.1)",                      INNO_VERSION_EXT(4, 2,  1, 0), 0 },
127 	{ "Inno Setup Setup Data (4.2.2)",                      INNO_VERSION_EXT(4, 2,  2, 0), 0 },
128 	{ "Inno Setup Setup Data (4.2.3)",      /* ambiguous */ INNO_VERSION_EXT(4, 2,  3, 0), 0 },
129 	{ "Inno Setup Setup Data (4.2.4)",                      INNO_VERSION_EXT(4, 2,  4, 0), 0 },
130 	{ "Inno Setup Setup Data (4.2.5)",                      INNO_VERSION_EXT(4, 2,  5, 0), 0 },
131 	{ "Inno Setup Setup Data (4.2.6)",                      INNO_VERSION_EXT(4, 2,  6, 0), 0 },
132 	{ "Inno Setup Setup Data (5.0.0)",                      INNO_VERSION_EXT(5, 0,  0, 0), 0 },
133 	{ "Inno Setup Setup Data (5.0.1)",                      INNO_VERSION_EXT(5, 0,  1, 0), 0 },
134 	{ "Inno Setup Setup Data (5.0.3)",                      INNO_VERSION_EXT(5, 0,  3, 0), 0 },
135 	{ "Inno Setup Setup Data (5.0.4)",                      INNO_VERSION_EXT(5, 0,  4, 0), 0 },
136 	{ "Inno Setup Setup Data (5.1.0)",                      INNO_VERSION_EXT(5, 1,  0, 0), 0 },
137 	{ "Inno Setup Setup Data (5.1.2)",                      INNO_VERSION_EXT(5, 1,  2, 0), 0 },
138 	{ "Inno Setup Setup Data (5.1.7)",                      INNO_VERSION_EXT(5, 1,  7, 0), 0 },
139 	{ "Inno Setup Setup Data (5.1.10)",                     INNO_VERSION_EXT(5, 1, 10, 0), 0 },
140 	{ "Inno Setup Setup Data (5.1.13)",                     INNO_VERSION_EXT(5, 1, 13, 0), 0 },
141 	{ "Inno Setup Setup Data (5.2.0)",                      INNO_VERSION_EXT(5, 2,  0, 0), 0 },
142 	{ "Inno Setup Setup Data (5.2.1)",                      INNO_VERSION_EXT(5, 2,  1, 0), 0 },
143 	{ "Inno Setup Setup Data (5.2.3)",                      INNO_VERSION_EXT(5, 2,  3, 0), 0 },
144 	{ "Inno Setup Setup Data (5.2.5)",                      INNO_VERSION_EXT(5, 2,  5, 0), 0 },
145 	{ "Inno Setup Setup Data (5.2.5) (u)",                  INNO_VERSION_EXT(5, 2,  5, 0), version::Unicode },
146 	{ "Inno Setup Setup Data (5.3.0)",                      INNO_VERSION_EXT(5, 3,  0, 0), 0 },
147 	{ "Inno Setup Setup Data (5.3.0) (u)",                  INNO_VERSION_EXT(5, 3,  0, 0), version::Unicode },
148 	{ "Inno Setup Setup Data (5.3.3)",                      INNO_VERSION_EXT(5, 3,  3, 0), 0 },
149 	{ "Inno Setup Setup Data (5.3.3) (u)",                  INNO_VERSION_EXT(5, 3,  3, 0), version::Unicode },
150 	{ "Inno Setup Setup Data (5.3.5)",                      INNO_VERSION_EXT(5, 3,  5, 0), 0 },
151 	{ "Inno Setup Setup Data (5.3.5) (u)",                  INNO_VERSION_EXT(5, 3,  5, 0), version::Unicode },
152 	{ "Inno Setup Setup Data (5.3.6)",                      INNO_VERSION_EXT(5, 3,  6, 0), 0 },
153 	{ "Inno Setup Setup Data (5.3.6) (u)",                  INNO_VERSION_EXT(5, 3,  6, 0), version::Unicode },
154 	{ "Inno Setup Setup Data (5.3.7)",                      INNO_VERSION_EXT(5, 3,  7, 0), 0 },
155 	{ "Inno Setup Setup Data (5.3.7) (u)",                  INNO_VERSION_EXT(5, 3,  7, 0), version::Unicode },
156 	{ "Inno Setup Setup Data (5.3.8)",                      INNO_VERSION_EXT(5, 3,  8, 0), 0 },
157 	{ "Inno Setup Setup Data (5.3.8) (u)",                  INNO_VERSION_EXT(5, 3,  8, 0), version::Unicode },
158 	{ "Inno Setup Setup Data (5.3.9)",                      INNO_VERSION_EXT(5, 3,  9, 0), 0 },
159 	{ "Inno Setup Setup Data (5.3.9) (u)",                  INNO_VERSION_EXT(5, 3,  9, 0), version::Unicode },
160 	{ "Inno Setup Setup Data (5.3.10)",                     INNO_VERSION_EXT(5, 3, 10, 0), 0 },
161 	{ "Inno Setup Setup Data (5.3.10) (u)",                 INNO_VERSION_EXT(5, 3, 10, 0), version::Unicode },
162 	{ "Inno Setup Setup Data (5.4.2)",                      INNO_VERSION_EXT(5, 4,  2, 0), 0 },
163 	{ "Inno Setup Setup Data (5.4.2) (u)",  /* ambiguous */ INNO_VERSION_EXT(5, 4,  2, 0), version::Unicode },
164 	{ "" /* BlackBox v1? */,                                INNO_VERSION_EXT(5, 4,  2, 1), 0 },
165 	{ "" /* BlackBox v1? */,                                INNO_VERSION_EXT(5, 4,  2, 1), version::Unicode },
166 	{ "Inno Setup Setup Data (5.5.0)",                      INNO_VERSION_EXT(5, 5,  0, 0), 0 },
167 	{ "Inno Setup Setup Data (5.5.0) (u)",  /* ambiguous */ INNO_VERSION_EXT(5, 5,  0, 0), version::Unicode },
168 	{ "" /* BlackBox v2 / Inno Setup Ultra */,              INNO_VERSION_EXT(5, 5,  0, 1), 0 },
169 	{ "" /* BlackBox v2 / Inno Setup Ultra */,              INNO_VERSION_EXT(5, 5,  0, 1), version::Unicode },
170 	{ "Inno Setup Setup Data (5.5.6)",                      INNO_VERSION_EXT(5, 5,  6, 0), 0 },
171 	{ "Inno Setup Setup Data (5.5.6) (u)",                  INNO_VERSION_EXT(5, 5,  6, 0), version::Unicode },
172 	{ "Inno Setup Setup Data (5.5.7)",      /* ambiguous */ INNO_VERSION_EXT(5, 5,  7, 0), 0 },
173 	{ "Inno Setup Setup Data (5.5.7) (u)",  /* ambiguous */ INNO_VERSION_EXT(5, 5,  7, 0), version::Unicode },
174 	{ "Inno Setup Setup Data (5.5.7) (U)",  /* ambiguous */ INNO_VERSION_EXT(5, 5,  7, 0), version::Unicode },
175 	{ "Inno Setup Setup Data (5.5.8) (u)", /* unofficial */ INNO_VERSION_EXT(5, 5,  7, 0), version::Unicode },
176 	{ "" /* unknown 5.5.7 (u) variant */,   /* ambiguous */ INNO_VERSION_EXT(5, 5,  7, 1), 0 },
177 	{ "" /* unknown 5.5.7 (u) variant */,   /* ambiguous */ INNO_VERSION_EXT(5, 5,  7, 1), version::Unicode },
178 	{ "Inno Setup Setup Data (5.6.0)",                      INNO_VERSION_EXT(5, 6,  0, 0), 0 },
179 	{ "Inno Setup Setup Data (5.6.0) (u)",                  INNO_VERSION_EXT(5, 6,  0, 0), version::Unicode },
180 	{ "Inno Setup Setup Data (5.6.2)",     /* prerelease */ INNO_VERSION_EXT(5, 6,  2, 0), 0 },
181 	{ "Inno Setup Setup Data (5.6.2) (u)", /* prerelease */ INNO_VERSION_EXT(5, 6,  2, 0), version::Unicode },
182 	{ "Inno Setup Setup Data (6.0.0) (u)",                  INNO_VERSION_EXT(6, 0,  0, 0), version::Unicode },
183 	{ "Inno Setup Setup Data (6.1.0) (u)",                  INNO_VERSION_EXT(6, 1,  0, 0), version::Unicode },
184 };
185 
186 } // anonymous namespace
187 
operator <<(std::ostream & os,const version & version)188 std::ostream & operator<<(std::ostream & os, const version & version) {
189 
190 	os << version.a() << '.' << version.b() << '.' << version.c();
191 	if(version.d()) {
192 		os << '.' << version.d();
193 	}
194 
195 	if(version.is_unicode()) {
196 		os << " (unicode)";
197 	}
198 
199 	if(version.bits() != 32) {
200 		os << " (" << int(version.bits()) << "-bit)";
201 	}
202 
203 	if(version.is_isx()) {
204 		os << " (isx)";
205 	}
206 
207 	return os;
208 }
209 
load(std::istream & is)210 void version::load(std::istream & is) {
211 
212 	static const char digits[] = "0123456789";
213 
214 	BOOST_STATIC_ASSERT(sizeof(stored_legacy_version) <= sizeof(stored_version));
215 
216 	stored_legacy_version legacy_version;
217 	is.read(legacy_version, std::streamsize(sizeof(legacy_version)));
218 
219 	if(legacy_version[0] == 'i' && legacy_version[sizeof(legacy_version) - 1] == '\x1a') {
220 
221 		for(size_t i = 0; i < size_t(boost::size(legacy_versions)); i++) {
222 			if(!memcmp(legacy_version, legacy_versions[i].name, sizeof(legacy_version))) {
223 				value = legacy_versions[i].version;
224 				variant = legacy_versions[i].variant;
225 				known = true;
226 				debug("known legacy version: \"" << versions[i].name << '"');
227 				return;
228 			}
229 		}
230 
231 		debug("unknown legacy version: \""
232 		      << std::string(legacy_version, sizeof(legacy_version)) << '"');
233 
234 		if(legacy_version[0] != 'i' || legacy_version[2] != '.' || legacy_version[4] != '.'
235 		   || legacy_version[7] != '-' || legacy_version[8] != '-') {
236 			throw version_error();
237 		}
238 
239 		if(legacy_version[9] == '1' && legacy_version[10] == '6') {
240 			variant = Bits16;
241 		} else if(legacy_version[9] == '3' && legacy_version[10] == '2') {
242 			variant = 0;
243 		} else {
244 			throw version_error();
245 		}
246 
247 		std::string version_str(legacy_version, sizeof(legacy_version));
248 
249 		try {
250 			unsigned a = util::to_unsigned(version_str.data() + 1, 1);
251 			unsigned b = util::to_unsigned(version_str.data() + 3, 1);
252 			unsigned c = util::to_unsigned(version_str.data() + 5, 2);
253 			value = INNO_VERSION(a, b, c);
254 		} catch(const boost::bad_lexical_cast &) {
255 			throw version_error();
256 		}
257 
258 		known = false;
259 
260 		return;
261 	}
262 
263 	stored_version version_string;
264 	BOOST_STATIC_ASSERT(sizeof(legacy_version) <= sizeof(version_string));
265 	memcpy(version_string, legacy_version, sizeof(legacy_version));
266 	is.read(version_string + sizeof(legacy_version),
267 	        std::streamsize(sizeof(version_string) - sizeof(legacy_version)));
268 
269 
270 	for(size_t i = 0; i < size_t(boost::size(versions)); i++) {
271 		if(versions[i].name[0] != '\0' && !memcmp(version_string, versions[i].name, sizeof(version_string))) {
272 			value = versions[i].version;
273 			variant = versions[i].variant;
274 			known = true;
275 			debug("known version: \"" << versions[i].name << '"');
276 			return;
277 		}
278 	}
279 
280 	char * end = std::find(version_string, version_string + boost::size(version_string), '\0');
281 	std::string version_str(version_string, end);
282 	debug("unknown version: \"" << version_str << '"');
283 	if(!boost::contains(version_str, "Inno Setup")) {
284 		throw version_error();
285 	}
286 
287 	value = 0;
288 	size_t bracket = version_str.find('(');
289 	for(; bracket != std::string::npos; bracket = version_str.find('(', bracket + 1)) {
290 
291 		if(version_str.length() - bracket < 6) {
292 			continue;
293 		}
294 
295 		try {
296 
297 			size_t a_start = bracket + 1;
298 			size_t a_end = version_str.find_first_not_of(digits, a_start);
299 			if(a_end == std::string::npos || version_str[a_end] != '.') {
300 				continue;
301 			}
302 			unsigned a = util::to_unsigned(version_str.data() + a_start, a_end - a_start);
303 
304 			size_t b_start = a_end + 1;
305 			size_t b_end = version_str.find_first_not_of(digits, b_start);
306 			if(b_end == std::string::npos || version_str[b_end] != '.') {
307 				continue;
308 			}
309 			unsigned b = util::to_unsigned(version_str.data() + b_start, b_end - b_start);
310 
311 			size_t c_start = b_end + 1;
312 			size_t c_end = version_str.find_first_not_of(digits, c_start);
313 			if(c_end == std::string::npos) {
314 				continue;
315 			}
316 			unsigned c = util::to_unsigned(version_str.data() + c_start, c_end - c_start);
317 
318 			size_t d_start = c_end;
319 			if(version_str[d_start] == 'a') {
320 				if(d_start + 1 >= version_str.length()) {
321 					continue;
322 				}
323 				d_start++;
324 			}
325 
326 			unsigned d = 0;
327 			if(version_str[d_start] == '.') {
328 				d_start++;
329 				size_t d_end = version_str.find_first_not_of(digits, d_start);
330 				if(d_end != std::string::npos && d_end != d_start) {
331 					d = util::to_unsigned(version_str.data() + d_start, d_end - d_start);
332 				}
333 			}
334 
335 			value = std::max(value, INNO_VERSION_EXT(a, b, c, d));
336 
337 		} catch(const boost::bad_lexical_cast &) {
338 			continue;
339 		}
340 	}
341 	if(!value) {
342 		throw version_error();
343 	}
344 
345 	variant = 0;
346 	if(boost::contains(version_str, "(u)") || boost::contains(version_str, "(U)")) {
347 		variant |= Unicode;
348 	}
349 	if(boost::contains(version_str, "My Inno Setup Extensions") || boost::contains(version_str, "with ISX")) {
350 		variant |= ISX;
351 	}
352 
353 	known = false;
354 }
355 
is_ambiguous() const356 bool version::is_ambiguous() const {
357 
358 	if(value == INNO_VERSION(1, 3, 21)) {
359 		// might be either 1.3.21 or 1.3.24
360 		return true;
361 	}
362 
363 	if(value == INNO_VERSION(2, 0, 1)) {
364 		// might be either 2.0.1 or 2.0.2
365 		return true;
366 	}
367 
368 	if(value == INNO_VERSION(3, 0, 3)) {
369 		// might be either 3.0.3 or 3.0.4
370 		return true;
371 	}
372 
373 	if(value == INNO_VERSION(4, 2, 3)) {
374 		// might be either 4.2.3 or 4.2.4
375 		return true;
376 	}
377 
378 	if(value == INNO_VERSION(5, 4, 2)) {
379 		// might be either 5.4.2 or 5.4.2.1
380 		return true;
381 	}
382 
383 	if(value == INNO_VERSION(5, 5, 0)) {
384 		// might be either 5.5.0 or 5.5.0.1
385 		return true;
386 	}
387 
388 	if(value == INNO_VERSION(5, 5, 7) || value == INNO_VERSION_EXT(5, 5, 7, 1)) {
389 		// might be either 5.5.7, an unknown modification of 5.5.7, or 5.6.0
390 		return true;
391 	}
392 
393 	return false;
394 }
395 
next()396 version_constant version::next() {
397 
398 	const known_legacy_version * legacy_end = boost::end(legacy_versions);
399 	const known_legacy_version * legacy_result;
400 	legacy_result = std::upper_bound(boost::begin(legacy_versions), legacy_end, value);
401 	while(legacy_result != legacy_end && legacy_result->variant != variant) {
402 		legacy_result++;
403 	}
404 	if(legacy_result != legacy_end) {
405 		return legacy_result->version;
406 	}
407 
408 	const known_version * end = boost::end(versions);
409 	const known_version * result = std::upper_bound(boost::begin(versions), end, value);
410 	while(result != end && result->variant != variant) {
411 		result++;
412 	}
413 	if(result != end) {
414 		return result->version;
415 	}
416 
417 	return 0;
418 }
419 
420 } // namespace setup
421