<commit_before>// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bloom.h"

#include "core.h"
#include "script.h"

#include <math.h>
#include <stdlib.h>

#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552

using namespace std;

static const unsigned char bit_mask[8] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};

CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) :
// The ideal size for a bloom filter with a given number of elements and false positive rate is:
// - nElements * log(fp rate) / ln(2)^2
// We ignore filter parameters which will create a bloom filter larger than the protocol limits
vData(min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
// The ideal number of hash functions is filter size * ln(2) / number of elements
// Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
// See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
isFull(false),
isEmpty(false),
nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn)
{
}

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
{
    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}

void CBloomFilter::insert(const vector<unsigned char>& vKey)
{
    if (isFull)
        return;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Sets bit nIndex of vData
        vData[nIndex >> 3] |= bit_mask[7 & nIndex];
    }
    isEmpty = false;
}

void CBloomFilter::insert(const COutPoint& outpoint)
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    vector<unsigned char> data(stream.begin(), stream.end());
    insert(data);
}

void CBloomFilter::insert(const uint256& hash)
{
    vector<unsigned char> data(hash.begin(), hash.end());
    insert(data);
}

bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
{
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Checks bit nIndex of vData
        if (!(vData[nIndex >> 3] & bit_mask[7 & nIndex]))
            return false;
    }
    return true;
}

bool CBloomFilter::contains(const COutPoint& outpoint) const
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    vector<unsigned char> data(stream.begin(), stream.end());
    return contains(data);
}

bool CBloomFilter::contains(const uint256& hash) const
{
    vector<unsigned char> data(hash.begin(), hash.end());
    return contains(data);
}

bool CBloomFilter::IsWithinSizeConstraints() const
{
    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}

bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash)
{
    bool fFound = false;
    // Match if the filter contains the hash of tx
    //  for finding tx when they appear in a block
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    if (contains(hash))
        fFound = true;

    for (unsigned int i = 0; i < tx.vout.size(); i++)
    {
        const CTxOut& txout = tx.vout[i];
        // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
        // If this matches, also add the specific output that was matched.
        // This means clients don't have to update the filter themselves when a new relevant tx
        // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
        CScript::const_iterator pc = txout.scriptPubKey.begin();
        vector<unsigned char> data;
        while (pc < txout.scriptPubKey.end())
        {
            opcodetype opcode;
            if (!txout.scriptPubKey.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
            {
                fFound = true;
                if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
                    insert(COutPoint(hash, i));
                else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
                {
                    txnouttype type;
                    vector<vector<unsigned char> > vSolutions;
                    if (Solver(txout.scriptPubKey, type, vSolutions) &&
                            (type == TX_PUBKEY || type == TX_MULTISIG))
                        insert(COutPoint(hash, i));
                }
                break;
            }
        }
    }

    if (fFound)
        return true;

    BOOST_FOREACH(const CTxIn& txin, tx.vin)
    {
        // Match if the filter contains an outpoint tx spends
        if (contains(txin.prevout))
            return true;

        // Match if the filter contains any arbitrary script data element in any scriptSig in tx
        CScript::const_iterator pc = txin.scriptSig.begin();
        vector<unsigned char> data;
        while (pc < txin.scriptSig.end())
        {
            opcodetype opcode;
            if (!txin.scriptSig.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
                return true;
        }
    }

    return false;
}

void CBloomFilter::UpdateEmptyFull()
{
    bool full = true;
    bool empty = true;
    for (unsigned int i = 0; i < vData.size(); i++)
    {
        full &= vData[i] == 0xff;
        empty &= vData[i] == 0;
    }
    isFull = full;
    isEmpty = empty;
}
<commit_msg>Fix bloom filter not to use bit_mask<commit_after>// Copyright (c) 2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "bloom.h"

#include "core.h"
#include "script.h"

#include <math.h>
#include <stdlib.h>

#define LN2SQUARED 0.4804530139182014246671025263266649717305529515945455
#define LN2 0.6931471805599453094172321214581765680755001343602552

using namespace std;

CBloomFilter::CBloomFilter(unsigned int nElements, double nFPRate, unsigned int nTweakIn, unsigned char nFlagsIn) :
// The ideal size for a bloom filter with a given number of elements and false positive rate is:
// - nElements * log(fp rate) / ln(2)^2
// We ignore filter parameters which will create a bloom filter larger than the protocol limits
vData(min((unsigned int)(-1  / LN2SQUARED * nElements * log(nFPRate)), MAX_BLOOM_FILTER_SIZE * 8) / 8),
// The ideal number of hash functions is filter size * ln(2) / number of elements
// Again, we ignore filter parameters which will create a bloom filter with more hash functions than the protocol limits
// See http://en.wikipedia.org/wiki/Bloom_filter for an explanation of these formulas
isFull(false),
isEmpty(false),
nHashFuncs(min((unsigned int)(vData.size() * 8 / nElements * LN2), MAX_HASH_FUNCS)),
nTweak(nTweakIn),
nFlags(nFlagsIn)
{
}

inline unsigned int CBloomFilter::Hash(unsigned int nHashNum, const std::vector<unsigned char>& vDataToHash) const
{
    // 0xFBA4C795 chosen as it guarantees a reasonable bit difference between nHashNum values.
    return MurmurHash3(nHashNum * 0xFBA4C795 + nTweak, vDataToHash) % (vData.size() * 8);
}

void CBloomFilter::insert(const vector<unsigned char>& vKey)
{
    if (isFull)
        return;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Sets bit nIndex of vData
        vData[nIndex >> 3] |= (1 << (7 & nIndex));
    }
    isEmpty = false;
}

void CBloomFilter::insert(const COutPoint& outpoint)
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    vector<unsigned char> data(stream.begin(), stream.end());
    insert(data);
}

void CBloomFilter::insert(const uint256& hash)
{
    vector<unsigned char> data(hash.begin(), hash.end());
    insert(data);
}

bool CBloomFilter::contains(const vector<unsigned char>& vKey) const
{
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    for (unsigned int i = 0; i < nHashFuncs; i++)
    {
        unsigned int nIndex = Hash(i, vKey);
        // Checks bit nIndex of vData
        if (!(vData[nIndex >> 3] & (1 << (7 & nIndex))))
            return false;
    }
    return true;
}

bool CBloomFilter::contains(const COutPoint& outpoint) const
{
    CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
    stream << outpoint;
    vector<unsigned char> data(stream.begin(), stream.end());
    return contains(data);
}

bool CBloomFilter::contains(const uint256& hash) const
{
    vector<unsigned char> data(hash.begin(), hash.end());
    return contains(data);
}

bool CBloomFilter::IsWithinSizeConstraints() const
{
    return vData.size() <= MAX_BLOOM_FILTER_SIZE && nHashFuncs <= MAX_HASH_FUNCS;
}

bool CBloomFilter::IsRelevantAndUpdate(const CTransaction& tx, const uint256& hash)
{
    bool fFound = false;
    // Match if the filter contains the hash of tx
    //  for finding tx when they appear in a block
    if (isFull)
        return true;
    if (isEmpty)
        return false;
    if (contains(hash))
        fFound = true;

    for (unsigned int i = 0; i < tx.vout.size(); i++)
    {
        const CTxOut& txout = tx.vout[i];
        // Match if the filter contains any arbitrary script data element in any scriptPubKey in tx
        // If this matches, also add the specific output that was matched.
        // This means clients don't have to update the filter themselves when a new relevant tx
        // is discovered in order to find spending transactions, which avoids round-tripping and race conditions.
        CScript::const_iterator pc = txout.scriptPubKey.begin();
        vector<unsigned char> data;
        while (pc < txout.scriptPubKey.end())
        {
            opcodetype opcode;
            if (!txout.scriptPubKey.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
            {
                fFound = true;
                if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_ALL)
                    insert(COutPoint(hash, i));
                else if ((nFlags & BLOOM_UPDATE_MASK) == BLOOM_UPDATE_P2PUBKEY_ONLY)
                {
                    txnouttype type;
                    vector<vector<unsigned char> > vSolutions;
                    if (Solver(txout.scriptPubKey, type, vSolutions) &&
                            (type == TX_PUBKEY || type == TX_MULTISIG))
                        insert(COutPoint(hash, i));
                }
                break;
            }
        }
    }

    if (fFound)
        return true;

    BOOST_FOREACH(const CTxIn& txin, tx.vin)
    {
        // Match if the filter contains an outpoint tx spends
        if (contains(txin.prevout))
            return true;

        // Match if the filter contains any arbitrary script data element in any scriptSig in tx
        CScript::const_iterator pc = txin.scriptSig.begin();
        vector<unsigned char> data;
        while (pc < txin.scriptSig.end())
        {
            opcodetype opcode;
            if (!txin.scriptSig.GetOp(pc, opcode, data))
                break;
            if (data.size() != 0 && contains(data))
                return true;
        }
    }

    return false;
}

