text: /*
   *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
   *
   *  Use of this source code is governed by a BSD-style license
   *  that can be found in the LICENSE file in the root of the source
   *  tree. An additional intellectual property rights grant can be found
   *  in the file PATENTS.  All contributing project authors may
   *  be found in the AUTHORS file in the root of the source tree.
   */
  
  #include "modules/remote_bitrate_estimator/test/bwe_test_baselinefile.h"
  
  #include <stdio.h>
  
  #include <algorithm>
  #include <memory>
  #include <vector>
  
  #include "modules/remote_bitrate_estimator/test/bwe_test_fileutils.h"
  #include "modules/remote_bitrate_estimator/test/bwe_test_logging.h"
  #include "rtc_base/constructormagic.h"
  #include "test/testsupport/fileutils.h"
  
  namespace webrtc {
  namespace testing {
  namespace bwe {
  
  // The format of BWE test baseline files is extremely simple:
  //   1. All read/written entities are 32-bit unsigned integers in network byte
  //      order (Big Endian).
  //   2. Files beging with a 2 word header containing a magic marker and file
  //      format version indicator. The Magic marker reads "BWE!" in a hex dump.
  //   3. Each estimate is logged as a pair of words: time in milliseconds and
  //      estimated bit rate, in bits per second.
  const uint32_t kMagicMarker = 0x42574521;
  const uint32_t kFileVersion1 = 0x00000001;
  const char kResourceSubDir[] = "remote_bitrate_estimator";
  
  class BaseLineFileVerify : public BaseLineFileInterface {
   public:
    // If |allow_missing_file| is set, VerifyOrWrite() will return true even if
    // the baseline file is missing. This is the default when verifying files, but
    // not when updating (i.e. we always write it out if missing).
    BaseLineFileVerify(const std::string& filepath, bool allow_missing_file)
        : reader_(), fail_to_read_response_(false) {
      std::unique_ptr<ResourceFileReader> reader;
      reader.reset(ResourceFileReader::Create(filepath, "bin"));
      if (!reader.get()) {
        printf("WARNING: Missing baseline file for BWE test: %s.bin\n",
               filepath.c_str());
        fail_to_read_response_ = allow_missing_file;
      } else {
        uint32_t magic_marker = 0;
        uint32_t file_version = 0;
        if (reader->Read(&magic_marker) && magic_marker == kMagicMarker &&
            reader->Read(&file_version) && file_version == kFileVersion1) {
          reader_.swap(reader);
        } else {
          printf("WARNING: Bad baseline file header for BWE test: %s.bin\n",
                 filepath.c_str());
        }
      }
    }
    virtual ~BaseLineFileVerify() {}
  
    virtual void Estimate(int64_t time_ms, uint32_t estimate_bps) {
      if (reader_.get()) {
        uint32_t read_ms = 0;
        uint32_t read_bps = 0;
        if (reader_->Read(&read_ms) && read_ms == time_ms &&
            reader_->Read(&read_bps) && read_bps == estimate_bps) {
        } else {
          printf("ERROR: Baseline differs starting at: %d ms (%d vs %d)!\n",
                 static_cast<uint32_t>(time_ms), estimate_bps, read_bps);
          reader_.reset(NULL);
        }
      }
    }
  
    virtual bool VerifyOrWrite() {
      if (reader_.get()) {
        if (reader_->IsAtEnd()) {
          return true;
        } else {
          printf("ERROR: Baseline file contains more data!\n");
          return false;
        }
      }
      return fail_to_read_response_;
    }
  
   private:
    std::unique_ptr<ResourceFileReader> reader_;
    bool fail_to_read_response_;
  
    RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BaseLineFileVerify);
  };
  
  class BaseLineFileUpdate : public BaseLineFileInterface {
   public:
    BaseLineFileUpdate(const std::string& filepath,
                       BaseLineFileInterface* verifier)
        : verifier_(verifier), output_content_(), filepath_(filepath) {
      output_content_.push_back(kMagicMarker);
      output_content_.push_back(kFileVersion1);
    }
    virtual ~BaseLineFileUpdate() {}
  
    virtual void Estimate(int64_t time_ms, uint32_t estimate_bps) {
      verifier_->Estimate(time_ms, estimate_bps);
      output_content_.push_back(static_cast<uint32_t>(time_ms));
      output_content_.push_back(estimate_bps);
    }
  
    virtual bool VerifyOrWrite() {
      if (!verifier_->VerifyOrWrite()) {
        std::string dir_path = webrtc::test::OutputPath() + kResourceSubDir;
        if (!webrtc::test::CreateDir(dir_path)) {
          printf("WARNING: Cannot create output dir: %s\n", dir_path.c_str());
          return false;
        }
        std::unique_ptr<OutputFileWriter> writer;
        writer.reset(OutputFileWriter::Create(filepath_, "bin"));
        if (!writer.get()) {
          printf("WARNING: Cannot create output file: %s.bin\n",
                 filepath_.c_str());
          return false;
        }
        printf("NOTE: Writing baseline file for BWE test: %s.bin\n",
               filepath_.c_str());
        for (std::vector<uint32_t>::iterator it = output_content_.begin();
             it != output_content_.end(); ++it) {
          writer->Write(*it);
        }
        return true;
      }
      printf("NOTE: No change, not writing: %s\n", filepath_.c_str());
      return true;
    }
  
   private:
    std::unique_ptr<BaseLineFileInterface> verifier_;
    std::vector<uint32_t> output_content_;
    std::string filepath_;
  
    RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(BaseLineFileUpdate);
  };
  
  BaseLineFileInterface* BaseLineFileInterface::Create(
      const std::string& filename,
      bool write_output_file) {
    std::string filepath = filename;
    std::replace(filepath.begin(), filepath.end(), '/', '_');
    filepath = std::string(kResourceSubDir) + "/" + filepath;
  
    std::unique_ptr<BaseLineFileInterface> result;
    result.reset(new BaseLineFileVerify(filepath, !write_output_file));
    if (write_output_file) {
      // Takes ownership of the |verifier| instance.
      result.reset(new BaseLineFileUpdate(filepath, result.release()));
    }
    return result.release();
  }
  }  // namespace bwe
  }  // namespace testing
  }  // namespace webrtc
  