text: /*
   * Copyright (c) 2017, ARM Limited, All Rights Reserved
   * SPDX-License-Identifier: Apache-2.0
   *
   * 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.
   */
  /**
   * \file buffer_reader.c
   * \copyright Copyright (c) ARM Ltd 2015
   * \author Donatien Garnier
   */
  
  #include "acore/ac_buffer_reader.h"
  #include "acore/ac_macros.h"
  
  #include "string.h"
  
  #define VOID
  #define ENSURE_READ_LENGTH(pBuf, n) do{ if( ac_buffer_reader_readable(pBuf) < n ) { return; } }while(0);
  
  static inline void update_buf(ac_buffer_t *pBuf)
  {
      while (ac_buffer_size(pBuf) == 0) {
          if (ac_buffer_next(pBuf) != NULL) {
              ac_buffer_t *pNext = ac_buffer_next(pBuf);
              ac_buffer_init(pBuf, ac_buffer_data(pNext), ac_buffer_size(pNext));
              pBuf->pNext = ac_buffer_next(pNext);
          } else if (pBuf->data != NULL) {
              ac_buffer_init(pBuf, NULL, 0);
          } else {
              return;
          }
      }
  }
  
  void ac_buffer_read_be(ac_buffer_t *pBuf, uint8_t *buf, size_t size)
  {
      ENSURE_READ_LENGTH(pBuf, size);
      buf += size;
      while (size > 0) {
          buf--;
          *buf = *ac_buffer_data(pBuf);
          pBuf->data++;
          pBuf->size--;
          update_buf(pBuf);
          size--;
      }
  }
  
  void ac_buffer_read_le(ac_buffer_t *pBuf, uint8_t *buf, size_t size)
  {
      ENSURE_READ_LENGTH(pBuf, size);
      while (size > 0) {
          size_t cpy = ac_buffer_size(pBuf);
          cpy = MIN(cpy, size);
          memcpy(buf, ac_buffer_data(pBuf), cpy);
          pBuf->data += cpy;
          pBuf->size -= cpy;
          update_buf(pBuf);
          size -= cpy;
          buf += cpy;
      }
  }
  
  void ac_buffer_read_n_skip(ac_buffer_t *pBuf, size_t size)
  {
      ENSURE_READ_LENGTH(pBuf, size);
      while (size > 0) {
          size_t cpy = ac_buffer_size(pBuf);
          cpy = MIN(cpy, size);
          pBuf->data += cpy;
          pBuf->size -= cpy;
          update_buf(pBuf);
          size -= cpy;
      }
  }
  
  size_t ac_buffer_reader_readable(const ac_buffer_t *pBuf)
  {
      size_t r = 0;
      while (pBuf != NULL) {
          r += ac_buffer_size(pBuf);
          pBuf = ac_buffer_next(pBuf);
      }
      return r;
  }
  
  const uint8_t *ac_buffer_reader_current_buffer_pointer(ac_buffer_t *pBuf)
  {
      update_buf(pBuf);
      return ac_buffer_data(pBuf);
  }
  
  size_t ac_buffer_reader_current_buffer_length(ac_buffer_t *pBuf)
  {
      update_buf(pBuf);
      return ac_buffer_size(pBuf);
  }
  
  bool ac_buffer_reader_cmp_bytes(const ac_buffer_t *pBuf, const uint8_t *bytes, size_t length)
  {
      ac_buffer_t reader;
  
      if (length > ac_buffer_reader_readable(pBuf)) {
          return false;
      }
  
      ac_buffer_dup(&reader, pBuf);
  
      while (length > 0) {
          size_t sz = ac_buffer_reader_current_buffer_length(&reader);
          if (sz > length) {
              sz = length;
          }
          int c = memcmp(ac_buffer_reader_current_buffer_pointer(&reader), bytes, sz);
          if (c) {
              return false;
          }
          length -= sz;
          bytes += sz;
          ac_buffer_read_n_skip(&reader, sz);
      }
  
      return true;
  }
  
  bool ac_buffer_reader_cmp(const ac_buffer_t *pBuf1, const ac_buffer_t *pBuf2)
  {
      ac_buffer_t reader1;
      ac_buffer_t reader2;
  
      if (ac_buffer_reader_readable(pBuf1) != ac_buffer_reader_readable(pBuf2)) {
          return false;
      }
  
      ac_buffer_dup(&reader1, pBuf1);
      ac_buffer_dup(&reader2, pBuf2);
  
      size_t length = ac_buffer_reader_readable(pBuf1);
      while (length > 0) {
          size_t sz1 = ac_buffer_reader_current_buffer_length(&reader1);
          size_t sz2 = ac_buffer_reader_current_buffer_length(&reader2);
  
          size_t sz = MIN(sz1, sz2);
  
          int c = memcmp(ac_buffer_reader_current_buffer_pointer(&reader1), ac_buffer_reader_current_buffer_pointer(&reader2), sz);
          if (c) {
              return false;
          }
          length -= sz;
          ac_buffer_read_n_skip(&reader1, sz);
          ac_buffer_read_n_skip(&reader2, sz);
      }
  
      return true;
  }
  