void CBloomFilter::UpdateEmptyFull()
{
    bool full = true;
    bool empty = true;
    for (unsigned int i = 0; i < vData.size(); i++)
    {
        full &= vData[i] == 0xff;
        empty &= vData[i] == 0;
    }
    isFull = full;
    isEmpty = empty;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 The WebM 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 "encoder/dash_writer.h"

#include <ios>
#include <sstream>

#include "glog/logging.h"

namespace webmlive {
const char kIndentStep[] = "  ";

// Default values for DashConfig. Time values in seconds unless otherwise noted.
// TODO(tomfinegan): Not sure if default belongs in the name for schema and
// profiles here; should these be configurable?
const char kDefaultSchema[] = "urn:mpeg:dash:schema:mpd:2011";
const int kDefaultMinBufferTime = 1;
const int kDefaultMediaPresentationDuration = 36000;  // 10 hours.
const char kDefaultType[] = "static";
const char kDefaultProfiles[] = "urn:mpeg:dash:profile:isoff-live:2011";
const int kDefaultStartTime = 0;
const int kDefaultMaxWidth = 1920;
const int kDefaultMaxHeight = 1080;
const int kDefaultMaxFrameRate = 60;
const int kDefaultContentComponentId = 1;
const char kContentComponentTypeAudio[] = "audio";
const char kContentComponentTypeVideo[] = "video";
const int kDefaultPeriodDuration = kDefaultMediaPresentationDuration;
const int kDefaultTimescale = 1000;  // milliseconds.
const int kDefaultChunkDuration = 5000;  // milliseconds.
const std::string kDefaultStartNumber = "1";
const int kDefaultStartWithSap = 1;
const int kDefaultBandwidth = 1000000;  // Bits.
const int kDefaultFrameRate = 30;
const int kDefaultAudioSampleRate = 44100;
const int kDefaultAudioChannels = 2;

const char kAudioMimeType[] = "audio/webm";
const char kVideoMimeType[] = "video/webm";
const char kAudioCodecs[] = "vorbis";
const char kVideoCodecs[] = "vp9";
const char kAudioId[] = "1";
const char kVideoId[] = "2";

// Base strings for initialization and chunk names.
const char kChunkPattern[] = "_$RepresentationID$_$Number$.chk";
const char kInitializationPattern[] = "_$RepresentationID$.hdr";

const char kAudioSchemeUri[] =
  "urn:mpeg:dash:23003:3:audio_channel_configuration:2011";

//
// AdaptationSet
//
AdaptationSet::AdaptationSet()
    : enabled(false),
      media_type(kVideo),
      segment_alignment(true),
      bitstream_switching(false),
      cc_id(kVideoId),
      content_type(kContentComponentTypeVideo),
      timescale(kDefaultTimescale),
      chunk_duration(kDefaultChunkDuration),
      start_number(kDefaultStartNumber),
      start_with_sap(kDefaultStartWithSap),
      bandwidth(kDefaultBandwidth) {}

//
// AudioAdaptationSet
//
AudioAdaptationSet::AudioAdaptationSet()
    : audio_sampling_rate(kDefaultAudioSampleRate),
      scheme_id_uri(kAudioSchemeUri),
      value(kDefaultAudioChannels) {
  media_type = kAudio;
  content_type = kContentComponentTypeAudio;
  mimetype = kAudioMimeType;
  codecs = kAudioCodecs;
}

//
// VideoAdaptationSet
//
VideoAdaptationSet::VideoAdaptationSet()
    : max_width(kDefaultMaxWidth),
      max_height(kDefaultMaxHeight),
      max_frame_rate(kDefaultMaxFrameRate),
      width(kDefaultMaxWidth),
      height(kDefaultMaxHeight),
      frame_rate(kDefaultFrameRate) {
  media_type = kVideo;
  cc_id = kAudioId;
  mimetype = kVideoMimeType;
  codecs = kVideoCodecs;
}

//
// DashConfig
//
DashConfig::DashConfig()
      : type(kDefaultType),
        min_buffer_time(kDefaultMinBufferTime),
        media_presentation_duration(kDefaultMediaPresentationDuration),
        start_time(kDefaultStartTime),
        period_duration(kDefaultPeriodDuration) {}

//
// DashWriter
//

bool DashWriter::Init(const WebmEncoderConfig& webm_config) {
  if (webm_config.dash_name.empty()) {
    LOG(ERROR) << "name empty in DashWriter::Init()";
    return false;
  }

  name_ = webm_config.dash_name;

  if (!webm_config.disable_audio) {
    config_.audio_as.enabled = true;
    config_.audio_as.bandwidth =
        webm_config.vorbis_config.average_bitrate * 1000;
    config_.audio_as.media = name_ + kChunkPattern;
    config_.audio_as.initialization = name_ + kInitializationPattern;
    config_.audio_as.rep_id = kAudioId;
    config_.audio_as.audio_sampling_rate =
        webm_config.actual_audio_config.sample_rate;
    config_.audio_as.value = webm_config.actual_audio_config.channels;
    config_.audio_as.start_number = webm_config.dash_start_number;
  }
  if (!webm_config.disable_video) {
    config_.video_as.enabled = true;
    config_.video_as.bandwidth = webm_config.vpx_config.bitrate * 1000;
    config_.video_as.media = name_ + kChunkPattern;
    config_.video_as.initialization = name_ + kInitializationPattern;
    config_.video_as.rep_id = kVideoId;
    config_.video_as.width = webm_config.actual_video_config.width;
    config_.video_as.height = webm_config.actual_video_config.height;
    config_.video_as.start_number = webm_config.dash_start_number;

    if (webm_config.vpx_config.decimate != VpxConfig::kUseDefault) {
      config_.video_as.frame_rate = static_cast<int>(
          std::ceil(webm_config.actual_video_config.frame_rate /
                    webm_config.vpx_config.decimate));
    } else {
      config_.video_as.frame_rate = static_cast<int>(
          std::ceil(webm_config.actual_video_config.frame_rate));
    }

    if (config_.video_as.frame_rate > config_.video_as.max_frame_rate) {
      config_.video_as.max_frame_rate = config_.video_as.frame_rate;
    }
  }

  config_.audio_as.chunk_duration = webm_config.vpx_config.keyframe_interval;
  config_.video_as.chunk_duration = webm_config.vpx_config.keyframe_interval;

  initialized_ = true;
  return true;
}

bool DashWriter::WriteManifest(std::string* out_manifest) {
  CHECK_NOTNULL(out_manifest);
  if (!initialized_) {
    LOG(ERROR) << "DashWriter not initialized before call to WriteManifest()";
    return false;
  }

  std::ostringstream manifest;

  manifest << "<?xml version=\"1.0\"?>\n";

  // Open the MPD element.
  manifest << "<MPD "
           << "xmlns=\"" << kDefaultSchema << "\" "
           << "type=\"" << config_.type << "\" "
           << "minBufferTime=\"PT" << config_.min_buffer_time << "S\" "
           << "mediaPresentationDuration=\"PT"
           << config_.media_presentation_duration << "S\" "
           << "profiles=\"" << kDefaultProfiles << "\">"
           << "\n";
  IncreaseIndent();

  // Open the Period element.
  manifest << indent_
           << "<Period "
           << "start=\"PT" << config_.start_time << "S\" "
           << "duration=\"PT" << config_.period_duration << "S\">"
           << "\n";
  IncreaseIndent();

  if (config_.audio_as.enabled) {
    std::string audio_as;
    WriteAudioAdaptationSet(&audio_as);
    manifest << audio_as;
  }

  if (config_.video_as.enabled) {
    std::string video_as;
    WriteVideoAdaptationSet(&video_as);
    manifest << video_as;
  }

  // Close open elements.
  DecreaseIndent();
  manifest << indent_ << "</Period>\n";
  DecreaseIndent();
  manifest << indent_ << "</MPD>\n";

  LOG(INFO) << "\nmanifest:\n" << manifest.str();
  *out_manifest = manifest.str();
  return true;
}

std::string DashWriter::IdForChunk(AdaptationSet::MediaType media_type,
                                   int64 chunk_num) const {
  CHECK(initialized_);
  std::string initialization;
  std::string media;
  if (media_type == AdaptationSet::kAudio) {
    initialization = name_ + "_" + kAudioId + ".hdr";
    media  = name_ + "_" + kAudioId + "_";
  } else {
    initialization = name_ + "_" + kVideoId + ".hdr";
    media  = name_ + "_" + kVideoId + "_";
  }

  std::ostringstream id;
  if (chunk_num == 0) {
    id << initialization << "";
  } else {
    id << media << chunk_num << ".chk";
  }
  return id.str();
}

void DashWriter::WriteAudioAdaptationSet(std::string* adaptation_set) {
  CHECK_NOTNULL(adaptation_set);
  std::ostringstream a_stream;
  const AudioAdaptationSet& audio_as = config_.audio_as;

  // Open the AdaptationSet element.
  a_stream << indent_
           << "<AdaptationSet "
           << "segmentAlignment=\""
           << std::boolalpha << audio_as.segment_alignment << "\" "
           << "audioSamplingRate=\"" << audio_as.audio_sampling_rate << "\" "
           << "bitstreamSwitching=\"" << audio_as.bitstream_switching << "\">"
           << "\n";
  IncreaseIndent();

  // Write AudioChannelConfiguration element.
  a_stream << indent_
           << "<AudioChannelConfiguration "
           << "schemeIdUri=\"" << audio_as.scheme_id_uri << "\" "
           << "value=\"" << audio_as.value << "\">"
           << "</AudioChannelConfiguration>"
           << "\n";

  // Write ContentComponent element.
  a_stream << indent_
           << "<ContentComponent "
           << "id=\"" << audio_as.cc_id << "\" "
           << "contentType=\"" << audio_as.content_type << "\"/>"
           << "\n";

  // Write SegmentTemplate element.
  a_stream << indent_
           << "<SegmentTemplate "
           << "timescale=\"" << audio_as.timescale << "\" "
           << "duration=\"" << audio_as.chunk_duration << "\" "
           << "media=\"" << audio_as.media << "\" "
           << "startNumber=\"" << audio_as.start_number << "\" "
           << "initialization=\"" << audio_as.initialization << "\"/>"
           << "\n";

  // Write the Representation element.
  a_stream << indent_
           << "<Representation "
           << "id=\"" << audio_as.rep_id << "\" "
           << "mimeType=\"" << audio_as.mimetype << "\" "
           << "codecs=\"" << audio_as.codecs << "\" "
           << "startWithSAP=\"" << audio_as.start_with_sap << "\" "
           << "bandwidth=\"" << audio_as.bandwidth << "\" "
           << "></Representation>"
           << "\n";

  // Close open the AdaptationSet element.
  DecreaseIndent();
  a_stream << indent_ << "</AdaptationSet>\n";
  *adaptation_set = a_stream.str();
}

void DashWriter::WriteVideoAdaptationSet(std::string* adaptation_set) {
  CHECK_NOTNULL(adaptation_set);
  std::ostringstream v_stream;
  const VideoAdaptationSet& video_as = config_.video_as;

  // Open the AdaptationSet element.
  v_stream << indent_
           << "<AdaptationSet "
           << "segmentAlignment=\""
           << std::boolalpha << video_as.segment_alignment << "\" "
           << "bitstreamSwitching=\"" << video_as.bitstream_switching << "\" "
           << "maxWidth=\"" << video_as.max_width << "\" "
           << "maxHeight=\"" << video_as.max_height << "\" "
           << "maxFrameRate=\"" << video_as.max_frame_rate << "\">"
           << "\n";
  IncreaseIndent();

  // Write ContentComponent element.
  v_stream << indent_
           << "<ContentComponent "
           << "id=\"" << video_as.cc_id << "\" "
           << "contentType=\"" << video_as.content_type << "\"/>"
           << "\n";

  // Write SegmentTemplate element.
  v_stream << indent_
           << "<SegmentTemplate "
           << "timescale=\"" << video_as.timescale << "\" "
           << "duration=\"" << video_as.chunk_duration << "\" "
           << "media=\"" << video_as.media << "\" "
           << "startNumber=\"" << video_as.start_number << "\" "
           << "initialization=\"" << video_as.initialization << "\"/>"
           << "\n";

  // Write the Representation element.
  v_stream << indent_
           << "<Representation "
           << "id=\"" << video_as.rep_id << "\" "
           << "mimeType=\"" << video_as.mimetype << "\" "
           << "codecs=\"" << video_as.codecs << "\" "
           << "width=\"" << video_as.width << "\" "
           << "height=\"" << video_as.height << "\" "
           << "startWithSAP=\"" << video_as.start_with_sap << "\" "
           << "bandwidth=\"" << video_as.bandwidth << "\" "
           << "frameRate=\"" << video_as.frame_rate << "\" "
           << "></Representation>"
           << "\n";

  // Close open the AdaptationSet element.
  DecreaseIndent();
  v_stream << indent_ << "</AdaptationSet>\n";
  *adaptation_set = v_stream.str();
}

void DashWriter::IncreaseIndent() {
  indent_ = indent_ + kIndentStep;
}

void DashWriter::DecreaseIndent() {
  std::string indent_step = kIndentStep;
  if (indent_.length() > 0)
    indent_ = indent_.substr(0, indent_.length() - indent_step.length());
}

void DashWriter::ResetIndent() {
  indent_ = "";
}

}  // namespace webmlive
<commit_msg>dash_writer: Update MPD output to allow live streaming<commit_after>// Copyright (c) 2015 The WebM 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 "encoder/dash_writer.h"

#include <ctime>
#include <ios>
#include <sstream>

#include "glog/logging.h"

#include "encoder/time_util.h"

namespace webmlive {
const char kIndentStep[] = "  ";

// Default values for DashConfig. Time values in seconds unless otherwise noted.
// TODO(tomfinegan): Not sure if default belongs in the name for schema and
// profiles here; should these be configurable?
const char kDefaultSchema[] = "urn:mpeg:dash:schema:mpd:2011";
const int kDefaultMinBufferTime = 1;
const int kDefaultMediaPresentationDuration = 36000;  // 10 hours.
const char kDefaultType[] = "dynamic";
const char kDefaultProfiles[] = "urn:mpeg:dash:profile:isoff-live:2011";
const int kDefaultStartTime = 0;
const int kDefaultMaxWidth = 1920;
const int kDefaultMaxHeight = 1080;
const int kDefaultMaxFrameRate = 60;
const int kDefaultContentComponentId = 1;
const char kContentComponentTypeAudio[] = "audio";
const char kContentComponentTypeVideo[] = "video";
const int kDefaultPeriodDuration = kDefaultMediaPresentationDuration;
const int kDefaultTimescale = 1000;  // milliseconds.
const int kDefaultChunkDuration = 5000;  // milliseconds.
const std::string kDefaultStartNumber = "1";
const int kDefaultStartWithSap = 1;
const int kDefaultBandwidth = 1000000;  // Bits.
const int kDefaultFrameRate = 30;
const int kDefaultAudioSampleRate = 44100;
const int kDefaultAudioChannels = 2;

const char kAudioMimeType[] = "audio/webm";
const char kVideoMimeType[] = "video/webm";
const char kAudioCodecs[] = "vorbis";
const char kVideoCodecs[] = "vp9";
const char kAudioId[] = "1";
const char kVideoId[] = "2";

// Base strings for initialization and chunk names.
const char kChunkPattern[] = "_$RepresentationID$_$Number$.chk";
const char kInitializationPattern[] = "_$RepresentationID$.hdr";

const char kAudioSchemeUri[] =
  "urn:mpeg:dash:23003:3:audio_channel_configuration:2011";

// %Y - year
// %m - month, zero padded (01-12)
// %d - day of month, zero padded (01-31).
// %H - hour, zero padded, 24 hour clock (00-23)
// %M - minute, zero padded (00-59)
// %S - second, zero padded (00-61)
const char kAvailabilityStartTimeFormat[] = "%Y-%m-%dT%H:%M:%SZ";

//
// AdaptationSet
//
AdaptationSet::AdaptationSet()
    : enabled(false),
      media_type(kVideo),
      segment_alignment(true),
      bitstream_switching(false),
      cc_id(kVideoId),
      content_type(kContentComponentTypeVideo),
      timescale(kDefaultTimescale),
      chunk_duration(kDefaultChunkDuration),
      start_number(kDefaultStartNumber),
      start_with_sap(kDefaultStartWithSap),
      bandwidth(kDefaultBandwidth) {}

//
// AudioAdaptationSet
//
AudioAdaptationSet::AudioAdaptationSet()
    : audio_sampling_rate(kDefaultAudioSampleRate),
      scheme_id_uri(kAudioSchemeUri),
      value(kDefaultAudioChannels) {
  media_type = kAudio;
  content_type = kContentComponentTypeAudio;
  mimetype = kAudioMimeType;
  codecs = kAudioCodecs;
}

//
// VideoAdaptationSet
//
VideoAdaptationSet::VideoAdaptationSet()
    : max_width(kDefaultMaxWidth),
      max_height(kDefaultMaxHeight),
      max_frame_rate(kDefaultMaxFrameRate),
      width(kDefaultMaxWidth),
      height(kDefaultMaxHeight),
      frame_rate(kDefaultFrameRate) {
  media_type = kVideo;
  cc_id = kAudioId;
  mimetype = kVideoMimeType;
  codecs = kVideoCodecs;
}

//
// DashConfig
//
DashConfig::DashConfig()
      : type(kDefaultType),
        min_buffer_time(kDefaultMinBufferTime),
        media_presentation_duration(kDefaultMediaPresentationDuration),
        start_time(kDefaultStartTime),
        period_duration(kDefaultPeriodDuration) {}

//
// DashWriter
//

bool DashWriter::Init(const WebmEncoderConfig& webm_config) {
  if (webm_config.dash_name.empty()) {
    LOG(ERROR) << "name empty in DashWriter::Init()";
    return false;
  }

  name_ = webm_config.dash_name;

  if (!webm_config.disable_audio) {
    config_.audio_as.enabled = true;
    config_.audio_as.bandwidth =
        webm_config.vorbis_config.average_bitrate * 1000;
    config_.audio_as.media = name_ + kChunkPattern;
    config_.audio_as.initialization = name_ + kInitializationPattern;
    config_.audio_as.rep_id = kAudioId;
    config_.audio_as.audio_sampling_rate =
        webm_config.actual_audio_config.sample_rate;
    config_.audio_as.value = webm_config.actual_audio_config.channels;
    config_.audio_as.start_number = webm_config.dash_start_number;
  }
  if (!webm_config.disable_video) {
    config_.video_as.enabled = true;
    config_.video_as.bandwidth = webm_config.vpx_config.bitrate * 1000;
    config_.video_as.media = name_ + kChunkPattern;
    config_.video_as.initialization = name_ + kInitializationPattern;
    config_.video_as.rep_id = kVideoId;
    config_.video_as.width = webm_config.actual_video_config.width;
    config_.video_as.height = webm_config.actual_video_config.height;
    config_.video_as.start_number = webm_config.dash_start_number;

    if (webm_config.vpx_config.decimate != VpxConfig::kUseDefault) {
      config_.video_as.frame_rate = static_cast<int>(
          std::ceil(webm_config.actual_video_config.frame_rate /
                    webm_config.vpx_config.decimate));
    } else {
      config_.video_as.frame_rate = static_cast<int>(
          std::ceil(webm_config.actual_video_config.frame_rate));
    }

    if (config_.video_as.frame_rate > config_.video_as.max_frame_rate) {
      config_.video_as.max_frame_rate = config_.video_as.frame_rate;
    }
  }

  config_.audio_as.chunk_duration = webm_config.vpx_config.keyframe_interval;
  config_.video_as.chunk_duration = webm_config.vpx_config.keyframe_interval;

  initialized_ = true;
  return true;
}

bool DashWriter::WriteManifest(std::string* out_manifest) {
  CHECK_NOTNULL(out_manifest);
  if (!initialized_) {
    LOG(ERROR) << "DashWriter not initialized before call to WriteManifest()";
    return false;
  }

  std::ostringstream manifest;

  manifest << "<?xml version=\"1.0\"?>\n";

  time_t raw_time = time(NULL);

  // Open the MPD element.
  manifest << "<MPD "
           << "xmlns=\"" << kDefaultSchema << "\" "
           << "type=\"" << config_.type << "\" "
           << "availabilityStartTime=\""
           << StrFTime(gmtime(&raw_time), kAvailabilityStartTimeFormat)
           << "\" "
           << "minBufferTime=\"PT" << config_.min_buffer_time << "S\" "
           << "mediaPresentationDuration=\"PT"
           << config_.media_presentation_duration << "S\" "
           << "profiles=\"" << kDefaultProfiles << "\">"
           << "\n";
  IncreaseIndent();

  // Open the Period element.
  manifest << indent_
           << "<Period "
           << "start=\"PT" << config_.start_time << "S\" "
           << "duration=\"PT" << config_.period_duration << "S\">"
           << "\n";
  IncreaseIndent();

  if (config_.audio_as.enabled) {
    std::string audio_as;
    WriteAudioAdaptationSet(&audio_as);
    manifest << audio_as;
  }

  if (config_.video_as.enabled) {
    std::string video_as;
    WriteVideoAdaptationSet(&video_as);
    manifest << video_as;
  }

  // Close open elements.
  DecreaseIndent();
  manifest << indent_ << "</Period>\n";
  DecreaseIndent();
  manifest << indent_ << "</MPD>\n";

  LOG(INFO) << "\nmanifest:\n" << manifest.str();
  *out_manifest = manifest.str();
  return true;
}

std::string DashWriter::IdForChunk(AdaptationSet::MediaType media_type,
                                   int64 chunk_num) const {
  CHECK(initialized_);
  std::string initialization;
  std::string media;
  if (media_type == AdaptationSet::kAudio) {
    initialization = name_ + "_" + kAudioId + ".hdr";
    media  = name_ + "_" + kAudioId + "_";
  } else {
    initialization = name_ + "_" + kVideoId + ".hdr";
    media  = name_ + "_" + kVideoId + "_";
  }

  std::ostringstream id;
  if (chunk_num == 0) {
    id << initialization << "";
  } else {
    id << media << chunk_num << ".chk";
  }
  return id.str();
}

void DashWriter::WriteAudioAdaptationSet(std::string* adaptation_set) {
  CHECK_NOTNULL(adaptation_set);
  std::ostringstream a_stream;
  const AudioAdaptationSet& audio_as = config_.audio_as;

  // Open the AdaptationSet element.
  a_stream << indent_
           << "<AdaptationSet "
           << "segmentAlignment=\""
           << std::boolalpha << audio_as.segment_alignment << "\" "
           << "audioSamplingRate=\"" << audio_as.audio_sampling_rate << "\" "
           << "bitstreamSwitching=\"" << audio_as.bitstream_switching << "\">"
           << "\n";
  IncreaseIndent();

  // Write AudioChannelConfiguration element.
  a_stream << indent_
           << "<AudioChannelConfiguration "
           << "schemeIdUri=\"" << audio_as.scheme_id_uri << "\" "
           << "value=\"" << audio_as.value << "\">"
           << "</AudioChannelConfiguration>"
           << "\n";

  // Write ContentComponent element.
  a_stream << indent_
           << "<ContentComponent "
           << "id=\"" << audio_as.cc_id << "\" "
           << "contentType=\"" << audio_as.content_type << "\"/>"
           << "\n";

  // Write SegmentTemplate element.
  a_stream << indent_
           << "<SegmentTemplate "
           << "timescale=\"" << audio_as.timescale << "\" "
           << "duration=\"" << audio_as.chunk_duration << "\" "
           << "media=\"" << audio_as.media << "\" "
           << "startNumber=\"" << audio_as.start_number << "\" "
           << "initialization=\"" << audio_as.initialization << "\"/>"
           << "\n";

  // Write the Representation element.
  a_stream << indent_
           << "<Representation "
           << "id=\"" << audio_as.rep_id << "\" "
           << "mimeType=\"" << audio_as.mimetype << "\" "
           << "codecs=\"" << audio_as.codecs << "\" "
           << "startWithSAP=\"" << audio_as.start_with_sap << "\" "
           << "bandwidth=\"" << audio_as.bandwidth << "\" "
           << "></Representation>"
           << "\n";

  // Close open the AdaptationSet element.
  DecreaseIndent();
  a_stream << indent_ << "</AdaptationSet>\n";
  *adaptation_set = a_stream.str();
}

void DashWriter::WriteVideoAdaptationSet(std::string* adaptation_set) {
  CHECK_NOTNULL(adaptation_set);
  std::ostringstream v_stream;
  const VideoAdaptationSet& video_as = config_.video_as;

  // Open the AdaptationSet element.
  v_stream << indent_
           << "<AdaptationSet "
           << "segmentAlignment=\""
           << std::boolalpha << video_as.segment_alignment << "\" "
           << "bitstreamSwitching=\"" << video_as.bitstream_switching << "\" "
           << "maxWidth=\"" << video_as.max_width << "\" "
           << "maxHeight=\"" << video_as.max_height << "\" "
           << "maxFrameRate=\"" << video_as.max_frame_rate << "\">"
           << "\n";
  IncreaseIndent();

  // Write ContentComponent element.
  v_stream << indent_
           << "<ContentComponent "
           << "id=\"" << video_as.cc_id << "\" "
           << "contentType=\"" << video_as.content_type << "\"/>"
           << "\n";

  // Write SegmentTemplate element.
  v_stream << indent_
           << "<SegmentTemplate "
           << "timescale=\"" << video_as.timescale << "\" "
           << "duration=\"" << video_as.chunk_duration << "\" "
           << "media=\"" << video_as.media << "\" "
           << "startNumber=\"" << video_as.start_number << "\" "
           << "initialization=\"" << video_as.initialization << "\"/>"
           << "\n";

  // Write the Representation element.
  v_stream << indent_
           << "<Representation "
           << "id=\"" << video_as.rep_id << "\" "
           << "mimeType=\"" << video_as.mimetype << "\" "
           << "codecs=\"" << video_as.codecs << "\" "
           << "width=\"" << video_as.width << "\" "
           << "height=\"" << video_as.height << "\" "
           << "startWithSAP=\"" << video_as.start_with_sap << "\" "
           << "bandwidth=\"" << video_as.bandwidth << "\" "
           << "frameRate=\"" << video_as.frame_rate << "\" "
           << "></Representation>"
           << "\n";

  // Close open the AdaptationSet element.
  DecreaseIndent();
  v_stream << indent_ << "</AdaptationSet>\n";
  *adaptation_set = v_stream.str();
}

void DashWriter::IncreaseIndent() {
  indent_ = indent_ + kIndentStep;
}

void DashWriter::DecreaseIndent() {
  std::string indent_step = kIndentStep;
  if (indent_.length() > 0)
    indent_ = indent_.substr(0, indent_.length() - indent_step.length());
}

void DashWriter::ResetIndent() {
  indent_ = "";
}

}  // namespace webmlive
<|endoftext|>


<commit_before>#include "client_net.h"
#include "interactive.h"
#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha3.h"
#include "spdlog/spdlog.h"
#include "logging.h"
#include "auth_common.h"
#include "packets/radius_packet.h"
#include "packets/eap_packet.h"
#include "packets/packet.h"
#include "packets/utils.h"

using namespace std;
const std::vector<byte> temp = {0xe0, 0xbd, 0x18, 0xdb, 0x4c, 0xc2, 0xf8, 0x5c,
                                0xed, 0xef, 0x65, 0x4f, 0xcc, 0xc4, 0xa4, 0xd8};

const std::string LOGGER_NAME = "client";
std::string hashString(std::string input, std::string hash);
int main(int argc, char **argv) {
    using namespace TCLAP;
    try {

        CmdLine cmd("NAS Test Client", ' ');

        ValueArg<string> logpathArg("l", "log",
                                    "The path where log file shall be written",
                                    false, "client.log", "string");
        cmd.add(logpathArg);

        ValueArg<string> loginArg(
            "u", "username", "The name of a user that wishes to authenticate",
            false, "Basia", "string");
        cmd.add(loginArg);

        ValueArg<string> passArg("", "password", "The password of a user",
                                 false, "password", "string");
        cmd.add(passArg);

        /*         SwitchArg interSwitch("i", "interactive", */
        /*                               "Run in the interactive mode", false);
         */
        /*         cmd.add(interSwitch); */

        SwitchArg verboseSwitch("v", "verbose", "Run in the verbose mode",
                                false);
        cmd.add(verboseSwitch);

        ValueArg<string> secretArg("s", "secret", "The secret shared with NAS",
                                   true, "", "string");
        cmd.add(secretArg);

        ValueArg<int> portArg("p", "port", "Binded port", false, 0, "number");
        cmd.add(portArg);

        ValueArg<string> bindIpArg("b", "bind-ip", "Binded IP address", false,
                                   "0.0.0.0", "IP");

        cmd.add(bindIpArg);

        ValueArg<string> ipArg("a", "address", "Server IP address", true, "",
                               "IP");

        cmd.add(ipArg);

        ValueArg<string> hashArg(
            "", "hash", "Type of hashing function (crc32 md5 sha1 sha256 sha3)",
            false, "sha256", "string");
        cmd.add(hashArg);

        cmd.parse(argc, argv);

        int port = portArg.getValue();
        string ip = ipArg.getValue();
        string bindIp = ipArg.getValue();
        string secret = secretArg.getValue();
        string logpath = logpathArg.getValue();
        radius::initLogger(logpath, LOGGER_NAME);

        bool verbose = verboseSwitch.getValue();
        if (verbose) {
            spdlog::set_level(spdlog::level::trace);
        }

        auto logger = spdlog::get(LOGGER_NAME);

        string hash = hashArg.getValue();

        string login = loginArg.getValue();
        string pas = passArg.getValue();
        /* bool inter = interSwitch.getValue(); */
        // setup address structure //adres serwera
        struct sockaddr_in server_addr;
        memset((char *)&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        /* if (inter) { */
        /*     login = radius::getUsername(); */
        /*     pas = radius::getPassword("Enter password:\n"); */
        /* } */
        pas = hashString(pas, hash);

        // radius::packets::Packet newPack(temp, server_addr);

        radius::startClient(ip.c_str(), port);
        // 1.access-request
        using namespace radius;
        using namespace radius::packets;
			EapPacket eapIdentity;
			eapIdentity = makeIdentity(login);
			eapIdentity.setType(EapPacket::RESPONSE);
			eapIdentity.setIdentifier(1);

			EapMessage eapMessage;
			eapMessage.setValue(eapIdentity.getBuffer());

			RadiusPacket arPacket;
			arPacket.setIdentifier(1);
			arPacket.setCode(RadiusPacket::ACCESS_REQUEST);
			std::array<radius::byte, 16> authTable = generateRandom16();
			arPacket.setAuthenticator(authTable);
			arPacket.addAVP(static_cast<const RadiusAVP &>(eapMessage));
			calcAndSetMsgAuth(arPacket, secret);

        radius::packets::Packet newPack(arPacket.getBuffer(), server_addr);
		logger->info() <<"Send Packet";
        logger->info() <<"[Packet:]\n" << packet2LogBytes(newPack.bytes);
		logger->info() <<"[RadiusPacket:]\n"<< arPacket;
		logger->info() <<"[EapPacket:]\n"<< eapIdentity;

        radius::sendPack(newPack);
        // 2.otrzymuj odpowiedz od Radius server
        newPack = radius::receivePack();

		RadiusPacket recArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" <<packet2LogBytes(recArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< recArPacket;
		EapPacket recEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< recEapIdentity;

			std::array<radius::byte,16> chalArray =calcChalVal(recEapIdentity,secret);

		//make response
		EapPacket eapMd5Chal;
		eapMd5Chal = makeChallengeResp(chalArray);
		eapMd5Chal.setType(EapPacket::RESPONSE);
		eapMd5Chal.setIdentifier(2);

			EapMessage eapMessage2;
			eapMessage2.setValue(eapMd5Chal.getBuffer());

		RadiusPacket responsePacket;
		responsePacket.setIdentifier(2);
		responsePacket.setCode(RadiusPacket::ACCESS_REQUEST);
		authTable = generateRandom16();
		responsePacket.setAuthenticator(authTable);
		responsePacket.addAVP(static_cast<const RadiusAVP &>(eapMessage2));
		calcAndSetMsgAuth(responsePacket, secret);

		radius::packets::Packet responsePack(responsePacket.getBuffer() , server_addr);

			logger->info() <<"Send Packet";
			logger->info() <<"[Packet:]\n" << packet2LogBytes(responsePack.bytes);
			logger->info() <<"[RadiusPacket:]\n"<< responsePacket;
			logger->info() <<"[EapPacket:]\n"<< eapMd5Chal;

        radius::sendPack(responsePack);
        // 4.success or failure
        //newPack = radius::receivePack();

        radius::stopClient();

    } catch (ArgException &e) {
        cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
    }
}

std::string hashString(std::string input, std::string hash) {
    std::string output;

    if (hash == "sha256") {
        SHA256 sha256;
        output = sha256(input);
    } else if (hash == "sha1") {
        SHA1 sha1;
        output = sha1(input);
    } else if (hash == "sha3") {
        SHA3 sha3;
        output = sha3(input);
    } else if (hash == "md5") {
        MD5 md5;
        output = md5(input);
    } else if (hash == "crc32") {
        CRC32 crc32;
        output = crc32(input);
    } else {
        output = input;
    }
    return output;
}
<commit_msg>odbior pakietu<commit_after>#include "client_net.h"
#include "interactive.h"
#include "crc32.h"
#include "md5.h"
#include "sha1.h"
#include "sha256.h"
#include "sha3.h"
#include "spdlog/spdlog.h"
#include "logging.h"
#include "auth_common.h"
#include "packets/radius_packet.h"
#include "packets/eap_packet.h"
#include "packets/packet.h"
#include "packets/utils.h"

using namespace std;
const std::vector<byte> temp = {0xe0, 0xbd, 0x18, 0xdb, 0x4c, 0xc2, 0xf8, 0x5c,
                                0xed, 0xef, 0x65, 0x4f, 0xcc, 0xc4, 0xa4, 0xd8};

const std::string LOGGER_NAME = "client";
std::string hashString(std::string input, std::string hash);
int main(int argc, char **argv) {
    using namespace TCLAP;
    try {

        CmdLine cmd("NAS Test Client", ' ');

        ValueArg<string> logpathArg("l", "log",
                                    "The path where log file shall be written",
                                    false, "client.log", "string");
        cmd.add(logpathArg);

        ValueArg<string> loginArg(
            "u", "username", "The name of a user that wishes to authenticate",
            false, "Basia", "string");
        cmd.add(loginArg);

        ValueArg<string> passArg("", "password", "The password of a user",
                                 false, "password", "string");
        cmd.add(passArg);

        /*         SwitchArg interSwitch("i", "interactive", */
        /*                               "Run in the interactive mode", false);
         */
        /*         cmd.add(interSwitch); */

        SwitchArg verboseSwitch("v", "verbose", "Run in the verbose mode",
                                false);
        cmd.add(verboseSwitch);

        ValueArg<string> secretArg("s", "secret", "The secret shared with NAS",
                                   true, "", "string");
        cmd.add(secretArg);

        ValueArg<int> portArg("p", "port", "Binded port", false, 0, "number");
        cmd.add(portArg);

        ValueArg<string> bindIpArg("b", "bind-ip", "Binded IP address", false,
                                   "0.0.0.0", "IP");

        cmd.add(bindIpArg);

        ValueArg<string> ipArg("a", "address", "Server IP address", true, "",
                               "IP");

        cmd.add(ipArg);

        ValueArg<string> hashArg(
            "", "hash", "Type of hashing function (crc32 md5 sha1 sha256 sha3)",
            false, "sha256", "string");
        cmd.add(hashArg);

        cmd.parse(argc, argv);

        int port = portArg.getValue();
        string ip = ipArg.getValue();
        string bindIp = ipArg.getValue();
        string secret = secretArg.getValue();
        string logpath = logpathArg.getValue();
        radius::initLogger(logpath, LOGGER_NAME);

        bool verbose = verboseSwitch.getValue();
        if (verbose) {
            spdlog::set_level(spdlog::level::trace);
        }

        auto logger = spdlog::get(LOGGER_NAME);

        string hash = hashArg.getValue();

        string login = loginArg.getValue();
        string pas = passArg.getValue();
        /* bool inter = interSwitch.getValue(); */
        // setup address structure //adres serwera
        struct sockaddr_in server_addr;
        memset((char *)&server_addr, 0, sizeof(server_addr));
        server_addr.sin_family = AF_INET;
        server_addr.sin_addr.s_addr = INADDR_ANY;
        server_addr.sin_port = htons(port);

        /* if (inter) { */
        /*     login = radius::getUsername(); */
        /*     pas = radius::getPassword("Enter password:\n"); */
        /* } */
        pas = hashString(pas, hash);

        // radius::packets::Packet newPack(temp, server_addr);

        radius::startClient(ip.c_str(), port);
        // 1.access-request
        using namespace radius;
        using namespace radius::packets;
			EapPacket eapIdentity;
			eapIdentity = makeIdentity(login);
			eapIdentity.setType(EapPacket::RESPONSE);
			eapIdentity.setIdentifier(1);

			EapMessage eapMessage;
			eapMessage.setValue(eapIdentity.getBuffer());

			RadiusPacket arPacket;
			arPacket.setIdentifier(1);
			arPacket.setCode(RadiusPacket::ACCESS_REQUEST);
			std::array<radius::byte, 16> authTable = generateRandom16();
			arPacket.setAuthenticator(authTable);
			arPacket.addAVP(static_cast<const RadiusAVP &>(eapMessage));
			calcAndSetMsgAuth(arPacket, secret);

        radius::packets::Packet newPack(arPacket.getBuffer(), server_addr);
		logger->info() <<"Send Packet";
        logger->info() <<"[Packet:]\n" << packet2LogBytes(newPack.bytes);
		logger->info() <<"[RadiusPacket:]\n"<< arPacket;
		logger->info() <<"[EapPacket:]\n"<< eapIdentity;

        radius::sendPack(newPack);
        // 2.otrzymuj odpowiedz od Radius server
        newPack = radius::receivePack();

		RadiusPacket recArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" <<packet2LogBytes(recArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< recArPacket;
		EapPacket recEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< recEapIdentity;

			std::array<radius::byte,16> chalArray =calcChalVal(recEapIdentity,secret);

		//make response
		EapPacket eapMd5Chal;
		eapMd5Chal = makeChallengeResp(chalArray);
		eapMd5Chal.setType(EapPacket::RESPONSE);
		eapMd5Chal.setIdentifier(2);

			EapMessage eapMessage2;
			eapMessage2.setValue(eapMd5Chal.getBuffer());

		RadiusPacket responsePacket;
		responsePacket.setIdentifier(2);
		responsePacket.setCode(RadiusPacket::ACCESS_REQUEST);
		authTable = generateRandom16();
		responsePacket.setAuthenticator(authTable);
		responsePacket.addAVP(static_cast<const RadiusAVP &>(eapMessage2));
		calcAndSetMsgAuth(responsePacket, secret);

		radius::packets::Packet responsePack(responsePacket.getBuffer() , server_addr);

			logger->info() <<"Send Packet";
			logger->info() <<"[Packet:]\n" << packet2LogBytes(responsePack.bytes);
			logger->info() <<"[RadiusPacket:]\n"<< responsePacket;
			logger->info() <<"[EapPacket:]\n"<< eapMd5Chal;

        radius::sendPack(responsePack);
        // 4.success or failure
        newPack = radius::receivePack();

		     newPack = radius::receivePack();

		RadiusPacket sucArPacket(newPack.bytes);
		logger->info() <<"Received Packet";
		logger->info() <<"[Packet:]\n" <<packet2LogBytes(sucArPacket.getBuffer());
		logger->info() <<"[RadiusPacket:]\n"<< sucArPacket;
		EapPacket sucEapIdentity = extractEapPacket(recArPacket);
		logger->info() <<"[EapPacket:]\n"<< sucEapIdentity;
		if (newPack.bytes[0]==0x02)
		{
			logger->info() <<"ACCEPT";
		}
		else
		{
			logger->info() <<"REJECT";
		}

        radius::stopClient();

    } catch (ArgException &e) {
        cerr << "error: " << e.error() << " for arg " << e.argId() << endl;
    }
}

std::string hashString(std::string input, std::string hash) {
    std::string output;

    if (hash == "sha256") {
        SHA256 sha256;
        output = sha256(input);
    } else if (hash == "sha1") {
        SHA1 sha1;
        output = sha1(input);
    } else if (hash == "sha3") {
        SHA3 sha3;
        output = sha3(input);
    } else if (hash == "md5") {
        MD5 md5;
        output = md5(input);
    } else if (hash == "crc32") {
        CRC32 crc32;
        output = crc32(input);
    } else {
        output = input;
    }
    return output;
}
<|endoftext|>


<commit_before>// RUN: %clang_cc1 -Oz -emit-llvm %s -o - | FileCheck %s -check-prefix=Oz
// RUN: %clang_cc1 -O0 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O3 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -Os -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// Check that we set the minsize attribute on each function
// when Oz optimization level is set.

int test1() {
  return 42;
// Oz: @{{.*}}test1{{.*}}minsize
// Oz: ret
// OTHER: @{{.*}}test1
// OTHER-NOT: minsize
// OTHER: ret
}

int test2() {
  return 42;
// Oz: @{{.*}}test2{{.*}}minsize
// Oz: ret
// OTHER: @{{.*}}test2
// OTHER-NOT: minsize
// OTHER: ret
}

__attribute__((minsize))
int test3() {
  return 42;
// Oz: @{{.*}}test3{{.*}}minsize
// OTHER: @{{.*}}test3{{.*}}minsize
}

// Check that the minsize attribute is well propagated through
// template instantiation

template<typename T>
__attribute__((minsize))
void test4(T arg) {
  return;
}

template
void test4<int>(int arg);
// Oz: define{{.*}}void @{{.*}}test4
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test4
// OTHER: minsize

template
void test4<float>(float arg);
// Oz: define{{.*}}void @{{.*}}test4
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test4
// OTHER: minsize

template<typename T>
void test5(T arg) {
  return;
}

template
void test5<int>(int arg);
// Oz: define{{.*}}void @{{.*}}test5
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test5
// OTHER-NOT: minsize

template
void test5<float>(float arg);
// Oz: define{{.*}}void @{{.*}}test5
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test5
// OTHER-NOT: minsize
<commit_msg>Update test to not fail with attribute groups.<commit_after>// RUN: %clang_cc1 -Oz -emit-llvm %s -o - | FileCheck %s -check-prefix=Oz
// RUN: %clang_cc1 -O0 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O1 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O2 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -O3 -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// RUN: %clang_cc1 -Os -emit-llvm %s -o - | FileCheck %s -check-prefix=OTHER
// Check that we set the minsize attribute on each function
// when Oz optimization level is set.

int test1() {
  return 42;
// Oz: @{{.*}}test1{{.*}}minsize
// Oz: ret
// OTHER: @{{.*}}test1
// OTHER-NOT: minsize
// OTHER: ret
}

int test2() {
  return 42;
// Oz: @{{.*}}test2{{.*}}minsize
// Oz: ret
// OTHER: @{{.*}}test2
// OTHER-NOT: minsize
// OTHER: ret
}

__attribute__((minsize))
int test3() {
  return 42;
// Oz: @{{.*}}test3{{.*}}minsize
// OTHER: @{{.*}}test3{{.*}}minsize
}

// Check that the minsize attribute is well propagated through
// template instantiation

template<typename T>
__attribute__((minsize))
void test4(T arg) {
  return;
}

template
void test4<int>(int arg);
// Oz: define{{.*}}void @{{.*}}test4
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test4
// OTHER: minsize

template
void test4<float>(float arg);
// Oz: define{{.*}}void @{{.*}}test4
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test4
// OTHER: minsize

template<typename T>
void test5(T arg) {
  return;
}

template
void test5<int>(int arg);
// Oz: define{{.*}}void @{{.*}}test5
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test5
// OTHER-NOT: define{{.*}}void @{{.*}}test5{{.*}}minsize

template
void test5<float>(float arg);
// Oz: define{{.*}}void @{{.*}}test5
// Oz: minsize
// OTHER: define{{.*}}void @{{.*}}test5
// OTHER-NOT: define{{.*}}void @{{.*}}test5{{.*}}minsize
<|endoftext|>


<commit_before>// Catch
#include <catch.hpp>
#include <catchExtension.hpp>

// Mantella
#include <mantella>

class TestPrintable : public mant::Printable {
  public:
    std::string toString() const override {
      return "ThisIsTestPrintable";
    }
};

TEST_CASE("printable: Printable", "") {
  SECTION("Returns the specified class name.") {
    TestPrintable testPrintable;

    CHECK(testPrintable.toString() == "ThisIsTestPrintable");
  }
}

TEST_CASE("string: to_string(Printable*)", "") {
  SECTION("Returns the specified class name.") {
    std::shared_ptr<mant::Printable> testPrintable = std::shared_ptr<mant::Printable>(new TestPrintable);

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }
}

<commit_msg>Improved section notice<commit_after>// Catch
#include <catch.hpp>
#include <catchExtension.hpp>

// Mantella
#include <mantella>

class TestPrintable : public mant::Printable {
  public:
    std::string toString() const override {
      return "ThisIsTestPrintable";
    }
};

TEST_CASE("Printable", "") {
  SECTION(".toString") {
    SECTION("Returns the expected class name.") {
      TestPrintable testPrintable;

      CHECK(testPrintable.toString() == "ThisIsTestPrintable");
    }
  }
}

TEST_CASE("to_string", "") {
  SECTION("Returns the expected class name.") {
    std::shared_ptr<mant::Printable> testPrintable = std::shared_ptr<mant::Printable>(new TestPrintable);

    CHECK(mant::to_string(testPrintable) == "ThisIsTestPrintable");
  }
}

<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#include <fstream>

#include <ydsh/ydsh.h>
#include <constant.h>
#include <vm.h>

#include "../test_common.h"

#ifndef HISTORY_MOD_PATH
#error "require HISTORY_MOD_PATH"
#endif

class HistoryTest : public ExpectOutput, public TempFileFactory {
protected:
    DSState *state{nullptr};

public:
    HistoryTest() {
        this->state = DSState_create();
        DSState_loadModule(this->state, HISTORY_MOD_PATH, DS_MOD_FULLPATH, nullptr);

        std::string value;
        value += '"';
        value += this->tmpFileName;
        value += '"';
        this->assignValue(VAR_HISTFILE, std::move(value));
    }

    ~HistoryTest() override {
        DSState_delete(&this->state);
    }

    void setHistSize(unsigned int size, bool sync = true) {
        this->assignUintValue(VAR_HISTSIZE, size);
        if(sync) {
            this->addHistory(nullptr);
        }
    }

    void setHistFileSize(unsigned int size) {
        this->assignUintValue(VAR_HISTFILESIZE, size);
    }

    unsigned int historySize() {
        return DSState_lineEdit(this->state, DS_EDIT_HIST_SIZE, 0, nullptr);
    }

    const char *getHistory(unsigned int index) {
        const char *buf = nullptr;
        DSState_lineEdit(this->state, DS_EDIT_HIST_GET, index, &buf);
        return buf;
    }

    void setHistory(unsigned int index, const char *line) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_SET, index, &line);
    }

    void delHistory(unsigned int index) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_DEL, index, nullptr);
    }

    void addHistory(const char *value) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_ADD, 0, &value);
    }

    void clearHistory() {
        DSState_lineEdit(this->state, DS_EDIT_HIST_CLEAR, 0, nullptr);
    }

    void loadHistory(const char *fileName = nullptr) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_LOAD, 0, &fileName);
    }

    void saveHistory(const char *fileName = nullptr) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_SAVE, 0, &fileName);
    }

