Skip to content

Commit 15d594f

Browse files
committed
Better implementation of integer parser for OPL parser
Works with all legal integers now. Fixes #336
1 parent 85633a0 commit 15d594f

2 files changed

Lines changed: 36 additions & 18 deletions

File tree

include/osmium/io/detail/opl_parser_functions.hpp

Lines changed: 13 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -206,42 +206,38 @@ namespace osmium {
206206
*data = s;
207207
}
208208

209-
enum {
210-
max_int_len = std::numeric_limits<int64_t>::digits10 + 1
211-
};
212-
213209
template <typename T>
214210
inline T opl_parse_int(const char** s) {
215-
if (**s == '\0') {
216-
throw opl_error{"expected integer", *s};
217-
}
218211
const bool negative = (**s == '-');
219212
if (negative) {
220213
++*s;
221214
}
222215

223-
int64_t value = 0;
216+
if (**s < '0' || **s > '9') {
217+
throw opl_error{"expected integer", *s};
218+
}
224219

225-
int n = max_int_len;
220+
int64_t value = 0;
226221
while (**s >= '0' && **s <= '9') {
227-
if (--n == 0) {
228-
throw opl_error{"integer too long", *s};
222+
if (value <= -922337203685477580) {
223+
if ((value < -922337203685477580) || (**s > '8')) {
224+
throw opl_error("integer too long", *s);
225+
}
229226
}
230227
value *= 10;
231-
value += **s - '0';
228+
value -= **s - '0';
232229
++*s;
233230
}
234231

235-
if (n == max_int_len) {
236-
throw opl_error{"expected integer", *s};
237-
}
238-
239232
if (negative) {
240-
value = -value;
241233
if (value < std::numeric_limits<T>::min()) {
242234
throw opl_error{"integer too long", *s};
243235
}
244236
} else {
237+
if (value == std::numeric_limits<int64_t>::min()) {
238+
throw opl_error{"integer too long", *s};
239+
}
240+
value = -value;
245241
if (value > std::numeric_limits<T>::max()) {
246242
throw opl_error{"integer too long", *s};
247243
}

test/t/io/test_opl_parser.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ TEST_CASE("Parse OPL: integer") {
262262
REQUIRE(test_parse_int("-1234567890123x") == -1234567890123);
263263
REQUIRE(test_parse_int("999999999999999999x") == 999999999999999999);
264264
REQUIRE(test_parse_int("-999999999999999999x") == -999999999999999999);
265+
REQUIRE(test_parse_int("1000000000000000000x") == 1000000000000000000);
266+
REQUIRE(test_parse_int("9223372036854775807x") == 9223372036854775807);
267+
REQUIRE(test_parse_int("-9223372036854775807x") == -9223372036854775807);
268+
REQUIRE(test_parse_int("-9223372036854775808x") == -9223372036854775807 - 1);
265269

266270
REQUIRE_THROWS_WITH(test_parse_int(""),
267271
"OPL error: expected integer");
@@ -275,7 +279,25 @@ TEST_CASE("Parse OPL: integer") {
275279
REQUIRE_THROWS_WITH(test_parse_int("x"),
276280
"OPL error: expected integer");
277281

278-
REQUIRE_THROWS_WITH(test_parse_int("99999999999999999999999x"),
282+
REQUIRE_THROWS_WITH(test_parse_int("9223372036854775808x"),
283+
"OPL error: integer too long");
284+
285+
REQUIRE_THROWS_WITH(test_parse_int("9223372036854775809x"),
286+
"OPL error: integer too long");
287+
288+
REQUIRE_THROWS_WITH(test_parse_int("9223372036854775810x"),
289+
"OPL error: integer too long");
290+
291+
REQUIRE_THROWS_WITH(test_parse_int("-9223372036854775809x"),
292+
"OPL error: integer too long");
293+
294+
REQUIRE_THROWS_WITH(test_parse_int("-9223372036854775810x"),
295+
"OPL error: integer too long");
296+
297+
REQUIRE_THROWS_WITH(test_parse_int("999999999999999999999x"),
298+
"OPL error: integer too long");
299+
300+
REQUIRE_THROWS_WITH(test_parse_int("-999999999999999999999x"),
279301
"OPL error: integer too long");
280302
}
281303

0 commit comments

Comments
 (0)