| /* |
| * Copyright 2018 The Hafnium 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 |
| * |
| * https://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 "hf/memiter.h" |
| |
| #include "hf/check.h" |
| #include "hf/dlog.h" |
| #include "hf/std.h" |
| |
| /** |
| * Initialises the given memory iterator. |
| */ |
| void memiter_init(struct memiter *it, const void *data, size_t size) |
| { |
| it->next = data; |
| it->limit = it->next + size; |
| } |
| |
| /** |
| * Determines if the next character is a whitespace. |
| */ |
| static bool memiter_isspace(struct memiter *it) |
| { |
| switch (*it->next) { |
| case ' ': |
| case '\t': |
| case '\n': |
| case '\r': |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| /** |
| * Moves iterator to the next non-whitespace character. |
| */ |
| static void memiter_skip_space(struct memiter *it) |
| { |
| while (it->next < it->limit && memiter_isspace(it)) { |
| it->next++; |
| } |
| } |
| |
| /** |
| * Compares the iterator to a null-terminated string. |
| */ |
| bool memiter_iseq(const struct memiter *it, const char *str) |
| { |
| size_t it_len = it->limit - it->next; |
| size_t len = strnlen_s(str, it_len + 1); |
| |
| if (len != it_len) { |
| return false; |
| } |
| |
| return memcmp(it->next, str, len) == 0; |
| } |
| |
| /** |
| * Retrieves the next string that is delimited by whitespaces. The result is |
| * stored in "str". |
| */ |
| bool memiter_parse_str(struct memiter *it, struct memiter *str) |
| { |
| /* Skip all white space and fail if we reach the end of the buffer. */ |
| memiter_skip_space(it); |
| if (it->next >= it->limit) { |
| return false; |
| } |
| |
| str->next = it->next; |
| |
| /* Find the end of the string. */ |
| while (it->next < it->limit && !memiter_isspace(it)) { |
| it->next++; |
| } |
| |
| str->limit = it->next; |
| |
| return true; |
| } |
| |
| /** |
| * Parses the next string that represents a 64-bit number. |
| */ |
| bool memiter_parse_uint(struct memiter *it, uint64_t *value) |
| { |
| uint64_t v = 0; |
| |
| /* Skip all white space and fail if we reach the end of the buffer. */ |
| memiter_skip_space(it); |
| if (it->next >= it->limit) { |
| return false; |
| } |
| |
| /* Fail if it's not a number. */ |
| if (*it->next < '0' || *it->next > '9') { |
| return false; |
| } |
| |
| /* Parse the number. */ |
| do { |
| v = v * 10 + *it->next - '0'; |
| it->next++; |
| } while (it->next < it->limit && *it->next >= '0' && *it->next <= '9'); |
| |
| *value = v; |
| |
| return true; |
| } |
| |
| /** |
| * Advances the iterator by the given number of bytes. Returns true if the |
| * iterator was advanced without going over its limit; returns false and leaves |
| * the iterator unmodified otherwise. |
| */ |
| bool memiter_advance(struct memiter *it, size_t v) |
| { |
| const char *p = it->next + v; |
| |
| if (p < it->next || p > it->limit) { |
| return false; |
| } |
| |
| it->next = p; |
| return true; |
| } |
| |
| /** |
| * Decrements the limit of iterator by the given number of bytes. Returns true |
| * if the limit was reduced without going over the base; returns false and |
| * leaves the iterator unmodified otherwise. |
| */ |
| bool memiter_restrict(struct memiter *it, size_t v) |
| { |
| size_t s = memiter_size(it); |
| |
| if (v > s) { |
| return false; |
| } |
| |
| it->limit = it->next + (s - v); |
| return true; |
| } |
| |
| /** |
| * Initializes `newit` with the first `v` bytes of `it` and advances `it` by |
| * the same number of bytes. This splits the original range into two iterators |
| * after `v` bytes. |
| * Returns true on success; returns false and leaves `it` unmodified and `newit` |
| * uninitialized otherwise. |
| */ |
| bool memiter_consume(struct memiter *it, size_t v, struct memiter *newit) |
| { |
| if (v > memiter_size(it)) { |
| return false; |
| } |
| |
| memiter_init(newit, memiter_base(it), v); |
| CHECK(memiter_advance(it, v)); |
| return true; |
| } |
| |
| const void *memiter_base(const struct memiter *it) |
| { |
| return (const void *)it->next; |
| } |
| |
| /** |
| * Returns the number of bytes in interval [it.next, it.limit). |
| */ |
| size_t memiter_size(const struct memiter *it) |
| { |
| return it->limit - it->next; |
| } |