private:
    void assignValue(const char *varName, std::string &&value) {
        std::string str = "$";
        str += varName;
        str += " = ";
        str += value;

        auto r = DSState_eval(this->state, "(dummy)", str.c_str(), str.size(), nullptr);
        ASSERT_TRUE(r == 0);
    }

    void assignUintValue(const char *varName, unsigned int value) {
        std::string str = std::to_string(value);
        this->assignValue(varName, std::move(str));
    }
};

#define DS_HISTFILESIZE_LIMIT   ((unsigned int) 4096)

TEST_F(HistoryTest, add) {
    this->setHistSize(2);
    this->addHistory("aaa");
    this->addHistory("bbb");

    ASSERT_EQ(2u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));

    this->addHistory("ccc");
    ASSERT_EQ(2u, this->historySize());
    ASSERT_STREQ("bbb", this->getHistory(0));
    ASSERT_STREQ("ccc", this->getHistory(1));
    ASSERT_EQ(nullptr, this->getHistory(100));

    this->addHistory("ccc");
    ASSERT_EQ(2u, this->historySize());

    // null
    ASSERT_EQ(nullptr, this->getHistory(100));
}

TEST_F(HistoryTest, set) {
    this->setHistSize(10);
    this->addHistory("aaa");
    this->addHistory("bbb");

    ASSERT_EQ(2u, this->historySize());

    this->setHistory(1, "ccc");
    ASSERT_STREQ("ccc", this->getHistory(1));

    this->setHistory(3, "ccc");    // do nothing, if out of range
    ASSERT_EQ(2u, this->historySize());
    ASSERT_EQ(nullptr, this->getHistory(3));

    this->setHistory(1000, "ccc");    // do nothing, if out of range
    ASSERT_EQ(2u, this->historySize());
}

