text: /*
   * Copyright (c) 2017, Matias Fontanini
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   * * Redistributions of source code must retain the above copyright
   *   notice, this list of conditions and the following disclaimer.
   * * Redistributions in binary form must reproduce the above
   *   copyright notice, this list of conditions and the following disclaimer
   *   in the documentation and/or other materials provided with the
   *   distribution.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   */
  
  #ifndef TINS_RADIOTAP_PARSER_H
  #define TINS_RADIOTAP_PARSER_H
  
  #include <stdint.h>
  #include "../macros.h"
  #include "../radiotap.h"
  #include "../pdu_option.h"
  
  namespace Tins {
  namespace Utils {
  
  struct RadioTapFlags;
  
  /**
   * \brief Allows parsing RadioTap options
   *
   * RadioTap is a somehow tricky protocol to be parsed, as it has ordered flags,
   * alignment between options, etc. This class allows parsing options in a RadioTap
   * header without much trouble.
   */
  class RadioTapParser {
  public:
      /**
       * Represents the RadioTap namespace currently being parsed
       */
      enum NamespaceType {
          RADIOTAP_NS,
          VENDOR_NS,
          UNKNOWN_NS
      };
  
      /**
       * Represents the size and alignment of each RadioTap field
       */
      struct FieldMetadata {
          uint32_t size;
          uint32_t alignment;
      };
  
      /**
       * Contains metadata for each data field in RadioTap
       */
      static const FieldMetadata RADIOTAP_METADATA[];
  
      /**
       * Represents the maximum bit we have information for
       */
      static const uint32_t MAX_RADIOTAP_FIELD;
  
      /**
       * \brief Constructs a RadioTap parser around a payload
       *
       * Note that the payload is not copied, hence it must be kept in 
       * scope while the parser is still being used.
       *
       * The buffer should contain an entire RadioTap header, with optionally
       * extra data at the end, which will be ignored.
       *
       * \param buffer The buffer to be parsed
       */
      RadioTapParser(const std::vector<uint8_t>& buffer);
  
      /**
       * Gets the current namespace being parsed
       */
      NamespaceType current_namespace() const;
  
      /**
       * \brief Gets a 0 index based namespace index.
       *
       * This index will be incremented every time a new namespace is found
       */
      uint32_t current_namespace_index() const;
  
      /**
       * Gets the current field being parsed
       */
      RadioTap::PresentFlags current_field() const;
  
      /**
       * Gets the option the parsed is currently pointing at
       */
      RadioTap::option current_option();
  
      /**
       * Gets the pointer at which the current option is located
       */
      const uint8_t* current_option_ptr() const;
  
      /**
       * \brief Advances to the next option
       *
       * If there's a namespace change, this will handle that as well.
       *
       * \return true iff advancing was successfull (e.g. false if we reached
       * the end of the header)
       */
      bool advance_field();
  
      /**
       * \brief Advances to the next namespace
       *
       * \return true iff advancing was successfull (e.g. false if we're currently
       * in the last namespace)
       */
      bool advance_namespace();
  
      /**
       * Gets the current namespace's flags
       */
      RadioTap::PresentFlags namespace_flags() const;
  
      /**
       * \brief Skips all fields until the provided one is found
       *
       * This will effectively move the current option pointer until the field is 
       * found or the end of the options list is reached
       *
       * \return true iff the field was foudn
       */
      bool skip_to_field(RadioTap::PresentFlags flag);
  
      /**
       * Indicates whether this RadioTap options buffer contains any fields set
       */
      bool has_fields() const;
  
      /**
       * \brief Indicates whether the provided field is set.
       *
       * This will look the field up in all flag sets and not just the current one
       */
      bool has_field(RadioTap::PresentFlags flag) const;
  private:
      const uint8_t* find_options_start() const;
      bool advance_to_first_field();
      bool advance_to_next_field();
      bool skip_current_field();
      bool advance_to_next_namespace();
      const RadioTapFlags* get_flags_ptr() const;
      void load_current_flags();
      bool is_field_set(uint32_t bit, const RadioTapFlags* flags) const;
  
      const uint8_t* start_;
      const uint8_t* end_; 
      const uint8_t* current_ptr_;
      uint64_t current_bit_;
      uint32_t current_flags_;
      uint32_t namespace_index_;
      NamespaceType current_namespace_;
  };
  
  } // Utils
  } // Tins
  
  #endif // TINS_RADIOTAP_PARSER_H
  