| /** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenseas/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef LIBMINIFI_INCLUDE_UTILS_VALUEPARSER_H_ |
| #define LIBMINIFI_INCLUDE_UTILS_VALUEPARSER_H_ |
| |
| #include <exception> |
| #include <string> |
| #include <cstring> |
| #include <vector> |
| #include <cstdlib> |
| #include <type_traits> |
| #include <limits> |
| #include <algorithm> |
| |
| #include "PropertyErrors.h" |
| |
| namespace org { |
| namespace apache { |
| namespace nifi { |
| namespace minifi { |
| namespace utils { |
| namespace internal { |
| |
| class ValueParser { |
| public: |
| explicit ValueParser(const std::string& str, std::size_t offset = 0) : str(str), offset(offset) {} |
| |
| ValueParser& parse(int& out) { // NOLINT |
| long result; // NOLINT |
| auto len = safeCallConverter(std::strtol, result); |
| if (len == 0) { |
| throw ParseException("Couldn't parse int"); |
| } |
| if (result < (std::numeric_limits<int>::min)() || result > (std::numeric_limits<int>::max)()) { |
| throw ParseException("Cannot convert long to int"); |
| } |
| offset += len; |
| out = result; |
| return *this; |
| } |
| |
| ValueParser& parse(int64_t& out) { |
| long long result; // NOLINT |
| auto len = safeCallConverter(std::strtoll, result); |
| if (len == 0) { |
| throw ParseException("Couldn't parse long long"); |
| } |
| if (result < (std::numeric_limits<int64_t>::min)() || result > (std::numeric_limits<int64_t>::max)()) { |
| throw ParseException("Cannot convert long long to int64_t"); |
| } |
| offset += len; |
| out = result; |
| return *this; |
| } |
| |
| ValueParser& parse(uint32_t & out) { |
| skipWhitespace(); |
| if (offset < str.length() && str[offset] == '-') { |
| throw ParseException("Not an unsigned long"); |
| } |
| unsigned long result; // NOLINT |
| auto len = safeCallConverter(std::strtoul, result); |
| if (len == 0) { |
| throw ParseException("Couldn't parse uint32_t"); |
| } |
| if (result > (std::numeric_limits<uint32_t>::max)()) { |
| throw ParseException("Cannot convert unsigned long to uint32_t"); |
| } |
| offset += len; |
| out = result; |
| return *this; |
| } |
| |
| ValueParser& parse(uint64_t& out) { |
| skipWhitespace(); |
| if (offset < str.length() && str[offset] == '-') { |
| throw ParseException("Not an unsigned long"); |
| } |
| unsigned long long result; // NOLINT |
| auto len = safeCallConverter(std::strtoull, result); |
| if (len == 0) { |
| throw ParseException("Couldn't parse unsigned long long"); |
| } |
| if (result > (std::numeric_limits<uint64_t>::max)()) { |
| throw ParseException("Cannot convert unsigned long long to uint64_t"); |
| } |
| offset += len; |
| out = result; |
| return *this; |
| } |
| |
| ValueParser& parse(bool& out) { |
| skipWhitespace(); |
| if (std::strncmp(str.c_str() + offset, "false", std::strlen("false")) == 0) { |
| offset += std::strlen("false"); |
| out = false; |
| } else if (std::strncmp(str.c_str() + offset, "true", std::strlen("true")) == 0) { |
| offset += std::strlen("true"); |
| out = true; |
| } else { |
| throw ParseException("Couldn't parse bool"); |
| } |
| return *this; |
| } |
| |
| void parseEnd() { |
| skipWhitespace(); |
| if (offset < str.length()) { |
| throw ParseException("Expected to parse till the end"); |
| } |
| } |
| |
| private: |
| /** |
| * |
| * @tparam T |
| * @param converter |
| * @param out |
| * @return the number of characters used during conversion, 0 for error |
| */ |
| template<typename T> |
| std::size_t safeCallConverter(T (*converter)(const char* begin, char** end, int base), T& out) { |
| const char* const begin = str.c_str() + offset; |
| char* end; |
| errno = 0; |
| T result = converter(begin, &end, 10); |
| if (end == begin || errno == ERANGE) { |
| return 0; |
| } |
| out = result; |
| return end - begin; |
| } |
| |
| void skipWhitespace() { |
| while (offset < str.length() && std::isspace(str[offset])) { |
| ++offset; |
| } |
| } |
| |
| const std::string& str; |
| std::size_t offset; |
| }; |
| |
| template<typename Out> |
| bool StringToTime(const std::string& input, Out& output, core::TimeUnit& timeunit) { |
| if (input.size() == 0) { |
| return false; |
| } |
| |
| const char* begin = input.c_str(); |
| char *end; |
| errno = 0; |
| auto ival = std::strtoll(begin, &end, 0); |
| if (end == begin || errno == ERANGE) { |
| return false; |
| } |
| |
| if (end[0] == '\0') { |
| return false; |
| } |
| |
| while (*end == ' ') { |
| // Skip the space |
| end++; |
| } |
| |
| std::string unit(end); |
| std::transform(unit.begin(), unit.end(), unit.begin(), ::tolower); |
| |
| if (unit == "sec" || unit == "s" || unit == "second" || unit == "seconds" || unit == "secs") { |
| timeunit = core::TimeUnit::SECOND; |
| output = ival; |
| return true; |
| } else if (unit == "msec" || unit == "ms" || unit == "millisecond" || unit == "milliseconds" || unit == "msecs") { |
| timeunit = core::TimeUnit::MILLISECOND; |
| output = ival; |
| return true; |
| } else if (unit == "min" || unit == "m" || unit == "mins" || unit == "minute" || unit == "minutes") { |
| timeunit = core::TimeUnit::MINUTE; |
| output = ival; |
| return true; |
| } else if (unit == "ns" || unit == "nano" || unit == "nanos" || unit == "nanoseconds") { |
| timeunit = core::TimeUnit::NANOSECOND; |
| output = ival; |
| return true; |
| } else if (unit == "ms" || unit == "milli" || unit == "millis" || unit == "milliseconds") { |
| timeunit = core::TimeUnit::MILLISECOND; |
| output = ival; |
| return true; |
| } else if (unit == "h" || unit == "hr" || unit == "hour" || unit == "hrs" || unit == "hours") { |
| timeunit = core::TimeUnit::HOUR; |
| output = ival; |
| return true; |
| } else if (unit == "d" || unit == "day" || unit == "days") { |
| timeunit = core::TimeUnit::DAY; |
| output = ival; |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| } /* namespace internal */ |
| } /* namespace utils */ |
| } /* namespace minifi */ |
| } /* namespace nifi */ |
| } /* namespace apache */ |
| } /* namespace org */ |
| |
| #endif // LIBMINIFI_INCLUDE_UTILS_VALUEPARSER_H_ |