TEST_F(HistoryTest, remove) {
    this->setHistSize(10);
    this->addHistory("aaa");
    this->addHistory("bbb");
    this->addHistory("ccc");
    this->addHistory("ddd");
    this->addHistory("eee");

    this->delHistory(2);
    ASSERT_EQ(4u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));
    ASSERT_STREQ("eee", this->getHistory(3));

    this->delHistory(3);
    ASSERT_EQ(3u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));

    // do nothing, if out of range
    this->delHistory(6);
    ASSERT_EQ(3u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));

    // do nothing, if out of range
    this->delHistory(600);
    ASSERT_EQ(3u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));
}

TEST_F(HistoryTest, clear) {
    this->setHistSize(10);
    this->addHistory("aaa");
    this->addHistory("bbb");
    this->addHistory("ccc");
    this->addHistory("ddd");
    this->addHistory("eee");

    ASSERT_EQ(5u, this->historySize());

    this->clearHistory();
    ASSERT_EQ(0u, this->historySize());
}

TEST_F(HistoryTest, resize) {
    this->setHistSize(10);
    for(unsigned int i = 0; i < 10; i++) {
        this->addHistory(std::to_string(i).c_str());
    }

    ASSERT_EQ(10u, this->historySize());

    this->setHistSize(5);
    ASSERT_EQ(5u, this->historySize());
    ASSERT_STREQ("0", this->getHistory(0));
    ASSERT_STREQ("1", this->getHistory(1));
    ASSERT_STREQ("2", this->getHistory(2));
    ASSERT_STREQ("3", this->getHistory(3));
    ASSERT_STREQ("4", this->getHistory(4));
}

