Changeset View
Changeset View
Standalone View
Standalone View
extern/gltf-draco/draco/src/draco/io/parser_utils.cc
- This file was added.
| // Copyright 2016 The Draco Authors. | |||||
| // | |||||
| // Licensed 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/licenses/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. | |||||
| // | |||||
| #include "draco/io/parser_utils.h" | |||||
| #include <algorithm> | |||||
| #include <cctype> | |||||
| #include <cmath> | |||||
| #include <iterator> | |||||
| namespace draco { | |||||
| namespace parser { | |||||
| void SkipCharacters(DecoderBuffer *buffer, const char *skip_chars) { | |||||
| if (skip_chars == nullptr) | |||||
| return; | |||||
| const int num_skip_chars = static_cast<int>(strlen(skip_chars)); | |||||
| char c; | |||||
| while (buffer->Peek(&c)) { | |||||
| // Check all characters in the pattern. | |||||
| bool skip = false; | |||||
| for (int i = 0; i < num_skip_chars; ++i) { | |||||
| if (c == skip_chars[i]) { | |||||
| skip = true; | |||||
| break; | |||||
| } | |||||
| } | |||||
| if (!skip) | |||||
| return; | |||||
| buffer->Advance(1); | |||||
| } | |||||
| } | |||||
| void SkipWhitespace(DecoderBuffer *buffer) { | |||||
| bool end_reached = false; | |||||
| while (PeekWhitespace(buffer, &end_reached) && !end_reached) { | |||||
| // Skip the whitespace character | |||||
| buffer->Advance(1); | |||||
| } | |||||
| } | |||||
| bool PeekWhitespace(DecoderBuffer *buffer, bool *end_reached) { | |||||
| uint8_t c; | |||||
| if (!buffer->Peek(&c)) { | |||||
| *end_reached = true; | |||||
| return false; // eof reached. | |||||
| } | |||||
| if (!isspace(c)) | |||||
| return false; // Non-whitespace character reached. | |||||
| return true; | |||||
| } | |||||
| void SkipLine(DecoderBuffer *buffer) { | |||||
| char c; | |||||
| while (buffer->Peek(&c)) { | |||||
| // Skip the character. | |||||
| buffer->Advance(1); | |||||
| if (c == '\n') | |||||
| return; // Return at the end of line | |||||
| } | |||||
| } | |||||
| bool ParseFloat(DecoderBuffer *buffer, float *value) { | |||||
| // Read optional sign. | |||||
| char ch; | |||||
| if (!buffer->Peek(&ch)) | |||||
| return false; | |||||
| int sign = GetSignValue(ch); | |||||
| if (sign != 0) { | |||||
| buffer->Advance(1); | |||||
| } else { | |||||
| sign = 1; | |||||
| } | |||||
| // Parse integer component. | |||||
| bool have_digits = false; | |||||
| double v = 0.0; | |||||
| while (buffer->Peek(&ch) && ch >= '0' && ch <= '9') { | |||||
| v *= 10.0; | |||||
| v += (ch - '0'); | |||||
| buffer->Advance(1); | |||||
| have_digits = true; | |||||
| } | |||||
| if (ch == '.') { | |||||
| // Parse fractional component. | |||||
| buffer->Advance(1); | |||||
| double fraction = 1.0; | |||||
| while (buffer->Peek(&ch) && ch >= '0' && ch <= '9') { | |||||
| fraction *= 0.1; | |||||
| v += (ch - '0') * fraction; | |||||
| buffer->Advance(1); | |||||
| have_digits = true; | |||||
| } | |||||
| } | |||||
| if (!have_digits) { | |||||
| // Check for special constants (inf, nan, ...). | |||||
| std::string text; | |||||
| if (!ParseString(buffer, &text)) | |||||
| return false; | |||||
| if (text == "inf" || text == "Inf") { | |||||
| v = std::numeric_limits<double>::infinity(); | |||||
| } else if (text == "nan" || text == "NaN") { | |||||
| v = nan(""); | |||||
| } else { | |||||
| // Invalid string. | |||||
| return false; | |||||
| } | |||||
| } else { | |||||
| // Handle exponent if present. | |||||
| if (ch == 'e' || ch == 'E') { | |||||
| buffer->Advance(1); // Skip 'e' marker. | |||||
| // Parse integer exponent. | |||||
| int32_t exponent = 0; | |||||
| if (!ParseSignedInt(buffer, &exponent)) | |||||
| return false; | |||||
| // Apply exponent scaling to value. | |||||
| v *= pow(10.0, exponent); | |||||
| } | |||||
| } | |||||
| *value = (sign < 0) ? static_cast<float>(-v) : static_cast<float>(v); | |||||
| return true; | |||||
| } | |||||
| bool ParseSignedInt(DecoderBuffer *buffer, int32_t *value) { | |||||
| // Parse any explicit sign and set the appropriate largest magnitude | |||||
| // value that can be represented without overflow. | |||||
| char ch; | |||||
| if (!buffer->Peek(&ch)) | |||||
| return false; | |||||
| const int sign = GetSignValue(ch); | |||||
| if (sign != 0) | |||||
| buffer->Advance(1); | |||||
| // Attempt to parse integer body. | |||||
| uint32_t v; | |||||
| if (!ParseUnsignedInt(buffer, &v)) | |||||
| return false; | |||||
| *value = (sign < 0) ? -v : v; | |||||
| return true; | |||||
| } | |||||
| bool ParseUnsignedInt(DecoderBuffer *buffer, uint32_t *value) { | |||||
| // Parse the number until we run out of digits. | |||||
| uint32_t v = 0; | |||||
| char ch; | |||||
| bool have_digits = false; | |||||
| while (buffer->Peek(&ch) && ch >= '0' && ch <= '9') { | |||||
| v *= 10; | |||||
| v += (ch - '0'); | |||||
| buffer->Advance(1); | |||||
| have_digits = true; | |||||
| } | |||||
| if (!have_digits) | |||||
| return false; | |||||
| *value = v; | |||||
| return true; | |||||
| } | |||||
| int GetSignValue(char c) { | |||||
| if (c == '-') | |||||
| return -1; | |||||
| if (c == '+') | |||||
| return 1; | |||||
| return 0; | |||||
| } | |||||
| bool ParseString(DecoderBuffer *buffer, std::string *out_string) { | |||||
| out_string->clear(); | |||||
| SkipWhitespace(buffer); | |||||
| bool end_reached = false; | |||||
| while (!PeekWhitespace(buffer, &end_reached) && !end_reached) { | |||||
| char c; | |||||
| if (!buffer->Decode(&c)) | |||||
| return false; | |||||
| *out_string += c; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| void ParseLine(DecoderBuffer *buffer, std::string *out_string) { | |||||
| out_string->clear(); | |||||
| char c; | |||||
| while (buffer->Peek(&c)) { | |||||
| // Skip the character. | |||||
| buffer->Advance(1); | |||||
| if (c == '\n') | |||||
| return; // Return at the end of line. | |||||
| if (c == '\r') | |||||
| continue; // Ignore extra line ending characters. | |||||
| *out_string += c; | |||||
| } | |||||
| } | |||||
| DecoderBuffer ParseLineIntoDecoderBuffer(DecoderBuffer *buffer) { | |||||
| const char *const head = buffer->data_head(); | |||||
| char c; | |||||
| while (buffer->Peek(&c)) { | |||||
| // Skip the character. | |||||
| buffer->Advance(1); | |||||
| if (c == '\n') | |||||
| break; // End of the line reached. | |||||
| if (c == '\r') | |||||
| continue; // Ignore extra line ending characters. | |||||
| } | |||||
| DecoderBuffer out_buffer; | |||||
| out_buffer.Init(head, buffer->data_head() - head); | |||||
| return out_buffer; | |||||
| } | |||||
| std::string ToLower(const std::string &str) { | |||||
| std::string out; | |||||
| std::transform(str.begin(), str.end(), std::back_inserter(out), tolower); | |||||
| return out; | |||||
| } | |||||
| } // namespace parser | |||||
| } // namespace draco | |||||