TEST_F(HistoryTest, file) {
    this->setHistSize(10);
    for(unsigned int i = 0; i < 10; i++) {
        this->addHistory(std::to_string(i).c_str());
    }

    this->setHistFileSize(15);
    /**
     * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
     */
    this->saveHistory();
    this->clearHistory();
    this->loadHistory();
    ASSERT_EQ(10u, this->historySize());

    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i), this->getHistory(i));
    }

    for(unsigned int i = 0; i < 5; i++) {
        this->addHistory(std::to_string(i + 10).c_str());
    }

    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i + 5), this->getHistory(i));
    }

    /**
     * previous hist file content
     * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
     *
     * newly added content
     * 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
     *
     * current hist file content
     * 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
     */
    this->saveHistory();
    this->clearHistory();
    this->setHistSize(15);
    this->loadHistory();
    ASSERT_EQ(10u, this->historySize());
    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i + 5), this->getHistory(i));
    }

    // not overwrite history file when buffer size is 0
    this->clearHistory();
    this->saveHistory();
    this->loadHistory();
    ASSERT_EQ(10u, this->historySize());
    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i + 5), this->getHistory(i));
    }

    // not overwrite history file when hist file size is 0
    this->setHistFileSize(0);
    this->clearHistory();
    this->addHistory("hoge");
    this->saveHistory();
    this->loadHistory();
    ASSERT_EQ(11u, this->historySize());
    ASSERT_STREQ("hoge", this->getHistory(0));
    for(unsigned int i = 1; i < 11; i++) {
        ASSERT_EQ(std::to_string(i + 4), this->getHistory(i));
    }
}

TEST_F(HistoryTest, file2) {
    this->setHistFileSize(DS_HISTFILESIZE_LIMIT + 10);
    this->setHistSize(DS_HISTFILESIZE_LIMIT);

    for(unsigned int i = 0; i < DS_HISTFILESIZE_LIMIT; i++) {
        this->addHistory(std::to_string(i).c_str());
    }

    ASSERT_EQ(DS_HISTFILESIZE_LIMIT, this->historySize());

    this->saveHistory();
    this->clearHistory();
    this->loadHistory();

    ASSERT_EQ(DS_HISTFILESIZE_LIMIT, this->historySize());
    for(unsigned int i = 0; i < DS_HISTFILESIZE_LIMIT; i++) {
        ASSERT_EQ(std::to_string(i), this->getHistory(i));
    }
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}<commit_msg>update history test case<commit_after>#include "gtest/gtest.h"

#include <fstream>

#include <ydsh/ydsh.h>
#include <constant.h>
#include <vm.h>

#include "../test_common.h"

#ifndef HISTORY_MOD_PATH
#error "require HISTORY_MOD_PATH"
#endif

class HistoryTest : public ExpectOutput, public TempFileFactory {
protected:
    DSState *state{nullptr};

public:
    HistoryTest() {
        this->state = DSState_create();
        DSState_loadModule(this->state, HISTORY_MOD_PATH, DS_MOD_FULLPATH, nullptr);

        std::string value;
        value += '"';
        value += this->tmpFileName;
        value += '"';
        this->assignValue(VAR_HISTFILE, std::move(value));
    }

    ~HistoryTest() override {
        DSState_delete(&this->state);
    }

    void setHistSize(unsigned int size, bool sync = true) {
        this->assignUintValue(VAR_HISTSIZE, size);
        if(sync) {
            this->addHistory(nullptr);
        }
    }

    void setHistFileSize(unsigned int size) {
        this->assignUintValue(VAR_HISTFILESIZE, size);
    }

    unsigned int historySize() {
        return DSState_lineEdit(this->state, DS_EDIT_HIST_SIZE, 0, nullptr);
    }

    const char *getHistory(unsigned int index) {
        const char *buf = nullptr;
        DSState_lineEdit(this->state, DS_EDIT_HIST_GET, index, &buf);
        return buf;
    }

    void setHistory(unsigned int index, const char *line) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_SET, index, &line);
    }

    void delHistory(unsigned int index) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_DEL, index, nullptr);
    }

    void addHistory(const char *value) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_ADD, 0, &value);
    }

    void clearHistory() {
        DSState_lineEdit(this->state, DS_EDIT_HIST_CLEAR, 0, nullptr);
    }

    void loadHistory(const char *fileName = nullptr) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_LOAD, 0, &fileName);
    }

    void saveHistory(const char *fileName = nullptr) {
        DSState_lineEdit(this->state, DS_EDIT_HIST_SAVE, 0, &fileName);
    }

private:
    void assignValue(const char *varName, std::string &&value) {
        std::string str = "$";
        str += varName;
        str += " = ";
        str += value;

        auto r = DSState_eval(this->state, "(dummy)", str.c_str(), str.size(), nullptr);
        ASSERT_TRUE(r == 0);
    }

    void assignUintValue(const char *varName, unsigned int value) {
        std::string str = std::to_string(value);
        this->assignValue(varName, std::move(str));
    }
};

#define DS_HISTFILESIZE_LIMIT   ((unsigned int) 4096)

TEST_F(HistoryTest, add) {
    this->setHistSize(2);
    this->addHistory("aaa");
    this->addHistory("bbb");

    ASSERT_EQ(2u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));

    this->addHistory("ccc");
    ASSERT_EQ(2u, this->historySize());
    ASSERT_STREQ("bbb", this->getHistory(0));
    ASSERT_STREQ("ccc", this->getHistory(1));
    ASSERT_EQ(nullptr, this->getHistory(100));

    this->addHistory("ccc");
    ASSERT_EQ(2u, this->historySize());

    // null
    ASSERT_EQ(nullptr, this->getHistory(100));
}

TEST_F(HistoryTest, set) {
    this->setHistSize(10);
    this->addHistory("aaa");
    this->addHistory("bbb");

    ASSERT_EQ(2u, this->historySize());

    this->setHistory(1, "ccc");
    ASSERT_STREQ("ccc", this->getHistory(1));

    this->setHistory(3, "ccc");    // do nothing, if out of range
    ASSERT_EQ(2u, this->historySize());
    ASSERT_EQ(nullptr, this->getHistory(3));

    this->setHistory(1000, "ccc");    // do nothing, if out of range
    ASSERT_EQ(2u, this->historySize());
}

TEST_F(HistoryTest, remove) {
    this->setHistSize(10);
    this->addHistory("aaa");
    this->addHistory("bbb");
    this->addHistory("ccc");
    this->addHistory("ddd");
    this->addHistory("eee");

    this->delHistory(2);
    ASSERT_EQ(4u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));
    ASSERT_STREQ("eee", this->getHistory(3));

    this->delHistory(3);
    ASSERT_EQ(3u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));

    // do nothing, if out of range
    this->delHistory(6);
    ASSERT_EQ(3u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));

    // do nothing, if out of range
    this->delHistory(600);
    ASSERT_EQ(3u, this->historySize());
    ASSERT_STREQ("aaa", this->getHistory(0));
    ASSERT_STREQ("bbb", this->getHistory(1));
    ASSERT_STREQ("ddd", this->getHistory(2));
}

TEST_F(HistoryTest, clear) {
    this->setHistSize(10);
    this->addHistory("aaa");
    this->addHistory("bbb");
    this->addHistory("ccc");
    this->addHistory("ddd");
    this->addHistory("eee");

    ASSERT_EQ(5u, this->historySize());

    this->clearHistory();
    ASSERT_EQ(0u, this->historySize());
}

TEST_F(HistoryTest, resize) {
    this->setHistSize(10);
    for(unsigned int i = 0; i < 10; i++) {
        this->addHistory(std::to_string(i).c_str());
    }

    ASSERT_EQ(10u, this->historySize());

    this->setHistSize(5);
    ASSERT_EQ(5u, this->historySize());
    ASSERT_STREQ("0", this->getHistory(0));
    ASSERT_STREQ("1", this->getHistory(1));
    ASSERT_STREQ("2", this->getHistory(2));
    ASSERT_STREQ("3", this->getHistory(3));
    ASSERT_STREQ("4", this->getHistory(4));
}

TEST_F(HistoryTest, file) {
    this->setHistSize(10);
    for(unsigned int i = 0; i < 10; i++) {
        this->addHistory(std::to_string(i).c_str());
    }

    this->setHistFileSize(15);
    /**
     * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
     */
    this->saveHistory();
    this->clearHistory();
    this->loadHistory();
    ASSERT_EQ(10u, this->historySize());

    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i), this->getHistory(i));
    }

    for(unsigned int i = 0; i < 5; i++) {
        this->addHistory(std::to_string(i + 10).c_str());
    }

    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i + 5), this->getHistory(i));
    }

    /**
     * previous hist file content
     * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
     *
     * newly added content
     * 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
     *
     * current hist file content
     * 5, 6, 7, 8, 9, 10, 11, 12, 13, 14
     */
    this->saveHistory();
    this->clearHistory();
    this->setHistSize(15);
    this->loadHistory();
    ASSERT_EQ(10u, this->historySize());
    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i + 5), this->getHistory(i));
    }

    // not overwrite history file when buffer size is 0
    this->clearHistory();
    this->saveHistory();
    this->loadHistory();
    ASSERT_EQ(10u, this->historySize());
    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i + 5), this->getHistory(i));
    }

    // not overwrite history file when hist file size is 0
    this->setHistFileSize(0);
    this->clearHistory();
    this->addHistory("hoge");
    this->saveHistory();
    this->loadHistory();
    ASSERT_EQ(11u, this->historySize());
    ASSERT_STREQ("hoge", this->getHistory(0));
    for(unsigned int i = 1; i < 11; i++) {
        ASSERT_EQ(std::to_string(i + 4), this->getHistory(i));
    }
}

TEST_F(HistoryTest, file2) {
    this->setHistFileSize(DS_HISTFILESIZE_LIMIT + 10);
    this->setHistSize(DS_HISTFILESIZE_LIMIT);

    for(unsigned int i = 0; i < DS_HISTFILESIZE_LIMIT; i++) {
        this->addHistory(std::to_string(i).c_str());
    }

    ASSERT_EQ(DS_HISTFILESIZE_LIMIT, this->historySize());

    this->saveHistory();
    this->clearHistory();
    this->loadHistory();

    ASSERT_EQ(DS_HISTFILESIZE_LIMIT, this->historySize());
    for(unsigned int i = 0; i < DS_HISTFILESIZE_LIMIT; i++) {
        ASSERT_EQ(std::to_string(i), this->getHistory(i));
    }
}

TEST_F(HistoryTest, file3) {
    this->setHistSize(10);
    for(unsigned int i = 0; i < 10; i++) {
        this->addHistory(std::to_string(i).c_str());
    }
    this->setHistFileSize(15);

    std::string fileName = this->getTempDirName();
    fileName += "/hogehogehgoe";

    this->saveHistory(fileName.c_str());
    this->clearHistory();
    this->loadHistory(fileName.c_str());

    ASSERT_EQ(10, this->historySize());
    for(unsigned int i = 0; i < 10; i++) {
        ASSERT_EQ(std::to_string(i), this->getHistory(i));
    }
}

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}<|endoftext|>


<commit_before>/*
    Author : David Barnett
    Date   : 03-10-2013
    License: MIT License
*/
#include "Settings.h"

#include <iosfwd>
#include <iostream>

using namespace IO;

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <algorithm>
#include <iterator>
#include "../etc/string.h"

//#define SETTINGS_VERBOSE

Settings::Settings() {
    this->loading_flag = SETTING_LOAD_NOTHING;
}

Settings::Settings(SettingsLoadFlags flag)
{
    this->loading_flag = flag;
}

Settings::~Settings()
{
    this->stored_settings.clear();
}

/**
 * @brief removes all currently loaded settings
 */
void Settings::clear()
{
    this->stored_settings.clear();
}

/**
 * @brief Checks if a given setting exists, and loads it if flags permit
 * @param header section header
 * @param key name of the setting to be accessed
 * @return true on exists
 */
bool Settings::exists (std::string header ,std::string  key)
{
    if (this->exists(header))
    {
        INISection* section = &(this->stored_settings[header]);
        if (section->loaded) {
            return section->properties.find(key) != section->properties.end();
        } else {
            //Load Header's properties?
            if ( this->loading_flag == SETTING_LOAD_ON_REQUEST ) {
                this->load_section ( header , SETTINGS_DUPLICATES_INGORED );
                return this->exists ( header , key);
            } else {
                return false;
            }
        }
    } else {
        return false;
    }
}

/**
 * @brief Checks if a header exits
 * @param header Name of section
 * @return true on success
 */
bool Settings::exists (std::string header)
{
    return this->stored_settings.find(header) != this->stored_settings.end();
}

/**
 * @brief Loads settings from a file
 * @param file_name
 * @param flag
 */
void Settings::load(std::string file_name , SettingsDuplicateFlags flag)
{
#ifdef SETTINGS_VERBOSE
    std::cout << "Loading " << file_name << std::endl;
#endif
    std::fstream file;
    file.open(file_name.c_str());
    this->file_name = file_name;
    //Check if the file is open
    if (!(file.is_open()))
    {
        return;
    }

    //Seek to the beginning of the file
    file.seekg( 0 , file.beg );
    file.peek();

    //Calculate the offset from the 1st byte to the 0th element
    int sys_error = file.tellg();

    std::string line;
    INISection section;
    section.header_name = "";
    section.loaded = false;
    section.start_index = 0;
#ifdef SETTINGS_VERBOSE
    std::cout << "sys error is " << sys_error << " Pos " << file.tellg() << std::endl;
    std::cout << "root  S:" << section.start_index;
#endif
    while ( ! file.eof() )
    {
        //Get current position with the sys error offset
        int start_pos = (int)(file.tellg()) - sys_error;
        std::getline( file , line );

        if (line.length() == 0)
            continue;

        line = etc::trim(line);

        //Treat lines starting with ; as comments and do not process
        if ( etc::startswith( line , ";" ) )
        {
            continue;
        }
        //Check if the line has the beginning of a section
        if (etc::startswith( line , "[" ) && etc::endswith( line , "]" ))
        {
            //Close last section
            section.end_index = (int)file.tellg();
            this->stored_settings[section.header_name] = section;
#ifdef SETTINGS_VERBOSE
            std::cout << " E:" << section.end_index << std::endl;
#endif

            //Refresh section
            section = INISection();
            //Remove the brackets
            section.header_name = line.substr ( 1 , line.size() - 2 );

            if ( this->exists(section.header_name)) {
                //Warning text
                std::cout << "ERROR : Another " << this->file_name << "::" << section.header_name << " has been defined!\nSections will be damaged." << std::endl;
            } else {
                //-2 constant is to correct the position of the start index
                section.start_index = start_pos ;
                section.loaded = false;
                section.properties = SettingsMap();

#ifdef SETTINGS_VERBOSE
            std::cout << section.header_name  << " S:" << section.start_index;
#endif

            }
            continue;
        }
    }

    file.seekg (0 , file.end);
    section.end_index = (int)file.tellg() - sys_error;
    this->stored_settings[section.header_name] = section;

#ifdef SETTINGS_VERBOSE
            std::cout << " E:" << section.end_index << std::endl;
#endif

    file.close();
}

/**
 * @brief Loads a section's data into memory
 * @param header Section name
 * @param flag Settings Duplicate Flags
 */
void Settings::load_section ( std::string header , SettingsDuplicateFlags flag) {
    std::fstream file;

    if (this->exists(header) == false)
        return;

    INISection* section = &(this->stored_settings[header]);

    file.open( this->file_name.c_str() );
    int file_pos_max = section->end_index;
    //Check if the file is open
    if (!(file.is_open()))
    {
        return;
    }

    //Seek to the beginning of the file
    file.seekg( 0 , file.beg );
    file.peek();

    file.seekg( section->start_index , file.beg );

    bool start = false;
    while ( file.tellg() < file_pos_max && !file.eof() )
    {
        std::string line;
        std::getline ( file, line );
        line = etc::trim ( line );

        if (line == "")
        {
            continue;
        }
        if ( etc::startswith( line , ";" ) )
        {
            continue;
        }
        //Check if the line has the beginning of a section
        if ( etc::startswith( line , "[" ) || etc::endswith( line , "]") )
        {
            std::string header_name = line.substr ( 1 , line.size() - 2 );
            //If another section is in contact, LEAVE NOW
            if (header_name != section->header_name) {
                break;
            } else {
                //Found the start of the section we are looking for
                start = true;
            }
            continue;
        }

        if (start == false)
        {
            continue;
        }

        //Find the equal part of the line
        std::size_t equal_pos = line.find_first_of('=', 0);

        if (equal_pos == line.npos) {
            continue;
        }

        std::string key = etc::trim ( line.substr( 0 , equal_pos ) );
        std::string value = etc::trim ( line.substr( equal_pos + 1  , line.length() - 1 ) );

        if (key == "") {
            continue;
        }

        if ( section->properties.find( key ) !=  section->properties.end() )
        {
            //There is another copy of the key, check if it is OK to override
            if (flag == SETTINGS_DUPLICATES_OVERRIDE)
            {
                section->properties[key] = value;
            }
        }
        else
        {
            section->properties[key] = value;
#ifdef SETTINGS_VERBOSE
            std::cout << section->header_name << "::" << key << "=" << value << std::endl;
#endif
        }
    }
    //Update loaded status
    section->loaded = true;
    file.close();

}

/**
 * @brief Unloads a specified section
 * @param header a section name
 */
void Settings::unload_section (std::string header)
{
    if (this->exists(header)) {
        this->stored_settings[header].properties.clear();
        this->stored_settings[header].loaded = false;
    }
}

/**
 * @brief Gets the string of the given setting and copies it into the out string
 * @param header the name of the section
 * @param key the name of setting
 * @param out A string to be written to
 * @return true on successful copy
 */
bool Settings::get (std::string header , std::string  key, std::string* out)
{
    if (this->exists(header ,key))
    {
        *out = this->stored_settings[header].properties[key];
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @brief Gets the value and converts it to a bool
 * @see Settings::get
 * @param bol Returns the value
 * @return
 */
bool Settings::getBool (std::string header , std::string  key , bool* bol)
{
    std::string b;
    if (this->get(header, key , &b) == false)
        return false;
    b = etc::toLower(b);
    if (b != "")
    {
        *bol = ( b == "true" ? true : false );
        return true;
    }
    else
    {
        return false;
    }
}

bool Settings::getInt (std::string header , std::string  key , int* num)
{
    std::string b;
    if (this->get(header, key , &b) == false)
        return false;

    if ( etc::is_number(b) )
    {
        *num = atoi( b.c_str() );
        return true;
    }
    else
    {
        return false;
    }
}

bool Settings::add (std::string header , std::string key , std::string value)
{
    if (!this->exists(header , key))
    {
        this->stored_settings[header].properties[key] = value;
        return true;
    }
    else
    {
        return false;
    }
}

bool Settings::set (std::string header , std::string key , std::string value)
{
     if (this->exists( header , key ) ) {
        this->stored_settings[header].properties[key] = value;
        return true;
     }
     return false;
}

/**
 * @brief Saves all the sections of a given file
 * @warning Deletes original file and then renames a temp file to replace it
 * @param filename Saves all headers that belong to a file
 * @return bool true on success
 */
bool Settings::save ()
{
    //The File to be read from
    std::ifstream file_in;
    //The File to be written to
    std::fstream file_out;
    //Stream are separate to prevent cross-contamination

    //Open the input file
    file_in.open( this->file_name.c_str() );

    //Check for errors
    if (file_in.is_open() == false) {
        std::cout << "Error input file : " << this->file_name.c_str() << " could not be opened." << std::endl;
        return false;
    }

    //Open the output file
    file_out.open( ("temp~" + this->file_name).c_str() , std::ofstream::out );

    //Check for errors
    if (file_out.is_open() == false) {
        std::cout << "Error output file : " << ("temp~" + this->file_name).c_str() << " could not be opened." << std::endl;
        return false;
    }

    //Go through whole file
    INISection* current_section = &(this->stored_settings[""]);
    while ( file_in.eof() == false )
    {
        std::string line;
        std::getline ( file_in , line );
        line = etc::trim ( line );

        std::size_t equal_pos = line.find_first_of('=', 0);

        if (line == "")
        {

        }
        else if ( etc::startswith( line , ";" ) )
        {

        }
        else if ( etc::startswith( line , "[" ) || etc::endswith( line , "]") )
        {
            //Check if the line has the beginning of a section
            //Update current_section
            if (current_section != nullptr)
            {
                current_section->end_index = file_out.tellg();
            }

            current_section = &( this->stored_settings[ line.substr ( 1 , line.size() - 2 )] );
            current_section->start_index = (int)file_out.tellg() - 1;
        }
        else if (equal_pos != line.npos) {
            std::string key = etc::trim ( line.substr( 0 , equal_pos ) );
            std::string value = current_section->properties[key];
            if (value == "") {
                value = etc::trim ( line.substr( equal_pos + 1  , line.length() - 1 ) );
            }

            file_out << key << '=' << value << std::endl;
            continue;
        }

        //Standard copy line out
        file_out << line << std::endl;
    }

    file_out.close();
    file_in.close();

    //File operations
    //File operation return value
    int file_op = 0;

    //Remove old version
    file_op = std::remove( this->file_name.c_str() );

    //Check if there was an error
    if (file_op != 0) {
        std::cout << "Error while removing the file " << this->file_name.c_str() << std::endl;
        return false;
    }

    //Rename the temp version to replace the deleted version
    file_op = std::rename( ("temp~" + this->file_name).c_str()  , this->file_name.c_str() );

    //Check if there was an error
    if (file_op != 0) {
        std::cout << "Error while renaming the file from " << ("temp~" + this->file_name).c_str() << " to " << this->file_name.c_str() << std::endl;
        return false;
    }

    return true;
}
<commit_msg>Settings Fix * Fixed bug where the last section had incorrect ending index * Added build option SETTINGS_VERBOOSE for console output of settings loading Conflicts: 	io/Settings.cpp<commit_after>/*
    Author : David Barnett
    Date   : 03-10-2013
    License: MIT License
*/
#include "Settings.h"

#include <iosfwd>
#include <iostream>

using namespace IO;

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sstream>
#include <algorithm>
#include <iterator>
#include "../etc/string.h"

//#define SETTINGS_VERBOSE

Settings::Settings() {
    this->loading_flag = SETTING_LOAD_NOTHING;
}

Settings::Settings(SettingsLoadFlags flag)
{
    this->loading_flag = flag;
}

Settings::~Settings()
{
    this->stored_settings.clear();
}

/**
 * @brief removes all currently loaded settings
 */
void Settings::clear()
{
    this->stored_settings.clear();
}

/**
 * @brief Checks if a given setting exists, and loads it if flags permit
 * @param header section header
 * @param key name of the setting to be accessed
 * @return true on exists
 */
bool Settings::exists (std::string header ,std::string  key)
{
    if (this->exists(header))
    {
        INISection* section = &(this->stored_settings[header]);
        if (section->loaded) {
            return section->properties.find(key) != section->properties.end();
        } else {
            //Load Header's properties?
            if ( this->loading_flag == SETTING_LOAD_ON_REQUEST ) {
                this->load_section ( header , SETTINGS_DUPLICATES_INGORED );
                return this->exists ( header , key);
            } else {
                return false;
            }
        }
    } else {
        return false;
    }
}

/**
 * @brief Checks if a header exits
 * @param header Name of section
 * @return true on success
 */
bool Settings::exists (std::string header)
{
    return this->stored_settings.find(header) != this->stored_settings.end();
}

/**
 * @brief Loads settings from a file
 * @param file_name
 * @param flag
 */
void Settings::load(std::string file_name , SettingsDuplicateFlags flag)
{
<<<<<<< HEAD
#ifdef SETTINGS_VERBOSE
=======
#ifdef SETTINGS_VERBOOSE
>>>>>>> 86e3c99... Settings Fix
    std::cout << "Loading " << file_name << std::endl;
#endif
    std::fstream file;
    file.open(file_name.c_str());
    this->file_name = file_name;
    //Check if the file is open
    if (!(file.is_open()))
    {
        return;
    }

    //Seek to the beginning of the file
    file.seekg( 0 , file.beg );
    file.peek();

    //Calculate the offset from the 1st byte to the 0th element
    int sys_error = file.tellg();
    file.seekg( 0, file.end );
    int file_size = (int)file.tellg();
    file.seekg( 0, file.beg );

    std::string line;
    INISection section;
    section.header_name = "";
    section.loaded = false;
    section.start_index = 0;
<<<<<<< HEAD
#ifdef SETTINGS_VERBOSE
=======
#ifdef SETTINGS_VERBOOSE
>>>>>>> 86e3c99... Settings Fix
    std::cout << "sys error is " << sys_error << " Pos " << file.tellg() << std::endl;
    std::cout << "root  S:" << section.start_index;
#endif
    while ( ! file.eof() )
    {
        //Get current position with the sys error offset
        int start_pos = (int)(file.tellg()) - sys_error;
        std::getline( file , line );

        if (line.length() == 0)
            continue;

        line = etc::trim(line);

        //Treat lines starting with ; as comments and do not process
        if ( etc::startswith( line , ";" ) )
        {
            continue;
        }
        //Check if the line has the beginning of a section
        if (etc::startswith( line , "[" ) && etc::endswith( line , "]" ))
        {
            //Close last section
            section.end_index = (int)file.tellg();
            this->stored_settings[section.header_name] = section;
<<<<<<< HEAD
#ifdef SETTINGS_VERBOSE
            std::cout << " E:" << section.end_index << std::endl;
#endif

=======
#ifdef SETTINGS_VERBOOSE
            std::cout << " E:" << section.end_index << std::endl;
#endif
>>>>>>> 86e3c99... Settings Fix
            //Refresh section
            section = INISection();
            //Remove the brackets
            section.header_name = line.substr ( 1 , line.size() - 2 );

            if ( this->exists(section.header_name)) {
                //Warning text
                std::cout << "ERROR : Another " << this->file_name << "::" << section.header_name << " has been defined!\nSections will be damaged." << std::endl;
            } else {
                //-2 constant is to correct the position of the start index
                section.start_index = start_pos ;
                section.loaded = false;
                section.properties = SettingsMap();
<<<<<<< HEAD

#ifdef SETTINGS_VERBOSE
            std::cout << section.header_name  << " S:" << section.start_index;
#endif

=======
#ifdef SETTINGS_VERBOOSE
            std::cout << section.header_name  << " S:" << section.start_index;
#endif
>>>>>>> 86e3c99... Settings Fix
            }
            continue;
        }
    }

    section.end_index = file_size;
    this->stored_settings[section.header_name] = section;
<<<<<<< HEAD

#ifdef SETTINGS_VERBOSE
            std::cout << " E:" << section.end_index << std::endl;
#endif

=======
#ifdef SETTINGS_VERBOOSE
            std::cout << " E:" << section.end_index << std::endl;
#endif
>>>>>>> 86e3c99... Settings Fix
    file.close();
}

/**
 * @brief Loads a section's data into memory
 * @param header Section name
 * @param flag Settings Duplicate Flags
 */
void Settings::load_section ( std::string header , SettingsDuplicateFlags flag) {
    std::fstream file;

    if (this->exists(header) == false)
        return;

    INISection* section = &(this->stored_settings[header]);

    file.open( this->file_name.c_str() );
    int file_pos_max = section->end_index;
    //Check if the file is open
    if (!(file.is_open()))
    {
        return;
    }

    //Seek to the beginning of the file
    file.seekg( 0 , file.beg );
    file.peek();

    file.seekg( section->start_index , file.beg );

    bool start = false;
    while ( file.tellg() < file_pos_max && !file.eof() )
    {
        std::string line;
        std::getline ( file, line );
        line = etc::trim ( line );

        if (line == "")
        {
            continue;
        }
        if ( etc::startswith( line , ";" ) )
        {
            continue;
        }
        //Check if the line has the beginning of a section
        if ( etc::startswith( line , "[" ) || etc::endswith( line , "]") )
        {
            std::string header_name = line.substr ( 1 , line.size() - 2 );
            //If another section is in contact, LEAVE NOW
            if (header_name != section->header_name) {
                break;
            } else {
                //Found the start of the section we are looking for
                start = true;
            }
            continue;
        }

        if (start == false)
        {
            continue;
        }

        //Find the equal part of the line
        std::size_t equal_pos = line.find_first_of('=', 0);

        if (equal_pos == line.npos) {
            continue;
        }

        std::string key = etc::trim ( line.substr( 0 , equal_pos ) );
        std::string value = etc::trim ( line.substr( equal_pos + 1  , line.length() - 1 ) );

        if (key == "") {
            continue;
        }

        if ( section->properties.find( key ) !=  section->properties.end() )
        {
            //There is another copy of the key, check if it is OK to override
            if (flag == SETTINGS_DUPLICATES_OVERRIDE)
            {
                section->properties[key] = value;
            }
        }
        else
        {
            section->properties[key] = value;
<<<<<<< HEAD
#ifdef SETTINGS_VERBOSE
=======
#ifdef SETTINGS_VERBOOSE
>>>>>>> 86e3c99... Settings Fix
            std::cout << section->header_name << "::" << key << "=" << value << std::endl;
#endif
        }
    }
    //Update loaded status
    section->loaded = true;
    file.close();

}

/**
 * @brief Unloads a specified section
 * @param header a section name
 */
void Settings::unload_section (std::string header)
{
    if (this->exists(header)) {
        this->stored_settings[header].properties.clear();
        this->stored_settings[header].loaded = false;
    }
}

/**
 * @brief Gets the string of the given setting and copies it into the out string
 * @param header the name of the section
 * @param key the name of setting
 * @param out A string to be written to
 * @return true on successful copy
 */
bool Settings::get (std::string header , std::string  key, std::string* out)
{
    if (this->exists(header ,key))
    {
        *out = this->stored_settings[header].properties[key];
        return true;
    }
    else
    {
        return false;
    }
}

/**
 * @brief Gets the value and converts it to a bool
 * @see Settings::get
 * @param bol Returns the value
 * @return
 */
bool Settings::getBool (std::string header , std::string  key , bool* bol)
{
    std::string b;
    if (this->get(header, key , &b) == false)
        return false;
    b = etc::toLower(b);
    if (b != "")
    {
        *bol = ( b == "true" ? true : false );
        return true;
    }
    else
    {
        return false;
    }
}

bool Settings::getInt (std::string header , std::string  key , int* num)
{
    std::string b;
    if (this->get(header, key , &b) == false)
        return false;

    if ( etc::is_number(b) )
    {
        *num = atoi( b.c_str() );
        return true;
    }
    else
    {
        return false;
    }
}

bool Settings::add (std::string header , std::string key , std::string value)
{
    if (!this->exists(header , key))
    {
        this->stored_settings[header].properties[key] = value;
        return true;
    }
    else
    {
        return false;
    }
}

bool Settings::set (std::string header , std::string key , std::string value)
{
     if (this->exists( header , key ) ) {
        this->stored_settings[header].properties[key] = value;
        return true;
     }
     return false;
}

/**
 * @brief Saves all the sections of a given file
 * @warning Deletes original file and then renames a temp file to replace it
 * @param filename Saves all headers that belong to a file
 * @return bool true on success
 */
bool Settings::save ()
{
    //The File to be read from
    std::ifstream file_in;
    //The File to be written to
    std::fstream file_out;
    //Stream are separate to prevent cross-contamination

    //Open the input file
    file_in.open( this->file_name.c_str() );

    //Check for errors
    if (file_in.is_open() == false) {
        std::cout << "Error input file : " << this->file_name.c_str() << " could not be opened." << std::endl;
        return false;
    }

    //Open the output file
    file_out.open( ("temp~" + this->file_name).c_str() , std::ofstream::out );

    //Check for errors
    if (file_out.is_open() == false) {
        std::cout << "Error output file : " << ("temp~" + this->file_name).c_str() << " could not be opened." << std::endl;
        return false;
    }

    //Go through whole file
    INISection* current_section = &(this->stored_settings[""]);
    while ( file_in.eof() == false )
    {
        std::string line;
        std::getline ( file_in , line );
        line = etc::trim ( line );

        std::size_t equal_pos = line.find_first_of('=', 0);

        if (line == "")
        {

        }
        else if ( etc::startswith( line , ";" ) )
        {

        }
        else if ( etc::startswith( line , "[" ) || etc::endswith( line , "]") )
        {
            //Check if the line has the beginning of a section
            //Update current_section
            if (current_section != nullptr)
            {
                current_section->end_index = file_out.tellg();
            }

            current_section = &( this->stored_settings[ line.substr ( 1 , line.size() - 2 )] );
            current_section->start_index = (int)file_out.tellg() - 1;
        }
        else if (equal_pos != line.npos) {
            std::string key = etc::trim ( line.substr( 0 , equal_pos ) );
            std::string value = current_section->properties[key];
            if (value == "") {
                value = etc::trim ( line.substr( equal_pos + 1  , line.length() - 1 ) );
            }

            file_out << key << '=' << value << std::endl;
            continue;
        }

        //Standard copy line out
        file_out << line << std::endl;
    }

    file_out.close();
    file_in.close();

    //File operations
    //File operation return value
    int file_op = 0;

    //Remove old version
    file_op = std::remove( this->file_name.c_str() );

    //Check if there was an error
    if (file_op != 0) {
        std::cout << "Error while removing the file " << this->file_name.c_str() << std::endl;
        return false;
    }

    //Rename the temp version to replace the deleted version
    file_op = std::rename( ("temp~" + this->file_name).c_str()  , this->file_name.c_str() );

    //Check if there was an error
    if (file_op != 0) {
        std::cout << "Error while renaming the file from " << ("temp~" + this->file_name).c_str() << " to " << this->file_name.c_str() << std::endl;
        return false;
    }

    return true;
}
<|endoftext|>