<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  gatecat <gatecat@ds0.me>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "chains.h"
#include <algorithm>
#include <vector>
#include "cells.h"
#include "chain_utils.h"
#include "design_utils.h"
#include "log.h"
#include "place_common.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

class ChainConstrainer
{
  private:
    int feedio_lcs = 0;
    Context *ctx;
    // Split a carry chain into multiple legal chains
    std::vector<CellChain> split_carry_chain(CellChain &carryc)
    {
        bool start_of_chain = true;
        std::vector<CellChain> chains;
        std::vector<const CellInfo *> tile;
        const int max_length = (ctx->chip_info->height - 2) * 8 - 2;
        auto curr_cell = carryc.cells.begin();
        while (curr_cell != carryc.cells.end()) {
            CellInfo *cell = *curr_cell;
            if (ctx->debug)
                log_info("  processing cell %s\n", ctx->nameOf(cell));
            if (tile.size() >= 8) {
                tile.clear();
            }
            if (start_of_chain) {
                tile.clear();
                chains.emplace_back();
                start_of_chain = false;
                if (cell->ports.at(id_CIN).net) {
                    // CIN is not constant and not part of a chain. Must feed in from fabric
                    CellInfo *feedin = make_carry_feed_in(cell, cell->ports.at(id_CIN));
                    chains.back().cells.push_back(feedin);
                    tile.push_back(feedin);
                    ++feedio_lcs;
                }
            }
            tile.push_back(cell);
            chains.back().cells.push_back(cell);
            bool split_chain = (!ctx->logic_cells_compatible(tile.data(), tile.size())) ||
                               (int(chains.back().cells.size()) > max_length);
            if (split_chain) {
                CellInfo *passout = make_carry_pass_out((*(curr_cell - 1))->ports.at(id_COUT));
                tile.pop_back();
                chains.back().cells.back() = passout;
                start_of_chain = true;
            } else {
                NetInfo *carry_net = cell->ports.at(id_COUT).net;
                bool at_end = (curr_cell == carryc.cells.end() - 1);
                if (carry_net != nullptr && (carry_net->users.entries() > 1 || at_end)) {
                    if (carry_net->users.entries() > 2 ||
                        (net_only_drives(ctx, carry_net, is_lc, id_I3, false) !=
                         net_only_drives(ctx, carry_net, is_lc, id_CIN, false)) ||
                        (at_end && !net_only_drives(ctx, carry_net, is_lc, id_I3, true))) {
                        if (ctx->debug)
                            log_info("      inserting feed-%s\n", at_end ? "out" : "out-in");
                        CellInfo *passout;
                        if (!at_end) {
                            // See if we need to split chain anyway
                            tile.push_back(*(curr_cell + 1));
                            bool split_chain_next = (!ctx->logic_cells_compatible(tile.data(), tile.size())) ||
                                                    (int(chains.back().cells.size()) > max_length);
                            tile.pop_back();
                            if (split_chain_next)
                                start_of_chain = true;
                            passout = make_carry_pass_out(cell->ports.at(id_COUT),
                                                          split_chain_next ? nullptr : *(curr_cell + 1));
                        } else {
                            passout = make_carry_pass_out(cell->ports.at(id_COUT), nullptr);
                        }

                        chains.back().cells.push_back(passout);
                        tile.push_back(passout);
                        ++feedio_lcs;
                    }
                }
                ++curr_cell;
            }
        }
        return chains;
    }

    // Insert a logic cell to legalise a COUT->fabric connection
    CellInfo *make_carry_pass_out(PortInfo &cout_port, CellInfo *cin_cell = nullptr)
    {
        NPNR_ASSERT(cout_port.net != nullptr);
        std::unique_ptr<CellInfo> lc = create_ice_cell(ctx, id_ICESTORM_LC);
        lc->params[id_LUT_INIT] = Property(65280, 16); // 0xff00: O = I3
        lc->params[id_CARRY_ENABLE] = Property::State::S1;
        lc->ports.at(id_O).net = cout_port.net;
        NetInfo *co_i3_net = ctx->createNet(ctx->id(lc->name.str(ctx) + "$I3"));
        co_i3_net->driver = cout_port.net->driver;
        lc->connectPort(id_I3, co_i3_net);
        PortRef o_r;
        o_r.port = id_O;
        o_r.cell = lc.get();
        cout_port.net->driver = o_r;
        cout_port.net = co_i3_net;

        // If COUT also connects to a CIN; preserve the carry chain
        if (cin_cell) {
            NetInfo *co_cin_net = ctx->createNet(ctx->id(lc->name.str(ctx) + "$COUT"));

            // Connect I1 to 1 to preserve carry chain
            NetInfo *vcc = ctx->nets.at(ctx->id("$PACKER_VCC_NET")).get();
            lc->connectPort(id_I1, vcc);

            // Connect co_cin_net to the COUT of the LC
            lc->connectPort(id_COUT, co_cin_net);

            // Find the user corresponding to the next CIN
            int replaced_ports = 0;
            if (ctx->debug)
                log_info("cell: %s\n", cin_cell->name.c_str(ctx));
            for (auto port : {id_CIN, id_I3}) {
                NetInfo *out_net = lc->ports.at(id_O).net;
                auto &cin_p = cin_cell->ports.at(port);
                if (cin_p.net == out_net) {
                    cin_cell->disconnectPort(port);
                    cin_cell->connectPort(port, co_cin_net);
                    ++replaced_ports;
                }
            }
            NPNR_ASSERT(replaced_ports > 0);
        }

        IdString name = lc->name;
        ctx->assignCellInfo(lc.get());
        ctx->cells[lc->name] = std::move(lc);
        return ctx->cells[name].get();
    }

    // Insert a logic cell to legalise a CIN->fabric connection
    CellInfo *make_carry_feed_in(CellInfo *cin_cell, PortInfo &cin_port)
    {
        NPNR_ASSERT(cin_port.net != nullptr);
        std::unique_ptr<CellInfo> lc = create_ice_cell(ctx, id_ICESTORM_LC);
        lc->params[id_CARRY_ENABLE] = Property::State::S1;
        lc->params[id_CIN_CONST] = Property::State::S1;
        lc->params[id_CIN_SET] = Property::State::S1;

        lc->connectPort(id_I1, cin_port.net);
        cin_port.net->users.remove(cin_port.user_idx);

        NetInfo *out_net = ctx->createNet(ctx->id(lc->name.str(ctx) + "$O"));

        lc->connectPort(id_COUT, out_net);

        cin_port.net = nullptr;
        cin_cell->connectPort(cin_port.name, out_net);

        IdString name = lc->name;
        ctx->assignCellInfo(lc.get());
        ctx->cells[lc->name] = std::move(lc);
        return ctx->cells[name].get();
    }

    void process_carries()
    {
        std::vector<CellChain> carry_chains = find_chains(
                ctx, [](const Context *ctx, const CellInfo *cell) { return is_lc(ctx, cell); },
                [](const Context *ctx, const

                   CellInfo *cell) {
                    CellInfo *carry_prev = net_driven_by(ctx, cell->ports.at(id_CIN).net, is_lc, id_COUT);
                    if (carry_prev != nullptr)
                        return carry_prev;
                    CellInfo *i3_prev = net_driven_by(ctx, cell->ports.at(id_I3).net, is_lc, id_COUT);
                    if (i3_prev != nullptr)
                        return i3_prev;
                    return (CellInfo *)nullptr;
                },
                [](const Context *ctx, const CellInfo *cell) {
                    CellInfo *carry_next = net_only_drives(ctx, cell->ports.at(id_COUT).net, is_lc, id_CIN, false);
                    if (carry_next != nullptr)
                        return carry_next;
                    CellInfo *i3_next = net_only_drives(ctx, cell->ports.at(id_COUT).net, is_lc, id_I3, false);
                    if (i3_next != nullptr)
                        return i3_next;
                    return (CellInfo *)nullptr;
                });
        pool<IdString> chained;
        for (auto &base_chain : carry_chains) {
            for (auto c : base_chain.cells)
                chained.insert(c->name);
        }
        // Any cells not in chains, but with carry enabled, must also be put in a single-carry chain
        // for correct processing
        for (auto &cell : ctx->cells) {
            CellInfo *ci = cell.second.get();
            if (chained.find(cell.first) == chained.end() && is_lc(ctx, ci) &&
                bool_or_default(ci->params, id_CARRY_ENABLE)) {
                CellChain sChain;
                sChain.cells.push_back(ci);
                chained.insert(cell.first);
                carry_chains.push_back(sChain);
            }
        }
        std::vector<CellChain> all_chains;
        // Chain splitting
        for (auto &base_chain : carry_chains) {
            if (ctx->verbose) {
                log_info("Found carry chain: \n");
                for (auto entry : base_chain.cells)
                    log_info("     %s\n", entry->name.c_str(ctx));
                log_info("\n");
            }
            std::vector<CellChain> split_chains = split_carry_chain(base_chain);
            for (auto &chain : split_chains) {
                all_chains.push_back(chain);
            }
        }
        // Actual chain placement
        for (auto &chain : all_chains) {
            if (ctx->verbose)
                log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx));

            // Place carry chain
            chain.cells.at(0)->constr_abs_z = true;
            chain.cells.at(0)->constr_z = 0;
            chain.cells.at(0)->cluster = chain.cells.at(0)->name;

            for (int i = 1; i < int(chain.cells.size()); i++) {
                chain.cells.at(i)->constr_x = 0;
                chain.cells.at(i)->constr_y = (i / 8);
                chain.cells.at(i)->constr_z = i % 8;
                chain.cells.at(i)->constr_abs_z = true;
                chain.cells.at(i)->cluster = chain.cells.at(0)->name;
                chain.cells.at(0)->constr_children.push_back(chain.cells.at(i));
            }
        }
        log_info("    %4d LCs used to legalise carry chains.\n", feedio_lcs);
    }

  public:
    ChainConstrainer(Context *ctx) : ctx(ctx){};
    void constrain_chains() { process_carries(); }
};

void constrain_chains(Context *ctx)
{
    log_info("Constraining chains...\n");
    ChainConstrainer(ctx).constrain_chains();
}

NEXTPNR_NAMESPACE_END
<commit_msg>ice40: Avoid chain finder from mixing up chains by only allowing I3 chaining at end<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  gatecat <gatecat@ds0.me>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "chains.h"
#include <algorithm>
#include <vector>
#include "cells.h"
#include "chain_utils.h"
#include "design_utils.h"
#include "log.h"
#include "place_common.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

class ChainConstrainer
{
  private:
    int feedio_lcs = 0;
    Context *ctx;
    // Split a carry chain into multiple legal chains
    std::vector<CellChain> split_carry_chain(CellChain &carryc)
    {
        bool start_of_chain = true;
        std::vector<CellChain> chains;
        std::vector<const CellInfo *> tile;
        const int max_length = (ctx->chip_info->height - 2) * 8 - 2;
        auto curr_cell = carryc.cells.begin();
        while (curr_cell != carryc.cells.end()) {
            CellInfo *cell = *curr_cell;
            if (ctx->debug)
                log_info("  processing cell %s\n", ctx->nameOf(cell));
            if (tile.size() >= 8) {
                tile.clear();
            }
            if (start_of_chain) {
                tile.clear();
                chains.emplace_back();
                start_of_chain = false;
                if (cell->ports.at(id_CIN).net) {
                    // CIN is not constant and not part of a chain. Must feed in from fabric
                    CellInfo *feedin = make_carry_feed_in(cell, cell->ports.at(id_CIN));
                    chains.back().cells.push_back(feedin);
                    tile.push_back(feedin);
                    ++feedio_lcs;
                }
            }
            tile.push_back(cell);
            chains.back().cells.push_back(cell);
            bool split_chain = (!ctx->logic_cells_compatible(tile.data(), tile.size())) ||
                               (int(chains.back().cells.size()) > max_length);
            if (split_chain) {
                CellInfo *passout = make_carry_pass_out((*(curr_cell - 1))->ports.at(id_COUT));
                tile.pop_back();
                chains.back().cells.back() = passout;
                start_of_chain = true;
            } else {
                NetInfo *carry_net = cell->ports.at(id_COUT).net;
                bool at_end = (curr_cell == carryc.cells.end() - 1);
                if (carry_net != nullptr && (carry_net->users.entries() > 1 || at_end)) {
                    if (carry_net->users.entries() > 2 ||
                        (net_only_drives(ctx, carry_net, is_lc, id_I3, false) !=
                         net_only_drives(ctx, carry_net, is_lc, id_CIN, false)) ||
                        (at_end && !net_only_drives(ctx, carry_net, is_lc, id_I3, true))) {
                        if (ctx->debug)
                            log_info("      inserting feed-%s\n", at_end ? "out" : "out-in");
                        CellInfo *passout;
                        if (!at_end) {
                            // See if we need to split chain anyway
                            tile.push_back(*(curr_cell + 1));
                            bool split_chain_next = (!ctx->logic_cells_compatible(tile.data(), tile.size())) ||
                                                    (int(chains.back().cells.size()) > max_length);
                            tile.pop_back();
                            if (split_chain_next)
                                start_of_chain = true;
                            passout = make_carry_pass_out(cell->ports.at(id_COUT),
                                                          split_chain_next ? nullptr : *(curr_cell + 1));
                        } else {
                            passout = make_carry_pass_out(cell->ports.at(id_COUT), nullptr);
                        }

                        chains.back().cells.push_back(passout);
                        tile.push_back(passout);
                        ++feedio_lcs;
                    }
                }
                ++curr_cell;
            }
        }
        return chains;
    }

    // Insert a logic cell to legalise a COUT->fabric connection
    CellInfo *make_carry_pass_out(PortInfo &cout_port, CellInfo *cin_cell = nullptr)
    {
        NPNR_ASSERT(cout_port.net != nullptr);
        std::unique_ptr<CellInfo> lc = create_ice_cell(ctx, id_ICESTORM_LC);
        lc->params[id_LUT_INIT] = Property(65280, 16); // 0xff00: O = I3
        lc->params[id_CARRY_ENABLE] = Property::State::S1;
        lc->ports.at(id_O).net = cout_port.net;
        NetInfo *co_i3_net = ctx->createNet(ctx->id(lc->name.str(ctx) + "$I3"));
        co_i3_net->driver = cout_port.net->driver;
        lc->connectPort(id_I3, co_i3_net);
        PortRef o_r;
        o_r.port = id_O;
        o_r.cell = lc.get();
        cout_port.net->driver = o_r;
        cout_port.net = co_i3_net;

        // If COUT also connects to a CIN; preserve the carry chain
        if (cin_cell) {
            NetInfo *co_cin_net = ctx->createNet(ctx->id(lc->name.str(ctx) + "$COUT"));

            // Connect I1 to 1 to preserve carry chain
            NetInfo *vcc = ctx->nets.at(ctx->id("$PACKER_VCC_NET")).get();
            lc->connectPort(id_I1, vcc);

            // Connect co_cin_net to the COUT of the LC
            lc->connectPort(id_COUT, co_cin_net);

            // Find the user corresponding to the next CIN
            int replaced_ports = 0;
            if (ctx->debug)
                log_info("cell: %s\n", cin_cell->name.c_str(ctx));
            for (auto port : {id_CIN, id_I3}) {
                NetInfo *out_net = lc->ports.at(id_O).net;
                auto &cin_p = cin_cell->ports.at(port);
                if (cin_p.net == out_net) {
                    cin_cell->disconnectPort(port);
                    cin_cell->connectPort(port, co_cin_net);
                    ++replaced_ports;
                }
            }
            NPNR_ASSERT(replaced_ports > 0);
        }

        IdString name = lc->name;
        ctx->assignCellInfo(lc.get());
        ctx->cells[lc->name] = std::move(lc);
        return ctx->cells[name].get();
    }

    // Insert a logic cell to legalise a CIN->fabric connection
    CellInfo *make_carry_feed_in(CellInfo *cin_cell, PortInfo &cin_port)
    {
        NPNR_ASSERT(cin_port.net != nullptr);
        std::unique_ptr<CellInfo> lc = create_ice_cell(ctx, id_ICESTORM_LC);
        lc->params[id_CARRY_ENABLE] = Property::State::S1;
        lc->params[id_CIN_CONST] = Property::State::S1;
        lc->params[id_CIN_SET] = Property::State::S1;

        lc->connectPort(id_I1, cin_port.net);
        cin_port.net->users.remove(cin_port.user_idx);

        NetInfo *out_net = ctx->createNet(ctx->id(lc->name.str(ctx) + "$O"));

        lc->connectPort(id_COUT, out_net);

        cin_port.net = nullptr;
        cin_cell->connectPort(cin_port.name, out_net);

        IdString name = lc->name;
        ctx->assignCellInfo(lc.get());
        ctx->cells[lc->name] = std::move(lc);
        return ctx->cells[name].get();
    }

    void process_carries()
    {
        // Find carry roots
        std::vector<CellChain> carry_chains;
        pool<IdString> processed;
        for (auto &cell : ctx->cells) {
            CellInfo *ci = cell.second.get();
            if (is_lc(ctx, ci) && bool_or_default(ci->params, id_CARRY_ENABLE)) {
                // possibly a non-root if CIN or I3 driven by another cout
                NetInfo *cin = ci->getPort(id_CIN);
                if (cin && cin->driver.cell && is_lc(ctx, cin->driver.cell) && cin->driver.port == id_COUT) {
                    continue;
                }
                carry_chains.emplace_back();
                auto &cc = carry_chains.back();
                CellInfo *cursor = ci;
                while (cursor) {
                    cc.cells.push_back(cursor);
                    processed.insert(cursor->name);
                    NetInfo *cout = cursor->getPort(id_COUT);
                    if (!cout)
                        break;
                    cursor = nullptr;
                    // look for CIN connectivity
                    for (auto &usr : cout->users) {
                        if (is_lc(ctx, usr.cell) && usr.port == id_CIN && !processed.count(usr.cell->name)) {
                            cursor = usr.cell;
                            break;
                        }
                    }
                    // look for I3 connectivity - only to a top cell with no further chaining
                    if (cursor)
                        continue;
                    for (auto &usr : cout->users) {
                        if (is_lc(ctx, usr.cell) && usr.port == id_I3 && !processed.count(usr.cell->name) &&
                            !usr.cell->getPort(id_COUT)) {
                            cursor = usr.cell;
                            break;
                        }
                    }
                }
            }
        }
        // anything left behind....
        for (auto &cell : ctx->cells) {
            CellInfo *ci = cell.second.get();
            if (is_lc(ctx, ci) && bool_or_default(ci->params, id_CARRY_ENABLE) && !processed.count(ci->name)) {
                carry_chains.emplace_back();
                carry_chains.back().cells.push_back(ci);
                processed.insert(ci->name);
            }
        }
        std::vector<CellChain> all_chains;
        // Chain splitting
        for (auto &base_chain : carry_chains) {
            if (ctx->verbose) {
                log_info("Found carry chain: \n");
                for (auto entry : base_chain.cells)
                    log_info("     %s\n", entry->name.c_str(ctx));
                log_info("\n");
            }
            std::vector<CellChain> split_chains = split_carry_chain(base_chain);
            for (auto &chain : split_chains) {
                all_chains.push_back(chain);
            }
        }
        // Actual chain placement
        for (auto &chain : all_chains) {
            if (ctx->verbose)
                log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx));

            // Place carry chain
            chain.cells.at(0)->constr_abs_z = true;
            chain.cells.at(0)->constr_z = 0;
            chain.cells.at(0)->cluster = chain.cells.at(0)->name;

            for (int i = 1; i < int(chain.cells.size()); i++) {
                chain.cells.at(i)->constr_x = 0;
                chain.cells.at(i)->constr_y = (i / 8);
                chain.cells.at(i)->constr_z = i % 8;
                chain.cells.at(i)->constr_abs_z = true;
                chain.cells.at(i)->cluster = chain.cells.at(0)->name;
                chain.cells.at(0)->constr_children.push_back(chain.cells.at(i));
            }
        }
        log_info("    %4d LCs used to legalise carry chains.\n", feedio_lcs);
    }

  public:
    ChainConstrainer(Context *ctx) : ctx(ctx){};
    void constrain_chains() { process_carries(); }
};

void constrain_chains(Context *ctx)
{
    log_info("Constraining chains...\n");
    ChainConstrainer(ctx).constrain_chains();
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>#ifndef CPPJIEBA_KEYWORD_EXTRACTOR_H
#define CPPJIEBA_KEYWORD_EXTRACTOR_H

#include "MixSegment.hpp"
#include <cmath>
#include <set>

#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))

namespace CppJieba
{
    using namespace Limonp;

    /*utf8*/
    class KeywordExtractor: public InitOnOff
    {
        private:
            MixSegment _segment;
        private:
            unordered_map<string, double> _idfMap;
            double _idfAverage;

            unordered_set<string> _stopWords;
        public:
            KeywordExtractor(){_setInitFlag(false);};
            explicit KeywordExtractor(const string& dictPath, const string& hmmFilePath, const string& idfPath, const string& stopWordPath)
            {
                _setInitFlag(init(dictPath, hmmFilePath, idfPath, stopWordPath));
            };
            ~KeywordExtractor(){};

        public:
            bool init(const string& dictPath, const string& hmmFilePath, const string& idfPath, const string& stopWordPath)
            {
                _loadIdfDict(idfPath);
                _loadStopWordDict(stopWordPath);
                return _setInitFlag(_segment.init(dictPath, hmmFilePath));
            };
        public:

            bool extract(const string& str, vector<string>& keywords, size_t topN) const
            {
                assert(_getInitFlag());
                vector<pair<string, double> > topWords;
                if(!extract(str, topWords, topN))
                {
                    return false;
                }
                for(size_t i = 0; i < topWords.size(); i++)
                {
                    keywords.push_back(topWords[i].first);
                }
                return true;
            }

            bool extract(const string& str, vector<pair<string, double> >& keywords, size_t topN) const
            {
                vector<string> words;
                if(!_segment.cut(str, words))
                {
                    LogError("segment cut(%s) failed.", str.c_str());
                    return false;
                }

                // filtering single word.
                for(vector<string>::iterator iter = words.begin(); iter != words.end(); )
                {
                    if(_isSingleWord(*iter))
                    {
                        iter = words.erase(iter);
                    }
                    else
                    {
                        iter++;
                    }
                }

                map<string, double> wordmap;
                for(size_t i = 0; i < words.size(); i ++)
                {
                    wordmap[ words[i] ] += 1.0;
                }

                for(map<string, double>::iterator itr = wordmap.begin(); itr != wordmap.end(); )
                {
                    if(_stopWords.end() != _stopWords.find(itr->first))
                    {
                        wordmap.erase(itr++);
                        continue;
                    }

                    unordered_map<string, double>::const_iterator cit = _idfMap.find(itr->first);
                    if(cit != _idfMap.end())
                    {
                        itr->second *= cit->second;
                    }
                    else
                    {
                        itr->second *= _idfAverage;
                    }
                    itr ++;
                }

                keywords.clear();
                std::copy(wordmap.begin(), wordmap.end(), std::inserter(keywords, keywords.begin()));
                topN = MIN(topN, keywords.size());
                partial_sort(keywords.begin(), keywords.begin() + topN, keywords.end(), _cmp);
                keywords.resize(topN);
                return true;
            }
        private:
            void _loadIdfDict(const string& idfPath)
            {
                ifstream ifs(idfPath.c_str());
                if(!ifs)
                {
                    LogError("open %s failed.", idfPath.c_str());
                    assert(false);
                }
                string line ;
                vector<string> buf;
                double idf = 0.0;
                double idfSum = 0.0;
                size_t lineno = 0;
                for(;getline(ifs, line); lineno++)
                {
                    buf.clear();
                    if(line.empty())
                    {
                        LogError("line[%d] empty. skipped.", lineno);
                        continue;
                    }
                    if(!split(line, buf, " ") || buf.size() != 2)
                    {
                        LogError("line %d [%s] illegal. skipped.", lineno, line.c_str());
                        continue;
                    }
                    idf = atof(buf[1].c_str());
                    _idfMap[buf[0]] = idf;
                    idfSum += idf;

                }

                assert(lineno);
                _idfAverage = idfSum / lineno;
                assert(_idfAverage > 0.0);
            }
            void _loadStopWordDict(const string& filePath)
            {
                ifstream ifs(filePath.c_str());
                if(!ifs)
                {
                    LogError("open %s failed.", filePath.c_str());
                    assert(false);
                }
                string line ;
                while(getline(ifs, line))
                {
                    _stopWords.insert(line);
                }
                assert(_stopWords.size());
            }
        private:
            bool _isSingleWord(const string& str) const
            {
                Unicode unicode;
                TransCode::decode(str, unicode);
                if(unicode.size() == 1)
                  return true;
                return false;
            }

        private:
            static bool _cmp(const pair<string, double>& lhs, const pair<string, double>& rhs)
            {
                return lhs.second > rhs.second;
            }

    };
}

#endif

<commit_msg>make keywordextractor faster<commit_after>#ifndef CPPJIEBA_KEYWORD_EXTRACTOR_H
#define CPPJIEBA_KEYWORD_EXTRACTOR_H

#include "MixSegment.hpp"
#include <cmath>
#include <set>

#define MIN(X,Y) ((X) < (Y) ? (X) : (Y))

namespace CppJieba
{
    using namespace Limonp;

    /*utf8*/
    class KeywordExtractor: public InitOnOff
    {
        private:
            MixSegment _segment;
        private:
            unordered_map<string, double> _idfMap;
            double _idfAverage;

            unordered_set<string> _stopWords;
        public:
            KeywordExtractor(){_setInitFlag(false);};
            explicit KeywordExtractor(const string& dictPath, const string& hmmFilePath, const string& idfPath, const string& stopWordPath)
            {
                _setInitFlag(init(dictPath, hmmFilePath, idfPath, stopWordPath));
            };
            ~KeywordExtractor(){};

        public:
            bool init(const string& dictPath, const string& hmmFilePath, const string& idfPath, const string& stopWordPath)
            {
                _loadIdfDict(idfPath);
                _loadStopWordDict(stopWordPath);
                return _setInitFlag(_segment.init(dictPath, hmmFilePath));
            };
        public:

            bool extract(const string& str, vector<string>& keywords, size_t topN) const
            {
                assert(_getInitFlag());
                vector<pair<string, double> > topWords;
                if(!extract(str, topWords, topN))
                {
                    return false;
                }
                for(size_t i = 0; i < topWords.size(); i++)
                {
                    keywords.push_back(topWords[i].first);
                }
                return true;
            }

            bool extract(const string& str, vector<pair<string, double> >& keywords, size_t topN) const
            {
                vector<string> words;
                if(!_segment.cut(str, words))
                {
                    LogError("segment cut(%s) failed.", str.c_str());
                    return false;
                }

                map<string, double> wordmap;
                for(vector<string>::iterator iter = words.begin(); iter != words.end(); iter++)
                {
                    if(_isSingleWord(*iter))
                    {
                        continue;
                    }
                    wordmap[*iter] += 1.0;
                }

                for(map<string, double>::iterator itr = wordmap.begin(); itr != wordmap.end(); )
                {
                    if(_stopWords.end() != _stopWords.find(itr->first))
                    {
                        wordmap.erase(itr++);
                        continue;
                    }

                    unordered_map<string, double>::const_iterator cit = _idfMap.find(itr->first);
                    if(cit != _idfMap.end())
                    {
                        itr->second *= cit->second;
                    }
                    else
                    {
                        itr->second *= _idfAverage;
                    }
                    itr ++;
                }

                keywords.clear();
                std::copy(wordmap.begin(), wordmap.end(), std::inserter(keywords, keywords.begin()));
                topN = MIN(topN, keywords.size());
                partial_sort(keywords.begin(), keywords.begin() + topN, keywords.end(), _cmp);
                keywords.resize(topN);
                return true;
            }
        private:
            void _loadIdfDict(const string& idfPath)
            {
                ifstream ifs(idfPath.c_str());
                if(!ifs)
                {
                    LogError("open %s failed.", idfPath.c_str());
                    assert(false);
                }
                string line ;
                vector<string> buf;
                double idf = 0.0;
                double idfSum = 0.0;
                size_t lineno = 0;
                for(;getline(ifs, line); lineno++)
                {
                    buf.clear();
                    if(line.empty())
                    {
                        LogError("line[%d] empty. skipped.", lineno);
                        continue;
                    }
                    if(!split(line, buf, " ") || buf.size() != 2)
                    {
                        LogError("line %d [%s] illegal. skipped.", lineno, line.c_str());
                        continue;
                    }
                    idf = atof(buf[1].c_str());
                    _idfMap[buf[0]] = idf;
                    idfSum += idf;

                }

                assert(lineno);
                _idfAverage = idfSum / lineno;
                assert(_idfAverage > 0.0);
            }
            void _loadStopWordDict(const string& filePath)
            {
                ifstream ifs(filePath.c_str());
                if(!ifs)
                {
                    LogError("open %s failed.", filePath.c_str());
                    assert(false);
                }
                string line ;
                while(getline(ifs, line))
                {
                    _stopWords.insert(line);
                }
                assert(_stopWords.size());
            }
        private:
            bool _isSingleWord(const string& str) const
            {
                Unicode unicode;
                TransCode::decode(str, unicode);
                if(unicode.size() == 1)
                  return true;
                return false;
            }

        private:
            static bool _cmp(const pair<string, double>& lhs, const pair<string, double>& rhs)
            {
                return lhs.second > rhs.second;
            }

    };
}

#endif

<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Bitcoin Unlimited developers

#include "connmgr.h"
#include "expedited.h"

std::unique_ptr<CConnMgr> connmgr(new CConnMgr);

/**
 * Find a node in a vector.  Just calls std::find.  Split out for cleanliness and also because std:find won't be
 * enough if we switch to vectors of noderefs.  Requires any lock for vector traversal to be held.
 */
static std::vector<CNode *>::iterator FindNode(std::vector<CNode *> &vNodes, CNode *pNode)
{
    return std::find(vNodes.begin(), vNodes.end(), pNode);
}

/**
 * Add a node to a vector, and take a reference.  This function does NOT prevent adding duplicates.
 * Requires any lock for vector traversal to be held.
 * @param[in] vNodes      The vector of nodes.
 * @param[in] pNode       The node to add.
 */
static void AddNode(std::vector<CNode *> &vNodes, CNode *pNode)
{
    pNode->AddRef();
    vNodes.push_back(pNode);
}

/**
 * If a node is present in a vector, remove it and drop a reference.
 * Requires any lock for vector traversal to be held.
 * @param[in] vNodes      The vector of nodes.
 * @param[in] pNode       The node to remove.
 * @return  True if the node was originally present, false if not.
 */
static bool RemoveNode(std::vector<CNode *> &vNodes, CNode *pNode)
{
    auto Node = FindNode(vNodes, pNode);

    if (Node != vNodes.end())
    {
        pNode->Release();
        vNodes.erase(Node);
        return true;
    }

    return false;
}

CConnMgr::CConnMgr() : nExpeditedBlocksMax(32), nExpeditedTxsMax(32), next(0)
{
    vSendExpeditedBlocks.reserve(256);
    vSendExpeditedTxs.reserve(256);
    vExpeditedUpstream.reserve(256);
}

NodeId CConnMgr::NextNodeId()
{
    // Pre-increment; do not use zero
    return ++next;
}

/**
 * Given a node ID, return a node reference to the node.
 */
CNodeRef CConnMgr::FindNodeFromId(NodeId id)
{
    LOCK(cs_vNodes);

    for (CNode *pNode : vNodes)
    {
        if (pNode->GetId() == id)
            return CNodeRef(pNode);
    }

    return CNodeRef();
}

void CConnMgr::EnableExpeditedSends(CNode *pNode, bool fBlocks, bool fTxs, bool fForceIfFull)
{
    LOCK(cs_expedited);

    if (fBlocks && FindNode(vSendExpeditedBlocks, pNode) == vSendExpeditedBlocks.end())
    {
        if (fForceIfFull || vSendExpeditedBlocks.size() < nExpeditedBlocksMax)
        {
            AddNode(vSendExpeditedBlocks, pNode);
            LOG(THIN, "Enabled expedited blocks to peer %s (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedBlocks.size());
        }
        else
        {
            LOG(THIN, "Cannot enable expedited blocks to peer %s, I am full (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedBlocks.size());
        }
    }

    if (fTxs && FindNode(vSendExpeditedTxs, pNode) == vSendExpeditedTxs.end())
    {
        if (fForceIfFull || vSendExpeditedTxs.size() < nExpeditedTxsMax)
        {
            AddNode(vSendExpeditedTxs, pNode);
            LOG(THIN, "Enabled expedited txs to peer %s (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedTxs.size());
        }
        else
        {
            LOG(THIN, "Cannot enable expedited txs to peer %s, I am full (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedTxs.size());
        }
    }
}

void CConnMgr::DisableExpeditedSends(CNode *pNode, bool fBlocks, bool fTxs)
{
    LOCK(cs_expedited);

    if (fBlocks && RemoveNode(vSendExpeditedBlocks, pNode))
        LOG(THIN, "Disabled expedited blocks to peer %s (%u peers total)\n", pNode->GetLogName(),
            vSendExpeditedBlocks.size());

    if (fTxs && RemoveNode(vSendExpeditedTxs, pNode))
        LOG(THIN, "Disabled expedited txs to peer %s (%u peers total)\n", pNode->GetLogName(),
            vSendExpeditedTxs.size());
}

void CConnMgr::HandleCommandLine()
{
    nExpeditedBlocksMax = GetArg("-maxexpeditedblockrecipients", nExpeditedBlocksMax);
    nExpeditedTxsMax = GetArg("-maxexpeditedtxrecipients", nExpeditedTxsMax);
}

// Called after a node is removed from the node list.
void CConnMgr::RemovedNode(CNode *pNode)
{
    LOCK(cs_expedited);

    RemoveNode(vSendExpeditedBlocks, pNode);
    RemoveNode(vSendExpeditedTxs, pNode);
    RemoveNode(vExpeditedUpstream, pNode);
}

void CConnMgr::ExpeditedNodeCounts(uint32_t &nBlocks, uint32_t &nTxs, uint32_t &nUpstream)
{
    LOCK(cs_expedited);

    nBlocks = vSendExpeditedBlocks.size();
    nTxs = vSendExpeditedTxs.size();
    nUpstream = vExpeditedUpstream.size();
}

VNodeRefs CConnMgr::ExpeditedBlockNodes()
{
    LOCK(cs_expedited);

    VNodeRefs vRefs;

    BOOST_FOREACH (CNode *pNode, vExpeditedUpstream)
        vRefs.push_back(CNodeRef(pNode));

    return vRefs;
}

bool CConnMgr::PushExpeditedRequest(CNode *pNode, uint64_t flags)
{
    if (!IsThinBlocksEnabled())
        return error("Thinblocks is not enabled so cannot request expedited blocks from peer %s", pNode->GetLogName());

    if (!pNode->ThinBlockCapable())
        return error("Remote peer has not enabled Thinblocks so you cannot request expedited blocks from %s",
            pNode->GetLogName());

    if (flags & EXPEDITED_BLOCKS)
    {
        LOCK(cs_expedited);

        // Add or remove this node as an upstream node
        if (flags & EXPEDITED_STOP)
        {
            RemoveNode(vExpeditedUpstream, pNode);
            LOGA("Requesting a stop of expedited blocks from peer %s\n", pNode->GetLogName());
        }
        else
        {
            if (FindNode(vExpeditedUpstream, pNode) == vExpeditedUpstream.end())
                AddNode(vExpeditedUpstream, pNode);
            LOGA("Requesting expedited blocks from peer %s\n", pNode->GetLogName());
        }
    }

    // Push even if its a repeat to allow the operator to use the CLI or GUI to force another message.
    pNode->PushMessage(NetMsgType::XPEDITEDREQUEST, flags);

    return true;
}

bool CConnMgr::IsExpeditedUpstream(CNode *pNode)
{
    LOCK(cs_expedited);

    return FindNode(vExpeditedUpstream, pNode) != vExpeditedUpstream.end();
}
<commit_msg>Fix variables shadowing in connmgr.cpp<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Copyright (c) 2016-2018 The Bitcoin Unlimited developers

#include "connmgr.h"
#include "expedited.h"

std::unique_ptr<CConnMgr> connmgr(new CConnMgr);

/**
 * Find a node in a vector.  Just calls std::find.  Split out for cleanliness and also because std:find won't be
 * enough if we switch to vectors of noderefs.  Requires any lock for vector traversal to be held.
 */
static std::vector<CNode *>::iterator FindNode(std::vector<CNode *> &_vNodes, CNode *pNode)
{
    return std::find(_vNodes.begin(), _vNodes.end(), pNode);
}

/**
 * Add a node to a vector, and take a reference.  This function does NOT prevent adding duplicates.
 * Requires any lock for vector traversal to be held.
 * @param[in] vNodes      The vector of nodes.
 * @param[in] pNode       The node to add.
 */
static void AddNode(std::vector<CNode *> &_vNodes, CNode *pNode)
{
    pNode->AddRef();
    _vNodes.push_back(pNode);
}

/**
 * If a node is present in a vector, remove it and drop a reference.
 * Requires any lock for vector traversal to be held.
 * @param[in] vNodes      The vector of nodes.
 * @param[in] pNode       The node to remove.
 * @return  True if the node was originally present, false if not.
 */
static bool RemoveNode(std::vector<CNode *> &_vNodes, CNode *pNode)
{
    auto Node = FindNode(_vNodes, pNode);

    if (Node != _vNodes.end())
    {
        pNode->Release();
        _vNodes.erase(Node);
        return true;
    }

    return false;
}

CConnMgr::CConnMgr() : nExpeditedBlocksMax(32), nExpeditedTxsMax(32), next(0)
{
    vSendExpeditedBlocks.reserve(256);
    vSendExpeditedTxs.reserve(256);
    vExpeditedUpstream.reserve(256);
}

NodeId CConnMgr::NextNodeId()
{
    // Pre-increment; do not use zero
    return ++next;
}

/**
 * Given a node ID, return a node reference to the node.
 */
CNodeRef CConnMgr::FindNodeFromId(NodeId id)
{
    LOCK(cs_vNodes);

    for (CNode *pNode : vNodes)
    {
        if (pNode->GetId() == id)
            return CNodeRef(pNode);
    }

    return CNodeRef();
}

void CConnMgr::EnableExpeditedSends(CNode *pNode, bool fBlocks, bool fTxs, bool fForceIfFull)
{
    LOCK(cs_expedited);

    if (fBlocks && FindNode(vSendExpeditedBlocks, pNode) == vSendExpeditedBlocks.end())
    {
        if (fForceIfFull || vSendExpeditedBlocks.size() < nExpeditedBlocksMax)
        {
            AddNode(vSendExpeditedBlocks, pNode);
            LOG(THIN, "Enabled expedited blocks to peer %s (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedBlocks.size());
        }
        else
        {
            LOG(THIN, "Cannot enable expedited blocks to peer %s, I am full (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedBlocks.size());
        }
    }

    if (fTxs && FindNode(vSendExpeditedTxs, pNode) == vSendExpeditedTxs.end())
    {
        if (fForceIfFull || vSendExpeditedTxs.size() < nExpeditedTxsMax)
        {
            AddNode(vSendExpeditedTxs, pNode);
            LOG(THIN, "Enabled expedited txs to peer %s (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedTxs.size());
        }
        else
        {
            LOG(THIN, "Cannot enable expedited txs to peer %s, I am full (%u peers total)\n", pNode->GetLogName(),
                vSendExpeditedTxs.size());
        }
    }
}

void CConnMgr::DisableExpeditedSends(CNode *pNode, bool fBlocks, bool fTxs)
{
    LOCK(cs_expedited);

    if (fBlocks && RemoveNode(vSendExpeditedBlocks, pNode))
        LOG(THIN, "Disabled expedited blocks to peer %s (%u peers total)\n", pNode->GetLogName(),
            vSendExpeditedBlocks.size());

    if (fTxs && RemoveNode(vSendExpeditedTxs, pNode))
        LOG(THIN, "Disabled expedited txs to peer %s (%u peers total)\n", pNode->GetLogName(),
            vSendExpeditedTxs.size());
}

void CConnMgr::HandleCommandLine()
{
    nExpeditedBlocksMax = GetArg("-maxexpeditedblockrecipients", nExpeditedBlocksMax);
    nExpeditedTxsMax = GetArg("-maxexpeditedtxrecipients", nExpeditedTxsMax);
}

// Called after a node is removed from the node list.
void CConnMgr::RemovedNode(CNode *pNode)
{
    LOCK(cs_expedited);

    RemoveNode(vSendExpeditedBlocks, pNode);
    RemoveNode(vSendExpeditedTxs, pNode);
    RemoveNode(vExpeditedUpstream, pNode);
}

void CConnMgr::ExpeditedNodeCounts(uint32_t &nBlocks, uint32_t &nTxs, uint32_t &nUpstream)
{
    LOCK(cs_expedited);

    nBlocks = vSendExpeditedBlocks.size();
    nTxs = vSendExpeditedTxs.size();
    nUpstream = vExpeditedUpstream.size();
}

VNodeRefs CConnMgr::ExpeditedBlockNodes()
{
    LOCK(cs_expedited);

    VNodeRefs vRefs;

    BOOST_FOREACH (CNode *pNode, vExpeditedUpstream)
        vRefs.push_back(CNodeRef(pNode));

    return vRefs;
}

bool CConnMgr::PushExpeditedRequest(CNode *pNode, uint64_t flags)
{
    if (!IsThinBlocksEnabled())
        return error("Thinblocks is not enabled so cannot request expedited blocks from peer %s", pNode->GetLogName());

    if (!pNode->ThinBlockCapable())
        return error("Remote peer has not enabled Thinblocks so you cannot request expedited blocks from %s",
            pNode->GetLogName());

    if (flags & EXPEDITED_BLOCKS)
    {
        LOCK(cs_expedited);

        // Add or remove this node as an upstream node
        if (flags & EXPEDITED_STOP)
        {
            RemoveNode(vExpeditedUpstream, pNode);
            LOGA("Requesting a stop of expedited blocks from peer %s\n", pNode->GetLogName());
        }
        else
        {
            if (FindNode(vExpeditedUpstream, pNode) == vExpeditedUpstream.end())
                AddNode(vExpeditedUpstream, pNode);
            LOGA("Requesting expedited blocks from peer %s\n", pNode->GetLogName());
        }
    }

    // Push even if its a repeat to allow the operator to use the CLI or GUI to force another message.
    pNode->PushMessage(NetMsgType::XPEDITEDREQUEST, flags);

    return true;
}

bool CConnMgr::IsExpeditedUpstream(CNode *pNode)
{
    LOCK(cs_expedited);

    return FindNode(vExpeditedUpstream, pNode) != vExpeditedUpstream.end();
}
<|endoftext|>


<commit_before><commit_msg>Init allocated SkBitmap pixels<commit_after><|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "call/audio_send_stream.h"

#include <stddef.h>

#include "rtc_base/string_encode.h"
#include "rtc_base/strings/audio_format_to_string.h"
#include "rtc_base/strings/string_builder.h"

namespace webrtc {

AudioSendStream::Stats::Stats() = default;
AudioSendStream::Stats::~Stats() = default;

AudioSendStream::Config::Config(Transport* send_transport)
    : send_transport(send_transport) {}

AudioSendStream::Config::~Config() = default;

std::string AudioSendStream::Config::ToString() const {
  char buf[1024];
  rtc::SimpleStringBuilder ss(buf);
  ss << "{rtp: " << rtp.ToString();
  ss << ", rtcp_report_interval_ms: " << rtcp_report_interval_ms;
  ss << ", send_transport: " << (send_transport ? "(Transport)" : "null");
  ss << ", min_bitrate_bps: " << min_bitrate_bps;
  ss << ", max_bitrate_bps: " << max_bitrate_bps;
  ss << ", send_codec_spec: "
     << (send_codec_spec ? send_codec_spec->ToString() : "<unset>");
  ss << '}';
  return ss.str();
}

AudioSendStream::Config::Rtp::Rtp() = default;

AudioSendStream::Config::Rtp::~Rtp() = default;

std::string AudioSendStream::Config::Rtp::ToString() const {
  char buf[1024];
  rtc::SimpleStringBuilder ss(buf);
  ss << "{ssrc: " << ssrc;
  ss << ", extmap-allow-mixed: " << (extmap_allow_mixed ? "true" : "false");
  ss << ", extensions: [";
  for (size_t i = 0; i < extensions.size(); ++i) {
    ss << extensions[i].ToString();
    if (i != extensions.size() - 1) {
      ss << ", ";
    }
  }
  ss << ']';
  ss << ", c_name: " << c_name;
  ss << '}';
  return ss.str();
}

AudioSendStream::Config::SendCodecSpec::SendCodecSpec(
    int payload_type,
    const SdpAudioFormat& format)
    : payload_type(payload_type), format(format) {}
AudioSendStream::Config::SendCodecSpec::~SendCodecSpec() = default;

std::string AudioSendStream::Config::SendCodecSpec::ToString() const {
  char buf[1024];
  rtc::SimpleStringBuilder ss(buf);
  ss << "{nack_enabled: " << (nack_enabled ? "true" : "false");
  ss << ", transport_cc_enabled: " << (transport_cc_enabled ? "true" : "false");
  ss << ", cng_payload_type: "
     << (cng_payload_type ? rtc::ToString(*cng_payload_type) : "<unset>");
  ss << ", red_payload_type: "
     << (red_payload_type ? rtc::ToString(*red_payload_type) : "<unset>");
  ss << ", payload_type: " << payload_type;
  ss << ", format: " << rtc::ToString(format);
  ss << '}';
  return ss.str();
}

bool AudioSendStream::Config::SendCodecSpec::operator==(
    const AudioSendStream::Config::SendCodecSpec& rhs) const {
  if (nack_enabled == rhs.nack_enabled &&
      transport_cc_enabled == rhs.transport_cc_enabled &&
      cng_payload_type == rhs.cng_payload_type &&
      payload_type == rhs.payload_type && format == rhs.format &&
      target_bitrate_bps == rhs.target_bitrate_bps) {
    return true;
  }
  return false;
}
}  // namespace webrtc
<commit_msg>red: fix SendCodecSpec == operator<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "call/audio_send_stream.h"

#include <stddef.h>

#include "rtc_base/string_encode.h"
#include "rtc_base/strings/audio_format_to_string.h"
#include "rtc_base/strings/string_builder.h"

namespace webrtc {

AudioSendStream::Stats::Stats() = default;
AudioSendStream::Stats::~Stats() = default;

AudioSendStream::Config::Config(Transport* send_transport)
    : send_transport(send_transport) {}

AudioSendStream::Config::~Config() = default;

std::string AudioSendStream::Config::ToString() const {
  char buf[1024];
  rtc::SimpleStringBuilder ss(buf);
  ss << "{rtp: " << rtp.ToString();
  ss << ", rtcp_report_interval_ms: " << rtcp_report_interval_ms;
  ss << ", send_transport: " << (send_transport ? "(Transport)" : "null");
  ss << ", min_bitrate_bps: " << min_bitrate_bps;
  ss << ", max_bitrate_bps: " << max_bitrate_bps;
  ss << ", send_codec_spec: "
     << (send_codec_spec ? send_codec_spec->ToString() : "<unset>");
  ss << '}';
  return ss.str();
}

AudioSendStream::Config::Rtp::Rtp() = default;

AudioSendStream::Config::Rtp::~Rtp() = default;

std::string AudioSendStream::Config::Rtp::ToString() const {
  char buf[1024];
  rtc::SimpleStringBuilder ss(buf);
  ss << "{ssrc: " << ssrc;
  ss << ", extmap-allow-mixed: " << (extmap_allow_mixed ? "true" : "false");
  ss << ", extensions: [";
  for (size_t i = 0; i < extensions.size(); ++i) {
    ss << extensions[i].ToString();
    if (i != extensions.size() - 1) {
      ss << ", ";
    }
  }
  ss << ']';
  ss << ", c_name: " << c_name;
  ss << '}';
  return ss.str();
}

AudioSendStream::Config::SendCodecSpec::SendCodecSpec(
    int payload_type,
    const SdpAudioFormat& format)
    : payload_type(payload_type), format(format) {}
AudioSendStream::Config::SendCodecSpec::~SendCodecSpec() = default;

std::string AudioSendStream::Config::SendCodecSpec::ToString() const {
  char buf[1024];
  rtc::SimpleStringBuilder ss(buf);
  ss << "{nack_enabled: " << (nack_enabled ? "true" : "false");
  ss << ", transport_cc_enabled: " << (transport_cc_enabled ? "true" : "false");
  ss << ", cng_payload_type: "
     << (cng_payload_type ? rtc::ToString(*cng_payload_type) : "<unset>");
  ss << ", red_payload_type: "
     << (red_payload_type ? rtc::ToString(*red_payload_type) : "<unset>");
  ss << ", payload_type: " << payload_type;
  ss << ", format: " << rtc::ToString(format);
  ss << '}';
  return ss.str();
}

bool AudioSendStream::Config::SendCodecSpec::operator==(
    const AudioSendStream::Config::SendCodecSpec& rhs) const {
  if (nack_enabled == rhs.nack_enabled &&
      transport_cc_enabled == rhs.transport_cc_enabled &&
      cng_payload_type == rhs.cng_payload_type &&
      red_payload_type == rhs.red_payload_type &&
      payload_type == rhs.payload_type && format == rhs.format &&
      target_bitrate_bps == rhs.target_bitrate_bps) {
    return true;
  }
  return false;
}
}  // namespace webrtc
<|endoftext|>


<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.

#include <array>

#include "sr300.h"
#include "ds5.h"
#include "backend.h"
#include "context.h"
#include "recorder.h"

#define constexpr_support 1

#ifdef _MSC_VER
#if (_MSC_VER <= 1800) // constexpr is not supported in MSVC2013
#pragma error( "Librealsense requires MSVC2015 or later to build" )
#undef constexpr_support
#define constexpr_support 0
#endif
#endif

#if (constexpr_support == 1)
template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
  return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

constexpr auto rs_api_version = concat("VERSION: ",RS_API_VERSION_STR);

#endif

namespace rsimpl
{
    context::context(backend_type type,
                     const char* filename,
                     const char* section,
                     rs_recording_mode mode)
    {
        switch(type)
        {
        case backend_type::standard:
            _backend = uvc::create_backend();
            break;
        case backend_type::record:
            _backend = std::make_shared<uvc::record_backend>(uvc::create_backend(), filename, section, mode);
            break;
        case backend_type::playback:
            _backend = std::make_shared<uvc::playback_backend>(filename, section);
            break;
        default: throw invalid_value_exception(to_string() << "Undefined backend type " << static_cast<int>(type));
        }
    }

    std::vector<std::shared_ptr<device_info>> context::query_devices() const
    {
        std::vector<std::shared_ptr<device_info>> list;

        auto uvc_devices = _backend->query_uvc_devices();
        auto usb_devices = _backend->query_usb_devices();
        auto hid_devices = _backend->query_hid_devices();

        auto sr300_devices = sr300_info::pick_sr300_devices(_backend, uvc_devices, usb_devices);
        std::copy(begin(sr300_devices), end(sr300_devices), std::back_inserter(list));

        auto ds5_devices = ds5_info::pick_ds5_devices(_backend, uvc_devices, usb_devices, hid_devices);
        std::copy(begin(ds5_devices), end(ds5_devices), std::back_inserter(list));

        auto recovery_devices = recovery_info::pick_recovery_devices(_backend, usb_devices);
        std::copy(begin(recovery_devices), end(recovery_devices), std::back_inserter(list));

        return list;
    }
}
<commit_msg>Fix MSVC error that will be raised for MSVC2013 or earlier<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2015 Intel Corporation. All Rights Reserved.
#ifdef _MSC_VER
#if (_MSC_VER <= 1800) // constexpr is not supported in MSVC2013
#error( "Librealsense requires MSVC2015 or later to build. Compilation will be aborted" )
#endif
#endif

#include <array>

#include "sr300.h"
#include "ds5.h"
#include "backend.h"
#include "context.h"
#include "recorder.h"

template<unsigned... Is> struct seq{};
template<unsigned N, unsigned... Is>
struct gen_seq : gen_seq<N-1, N-1, Is...>{};
template<unsigned... Is>
struct gen_seq<0, Is...> : seq<Is...>{};

template<unsigned N1, unsigned... I1, unsigned N2, unsigned... I2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2], seq<I1...>, seq<I2...>){
  return {{ a1[I1]..., a2[I2]... }};
}

template<unsigned N1, unsigned N2>
constexpr std::array<char const, N1+N2-1> concat(char const (&a1)[N1], char const (&a2)[N2]){
  return concat(a1, a2, gen_seq<N1-1>{}, gen_seq<N2>{});
}

// The string is used to retrieve the version embedded into .so file on Linux
constexpr auto rs_api_version = concat("VERSION: ",RS_API_VERSION_STR);

namespace rsimpl
{
    context::context(backend_type type,
                     const char* filename,
                     const char* section,
                     rs_recording_mode mode)
    {
        switch(type)
        {
        case backend_type::standard:
            _backend = uvc::create_backend();
            break;
        case backend_type::record:
            _backend = std::make_shared<uvc::record_backend>(uvc::create_backend(), filename, section, mode);
            break;
        case backend_type::playback:
            _backend = std::make_shared<uvc::playback_backend>(filename, section);
            break;
        default: throw invalid_value_exception(to_string() << "Undefined backend type " << static_cast<int>(type));
        }
    }

    std::vector<std::shared_ptr<device_info>> context::query_devices() const
    {
        std::vector<std::shared_ptr<device_info>> list;

        auto uvc_devices = _backend->query_uvc_devices();
        auto usb_devices = _backend->query_usb_devices();
        auto hid_devices = _backend->query_hid_devices();

        auto sr300_devices = sr300_info::pick_sr300_devices(_backend, uvc_devices, usb_devices);
        std::copy(begin(sr300_devices), end(sr300_devices), std::back_inserter(list));

        auto ds5_devices = ds5_info::pick_ds5_devices(_backend, uvc_devices, usb_devices, hid_devices);
        std::copy(begin(ds5_devices), end(ds5_devices), std::back_inserter(list));

        auto recovery_devices = recovery_info::pick_recovery_devices(_backend, usb_devices);
        std::copy(begin(recovery_devices), end(recovery_devices), std::back_inserter(list));

        return list;
    }
}
<|endoftext|>


<commit_before>/*
  Copyright (C) 2015 Guy Sherman, Shermann Innovations Limited

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

// C++ Standard Headers
#include <map>
#include <vector>

// C Standard Headers
#include <arpa/inet.h>

// Boost Headers

// 3rd Party Headers

// GTK Headers

#include <oca/OcaTypes.hxx>
#include "OcpMessageReader.hxx"
#include "Ocp1Header.hxx"
#include "Ocp1Response.hxx"
#include "Ocp1EventData.hxx"

namespace oca
{
	OcpMessageReader::OcpMessageReader()
	{

	}

	OcpMessageReader::~OcpMessageReader()
	{

	}

	const net::Ocp1Header OcpMessageReader::HeaderFromBuffer(boost::asio::const_buffer& buffer)
	{
		net::Ocp1Header header;

		HeaderFromBuffer(buffer, header);

		return header;
	}

	void OcpMessageReader::HeaderFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Header& header)
	{
		// Cast the buffer to the type we want, and dereference the pointer
		// so that we can read the data.
		header.protocolVersion = ntohs(*(boost::asio::buffer_cast<const uint16_t*>(buffer)));

		// Create a new buffer offset from the previous one so that we can
		// do the same as above but for the next field
		boost::asio::const_buffer ms = buffer+sizeof(uint16_t);
		header.messageSize = ntohl(*(boost::asio::buffer_cast<const uint32_t*>(ms)));

		boost::asio::const_buffer mt = ms+sizeof(uint32_t);
		header.messageType = (net::OcaMessageType) *(boost::asio::buffer_cast<const uint8_t*>(mt));

		boost::asio::const_buffer mc = mt+sizeof(uint8_t);
		header.messageCount = ntohs(*(boost::asio::buffer_cast<const uint16_t*>(mc)));
	}

	void OcpMessageReader::ParametersFromBuffer(boost::asio::const_buffer& buffer, size_t remainingCommandBytes, net::Ocp1Parameters& parameters)
	{
		parameters.parameterCount = *(boost::asio::buffer_cast<const uint8_t*>(buffer));

		size_t parameterBufferBytes = (remainingCommandBytes - sizeof(uint8_t));
		boost::asio::const_buffer paramBuffer = buffer+sizeof(uint8_t);
		//const uint8_t* params = boost::asio::buffer_cast<const uint8_t*>(paramBuffer);

		bufferToUint8Vector(paramBuffer, parameterBufferBytes, parameters.parameters);

		// assert (parameters.parameters.size() == 0);
		// // We ask the vector to grow in one hit, so we can memcpy straight after into it
		// // We reserve then resize, rather than just resizing, so that we only get one
		// // allocation, rather than log(n) allocations;
		// // We resize so that the size()  value is up to date, and so that the
		// // memory gets initialized to 0.
		// parameters.parameters.reserve(parameterBufferBytes);
		// parameters.parameters.resize(parameterBufferBytes, 0);
		// // TODO: security issue: we trust that the buffer actually has the right number of bytes #security
		// memcpy(&parameters.parameters[0], params, parameterBufferBytes);

	}

	void OcpMessageReader::bufferToUint8Vector(boost::asio::const_buffer& buffer, size_t numBytes, std::vector<OcaUint8>& vec)
	{
		assert (vec.size() == 0);

		const OcaUint8* bytes = boost::asio::buffer_cast<const OcaUint8*>(buffer);

		// We ask the vector to grow in one hit, so we can memcpy straight after into it
		// We reserve then resize, rather than just resizing, so that we only get one
		// allocation, rather than log(n) allocations;
		// We resize so that the size()  value is up to date, and so that the
		// memory gets initialized to 0.
		vec.reserve(numBytes);
		vec.resize(numBytes, 0);
		// TODO: security issue: we trust that the buffer actually has the right number of bytes #security
		memcpy(&vec[0], bytes, numBytes);
	}

	void OcpMessageReader::MethodIdFromBuffer(boost::asio::const_buffer& buffer, OcaMethodId& methodId)
	{
		methodId.treeLevel = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(buffer)));

		boost::asio::const_buffer mi = buffer + sizeof(OcaUint16);
		methodId.methodIndex = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(mi)));
	}

	void OcpMessageReader::CommandFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Command& cmd)
	{
		cmd.commandSize = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(buffer)));

		boost::asio::const_buffer handleBuf = buffer + sizeof(OcaUint32);
		cmd.handle = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(handleBuf)));

		boost::asio::const_buffer targetONoBuffer = handleBuf + sizeof(OcaUint32);
		cmd.targetONo = ntohl(*(boost::asio::buffer_cast<const OcaONo*>(targetONoBuffer)));

		boost::asio::const_buffer methodIdBuffer = targetONoBuffer + sizeof(OcaONo);
		MethodIdFromBuffer(methodIdBuffer, cmd.methodId);

		size_t remainingBytes = cmd.commandSize - (2*sizeof(OcaUint32) + sizeof(OcaONo) + sizeof(OcaMethodId));
		boost::asio::const_buffer parametersBuffer = methodIdBuffer + sizeof(OcaMethodId);

		ParametersFromBuffer(parametersBuffer, remainingBytes, cmd.parameters);
	}

	void OcpMessageReader::CommandListFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Header header, std::vector<net::Ocp1Command>& commands)
	{
		boost::asio::const_buffer message = buffer;

		for (uint16_t i = 0; i < header.messageCount; ++i )
		{
			net::Ocp1Command cmd;
			CommandFromBuffer(message, cmd);
			commands.push_back(cmd);
			message = message + cmd.commandSize;
		}
	}

	void OcpMessageReader::ResponseListFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Header header, std::vector<net::Ocp1Response>& responses)
	{
		boost::asio::const_buffer message = buffer;
		for (uint16_t i = 0; i < header.messageCount; ++i)
		{
			net::Ocp1Response resp;
			ResponseFromBuffer(message, resp);
			responses.push_back(resp);
			message = message + resp.responseSize;
		}
	}

	void OcpMessageReader::ResponseFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Response& resp)
	{
		resp.responseSize = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(buffer)));

		boost::asio::const_buffer handleBuf = buffer + sizeof(OcaUint32);
		resp.handle = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(handleBuf)));

		boost::asio::const_buffer statusCodeBuf = handleBuf + sizeof(OcaUint32);
		resp.statusCode = *(boost::asio::buffer_cast<const OcaStatus*>(statusCodeBuf));

		boost::asio::const_buffer paramsBuf = statusCodeBuf + sizeof(OcaStatus);
		size_t remainingBytes = resp.responseSize - (2*sizeof(OcaUint32) + sizeof(OcaStatus));
		ParametersFromBuffer(paramsBuf, remainingBytes, resp.parameters);
	}

	void OcpMessageReader::EventIdFromBuffer(boost::asio::const_buffer& buffer, OcaEventId& eventId)
	{
		eventId.treeLevel = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(buffer)));

		boost::asio::const_buffer indexBuf = buffer + sizeof(OcaUint16);
		eventId.eventIndex = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(indexBuf)));
	}

	void OcpMessageReader::EventFromBuffer(boost::asio::const_buffer& buffer, OcaEvent& event)
	{
		event.emitterONo = ntohl(*(boost::asio::buffer_cast<const OcaONo*>(buffer)));

		boost::asio::const_buffer idBuffer = buffer + sizeof(OcaONo);
		EventIdFromBuffer(idBuffer, event.eventId);
	}

	void OcpMessageReader::EventDataFromBuffer(boost::asio::const_buffer& buffer, size_t remainingBytes, oca::net::Ocp1EventData& data)
	{
		EventFromBuffer(buffer, data.event);

		boost::asio::const_buffer paramsBuffer = buffer + sizeof(OcaEvent);
		size_t parameterBytes = remainingBytes - sizeof(OcaEvent);
		bufferToUint8Vector(paramsBuffer, parameterBytes, data.eventParameters);

	}

	void OcpMessageReader::SyncValueReceived(uint8_t* bufferData,
		const boost::system::error_code& error,
		size_t bytesTransferred,
		boost::function<void(void)> getHeader )
	{
		if (error.value() != boost::system::errc::success)
		{
			// TODO: consider an exception here
			return;
		}

		if (bytesTransferred != 1)
		{
			// TODO: consider an exception here
			return;
		}

		// TODO: logging

		if (bufferData != 0)
		{
			if (bufferData[0] == 0x3B)
			{
				getHeader();
			}
		}
	}

	void OcpMessageReader::Ocp1HeaderReceived(uint8_t* bufferData,
		uint64_t connectionIdentifier,
		const boost::system::error_code& error,
		size_t bytesTransferred,
		boost::function<void(uint32_t)> getData)
	{
		boost::asio::const_buffer headerBuffer(bufferData, bytesTransferred);

		// By convetion we should be removing the per connection header object once we're done
		// so if this assert throws we've either forgotten, or we've got a concurrency
		// issue.
		ConnectionStateMap::iterator it = perConnectionState.find(connectionIdentifier);
		assert(it == perConnectionState.end());

		oca::net::Ocp1Header header = HeaderFromBuffer(headerBuffer);

		perConnectionState.insert(ConnectionStateMap::value_type(connectionIdentifier, header));

		// The messageSize property includes the header, but we've
		// already got it so we ask for fewer bytes.
		getData(header.messageSize - OCP1_HEADER_SIZE);

	}

	void OcpMessageReader::Ocp1DataReceived(uint8_t* bufferData,
		uint64_t connectionIdentifier,
		const boost::system::error_code& error,
		size_t bytesTransferred)
	{
		// Don't really have anything to do here yet...

		// ...but before we go, lets clean up
		ConnectionStateMap::iterator it = perConnectionState.find(connectionIdentifier);
		if (it != perConnectionState.end())
		{
			perConnectionState.erase(it);
		}
		return;
	}

}
<commit_msg>* Cleand up some code that had been commented out.<commit_after>/*
  Copyright (C) 2015 Guy Sherman, Shermann Innovations Limited

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

// C++ Standard Headers
#include <map>
#include <vector>

// C Standard Headers
#include <arpa/inet.h>

// Boost Headers

// 3rd Party Headers

// GTK Headers

#include <oca/OcaTypes.hxx>
#include "OcpMessageReader.hxx"
#include "Ocp1Header.hxx"
#include "Ocp1Response.hxx"
#include "Ocp1EventData.hxx"

namespace oca
{
	OcpMessageReader::OcpMessageReader()
	{

	}

	OcpMessageReader::~OcpMessageReader()
	{

	}

	const net::Ocp1Header OcpMessageReader::HeaderFromBuffer(boost::asio::const_buffer& buffer)
	{
		net::Ocp1Header header;

		HeaderFromBuffer(buffer, header);

		return header;
	}

	void OcpMessageReader::HeaderFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Header& header)
	{
		// Cast the buffer to the type we want, and dereference the pointer
		// so that we can read the data.
		header.protocolVersion = ntohs(*(boost::asio::buffer_cast<const uint16_t*>(buffer)));

		// Create a new buffer offset from the previous one so that we can
		// do the same as above but for the next field
		boost::asio::const_buffer ms = buffer+sizeof(uint16_t);
		header.messageSize = ntohl(*(boost::asio::buffer_cast<const uint32_t*>(ms)));

		boost::asio::const_buffer mt = ms+sizeof(uint32_t);
		header.messageType = (net::OcaMessageType) *(boost::asio::buffer_cast<const uint8_t*>(mt));

		boost::asio::const_buffer mc = mt+sizeof(uint8_t);
		header.messageCount = ntohs(*(boost::asio::buffer_cast<const uint16_t*>(mc)));
	}

	void OcpMessageReader::ParametersFromBuffer(boost::asio::const_buffer& buffer, size_t remainingCommandBytes, net::Ocp1Parameters& parameters)
	{
		parameters.parameterCount = *(boost::asio::buffer_cast<const uint8_t*>(buffer));

		size_t parameterBufferBytes = (remainingCommandBytes - sizeof(uint8_t));
		boost::asio::const_buffer paramBuffer = buffer+sizeof(uint8_t);
		//const uint8_t* params = boost::asio::buffer_cast<const uint8_t*>(paramBuffer);

		bufferToUint8Vector(paramBuffer, parameterBufferBytes, parameters.parameters);

	}

	void OcpMessageReader::bufferToUint8Vector(boost::asio::const_buffer& buffer, size_t numBytes, std::vector<OcaUint8>& vec)
	{
		assert (vec.size() == 0);

		const OcaUint8* bytes = boost::asio::buffer_cast<const OcaUint8*>(buffer);

		// We ask the vector to grow in one hit, so we can memcpy straight after into it
		// We reserve then resize, rather than just resizing, so that we only get one
		// allocation, rather than log(n) allocations;
		// We resize so that the size()  value is up to date, and so that the
		// memory gets initialized to 0.
		vec.reserve(numBytes);
		vec.resize(numBytes, 0);
		// TODO: security issue: we trust that the buffer actually has the right number of bytes #security
		memcpy(&vec[0], bytes, numBytes);
	}

	void OcpMessageReader::MethodIdFromBuffer(boost::asio::const_buffer& buffer, OcaMethodId& methodId)
	{
		methodId.treeLevel = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(buffer)));

		boost::asio::const_buffer mi = buffer + sizeof(OcaUint16);
		methodId.methodIndex = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(mi)));
	}

	void OcpMessageReader::CommandFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Command& cmd)
	{
		cmd.commandSize = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(buffer)));

		boost::asio::const_buffer handleBuf = buffer + sizeof(OcaUint32);
		cmd.handle = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(handleBuf)));

		boost::asio::const_buffer targetONoBuffer = handleBuf + sizeof(OcaUint32);
		cmd.targetONo = ntohl(*(boost::asio::buffer_cast<const OcaONo*>(targetONoBuffer)));

		boost::asio::const_buffer methodIdBuffer = targetONoBuffer + sizeof(OcaONo);
		MethodIdFromBuffer(methodIdBuffer, cmd.methodId);

		size_t remainingBytes = cmd.commandSize - (2*sizeof(OcaUint32) + sizeof(OcaONo) + sizeof(OcaMethodId));
		boost::asio::const_buffer parametersBuffer = methodIdBuffer + sizeof(OcaMethodId);

		ParametersFromBuffer(parametersBuffer, remainingBytes, cmd.parameters);
	}

	void OcpMessageReader::CommandListFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Header header, std::vector<net::Ocp1Command>& commands)
	{
		boost::asio::const_buffer message = buffer;

		for (uint16_t i = 0; i < header.messageCount; ++i )
		{
			net::Ocp1Command cmd;
			CommandFromBuffer(message, cmd);
			commands.push_back(cmd);
			message = message + cmd.commandSize;
		}
	}

	void OcpMessageReader::ResponseListFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Header header, std::vector<net::Ocp1Response>& responses)
	{
		boost::asio::const_buffer message = buffer;
		for (uint16_t i = 0; i < header.messageCount; ++i)
		{
			net::Ocp1Response resp;
			ResponseFromBuffer(message, resp);
			responses.push_back(resp);
			message = message + resp.responseSize;
		}
	}

	void OcpMessageReader::ResponseFromBuffer(boost::asio::const_buffer& buffer, net::Ocp1Response& resp)
	{
		resp.responseSize = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(buffer)));

		boost::asio::const_buffer handleBuf = buffer + sizeof(OcaUint32);
		resp.handle = ntohl(*(boost::asio::buffer_cast<const OcaUint32*>(handleBuf)));

		boost::asio::const_buffer statusCodeBuf = handleBuf + sizeof(OcaUint32);
		resp.statusCode = *(boost::asio::buffer_cast<const OcaStatus*>(statusCodeBuf));

		boost::asio::const_buffer paramsBuf = statusCodeBuf + sizeof(OcaStatus);
		size_t remainingBytes = resp.responseSize - (2*sizeof(OcaUint32) + sizeof(OcaStatus));
		ParametersFromBuffer(paramsBuf, remainingBytes, resp.parameters);
	}

	void OcpMessageReader::EventIdFromBuffer(boost::asio::const_buffer& buffer, OcaEventId& eventId)
	{
		eventId.treeLevel = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(buffer)));

		boost::asio::const_buffer indexBuf = buffer + sizeof(OcaUint16);
		eventId.eventIndex = ntohs(*(boost::asio::buffer_cast<const OcaUint16*>(indexBuf)));
	}

	void OcpMessageReader::EventFromBuffer(boost::asio::const_buffer& buffer, OcaEvent& event)
	{
		event.emitterONo = ntohl(*(boost::asio::buffer_cast<const OcaONo*>(buffer)));

		boost::asio::const_buffer idBuffer = buffer + sizeof(OcaONo);
		EventIdFromBuffer(idBuffer, event.eventId);
	}

	void OcpMessageReader::EventDataFromBuffer(boost::asio::const_buffer& buffer, size_t remainingBytes, oca::net::Ocp1EventData& data)
	{
		EventFromBuffer(buffer, data.event);

		boost::asio::const_buffer paramsBuffer = buffer + sizeof(OcaEvent);
		size_t parameterBytes = remainingBytes - sizeof(OcaEvent);
		bufferToUint8Vector(paramsBuffer, parameterBytes, data.eventParameters);

	}

	void OcpMessageReader::SyncValueReceived(uint8_t* bufferData,
		const boost::system::error_code& error,
		size_t bytesTransferred,
		boost::function<void(void)> getHeader )
	{
		if (error.value() != boost::system::errc::success)
		{
			// TODO: consider an exception here
			return;
		}

		if (bytesTransferred != 1)
		{
			// TODO: consider an exception here
			return;
		}

		// TODO: logging

		if (bufferData != 0)
		{
			if (bufferData[0] == 0x3B)
			{
				getHeader();
			}
		}
	}

	void OcpMessageReader::Ocp1HeaderReceived(uint8_t* bufferData,
		uint64_t connectionIdentifier,
		const boost::system::error_code& error,
		size_t bytesTransferred,
		boost::function<void(uint32_t)> getData)
	{
		boost::asio::const_buffer headerBuffer(bufferData, bytesTransferred);

		// By convetion we should be removing the per connection header object once we're done
		// so if this assert throws we've either forgotten, or we've got a concurrency
		// issue.
		ConnectionStateMap::iterator it = perConnectionState.find(connectionIdentifier);
		assert(it == perConnectionState.end());

		oca::net::Ocp1Header header = HeaderFromBuffer(headerBuffer);

		perConnectionState.insert(ConnectionStateMap::value_type(connectionIdentifier, header));

		// The messageSize property includes the header, but we've
		// already got it so we ask for fewer bytes.
		getData(header.messageSize - OCP1_HEADER_SIZE);

	}

	void OcpMessageReader::Ocp1DataReceived(uint8_t* bufferData,
		uint64_t connectionIdentifier,
		const boost::system::error_code& error,
		size_t bytesTransferred)
	{
		// Don't really have anything to do here yet...

		// ...but before we go, lets clean up
		ConnectionStateMap::iterator it = perConnectionState.find(connectionIdentifier);
		if (it != perConnectionState.end())
		{
			perConnectionState.erase(it);
		}
		return;
	}

}
<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "cvmfs_config.h"
#include "publish/settings.h"

#include <cstdlib>
#include <string>
#include <vector>

#include "options.h"
#include "publish/except.h"
#include "publish/repository.h"
#include "sanitizer.h"
#include "util/posix.h"
#include "util/string.h"

namespace publish {

void SettingsSpoolArea::UseSystemTempDir() {
  if (getenv("TMPDIR") != NULL)
    tmp_dir_ = getenv("TMPDIR");
  else
    tmp_dir_ = "/tmp";
}

void SettingsSpoolArea::SetSpoolArea(const std::string &path) {
  workspace_ = path;
  tmp_dir_ = workspace_() + "/tmp";
}

void SettingsSpoolArea::SetUnionMount(const std::string &path) {
  union_mnt_ = path;
}

void SettingsSpoolArea::SetRepairMode(const EUnionMountRepairMode val) {
  repair_mode_ = val;
}

//------------------------------------------------------------------------------

void SettingsTransaction::SetUnionFsType(const std::string &union_fs) {
  if (union_fs == "aufs") {
    union_fs_ = kUnionFsAufs;
  } else if ((union_fs == "overlay") || (union_fs == "overlayfs")) {
    union_fs_ = kUnionFsOverlay;
  } else if (union_fs == "tarball") {
    union_fs_ = kUnionFsTarball;
  } else {
    throw EPublish("unsupported union file system: " + union_fs);
  }
}

void SettingsTransaction::DetectUnionFsType() {
  // TODO(jblomer): shall we switch the order?
  if (DirectoryExists("/sys/fs/aufs")) {
    union_fs_ = kUnionFsAufs;
    return;
  }
  // TODO(jblomer): modprobe aufs, try again
  if (DirectoryExists("/sys/module/overlay")) {
    union_fs_ = kUnionFsOverlay;
    return;
  }
  // TODO(jblomer): modprobe overlay, try again
  throw EPublish("neither AUFS nor OverlayFS detected on the system");
}

bool SettingsTransaction::ValidateUnionFs() {
  // TODO(jblomer)
  return true;
}

void SettingsTransaction::SetTimeout(unsigned seconds) {
  timeout_s_ = seconds;
}

void SettingsTransaction::SetLeasePath(const std::string &path) {
  lease_path_ = path;
}

//------------------------------------------------------------------------------

std::string SettingsStorage::GetLocator() const {
  return std::string(upload::SpoolerDefinition::kDriverNames[type_]) +
    "," + tmp_dir_() +
    "," + endpoint_();
}

void SettingsStorage::MakeS3(
  const std::string &s3_config,
  const std::string &tmp_dir)
{
  type_ = upload::SpoolerDefinition::S3;
  tmp_dir_ = tmp_dir;
  endpoint_ = "cvmfs/" + fqrn_() + "@" + s3_config;
}

void SettingsStorage::MakeLocal(const std::string &path) {
  type_ = upload::SpoolerDefinition::Local;
  endpoint_ = path;
  tmp_dir_ = path + "/data/txn";
}

void SettingsStorage::MakeGateway(
  const std::string &host,
  unsigned int port,
  const std::string &tmp_dir)
{
  type_ = upload::SpoolerDefinition::Gateway;
  endpoint_ = "http://" + host + ":" + StringifyInt(port) + "/api/v1";
  tmp_dir_ = tmp_dir_;
}

void SettingsStorage::SetLocator(const std::string &locator) {
  std::vector<std::string> tokens = SplitString(locator, ',');
  if (tokens.size() != 3) {
    throw EPublish("malformed storage locator, expected format is "
                   "<type>,<temporary directory>,<endpoint>");
  }
  if (tokens[0] == "local") {
    type_ = upload::SpoolerDefinition::Local;
  } else if (tokens[0] == "S3") {
    type_ = upload::SpoolerDefinition::S3;
  } else if (tokens[0] == "gw") {
    type_ = upload::SpoolerDefinition::Gateway;
  } else {
    throw EPublish("unsupported storage type: " + tokens[0]);
  }
  tmp_dir_ = tokens[1];
  endpoint_ = tokens[2];
}

//------------------------------------------------------------------------------

void SettingsKeychain::SetKeychainDir(const std::string &keychain_dir) {
  keychain_dir_ = keychain_dir;
  master_private_key_path_ = keychain_dir + "/" + fqrn_() + ".masterkey";
  master_public_key_path_ = keychain_dir + "/" + fqrn_() + ".pub";
  private_key_path_ = keychain_dir + "/" + fqrn_() + ".key";
  certificate_path_ = keychain_dir + "/" + fqrn_() + ".crt";
  gw_key_path_ = keychain_dir + "/" + fqrn_() + ".gw";
}

bool SettingsKeychain::HasDanglingMasterKeys() const {
  return (FileExists(master_private_key_path_) &&
          !FileExists(master_public_key_path_)) ||
         (!FileExists(master_private_key_path_) &&
          FileExists(master_public_key_path_));
}

bool SettingsKeychain::HasMasterKeys() const {
  return FileExists(master_private_key_path_) &&
         FileExists(master_public_key_path_);
}

bool SettingsKeychain::HasDanglingRepositoryKeys() const {
  return (FileExists(private_key_path_) &&
          !FileExists(certificate_path_)) ||
         (!FileExists(private_key_path_) &&
          FileExists(certificate_path_));
}

bool SettingsKeychain::HasRepositoryKeys() const {
  return FileExists(private_key_path_) &&
         FileExists(certificate_path_);
}

bool SettingsKeychain::HasGatewayKey() const {
  return FileExists(gw_key_path_);
}

//------------------------------------------------------------------------------

SettingsRepository::SettingsRepository(
  const SettingsPublisher &settings_publisher)
  : fqrn_(settings_publisher.fqrn())
  , url_(settings_publisher.url())
  , tmp_dir_(settings_publisher.transaction().spool_area().tmp_dir())
  , keychain_(settings_publisher.fqrn())
{
  keychain_.SetKeychainDir(settings_publisher.keychain().keychain_dir());
}

void SettingsRepository::SetUrl(const std::string &url) {
  // TODO(jblomer): sanitiation, check availability
  url_ = url;
}

void SettingsRepository::SetTmpDir(const std::string &tmp_dir) {
  tmp_dir_ = tmp_dir;
}

//------------------------------------------------------------------------------

const unsigned SettingsPublisher::kDefaultWhitelistValidity = 30;

SettingsPublisher::SettingsPublisher(
  const SettingsRepository &settings_repository)
  : fqrn_(settings_repository.fqrn())
  , url_(settings_repository.url())
  , owner_uid_(0)
  , owner_gid_(0)
  , whitelist_validity_days_(kDefaultWhitelistValidity)
  , is_silent_(false)
  , is_managed_(false)
  , storage_(fqrn_)
  , transaction_(fqrn_)
  , keychain_(fqrn_)
{
  keychain_.SetKeychainDir(settings_repository.keychain().keychain_dir());
}

void SettingsPublisher::SetUrl(const std::string &url) {
  // TODO(jblomer): sanitiation, check availability
  url_ = url;
}

void SettingsPublisher::SetOwner(const std::string &user_name) {
  bool retval = GetUidOf(user_name, owner_uid_.GetPtr(), owner_gid_.GetPtr());
  if (!retval) {
    throw EPublish("unknown user name for repository owner");
  }
}

void SettingsPublisher::SetOwner(uid_t uid, gid_t gid) {
  owner_uid_ = uid;
  owner_gid_ = gid;
}

void SettingsPublisher::SetIsSilent(bool value) {
  is_silent_ = value;
}

void SettingsPublisher::SetIsManaged(bool value) {
  is_managed_ = value;
}

//------------------------------------------------------------------------------

SettingsBuilder::~SettingsBuilder() {
  delete options_mgr_;
}

std::string SettingsBuilder::GetSingleAlias() {
  std::vector<std::string> repositories = FindDirectories(config_path_);
  if (repositories.empty())
    throw EPublish("no repositories available in " + config_path_);
  if (repositories.size() > 1)
    throw EPublish("multiple repositories available in " + config_path_);
  return GetFileName(repositories[0]);
}

SettingsRepository SettingsBuilder::CreateSettingsRepository(
  const std::string &ident)
{
  if (HasPrefix(ident, "http://", true /* ignore case */) ||
      HasPrefix(ident, "https://", true /* ignore case */) ||
      HasPrefix(ident, "file://", true /* ignore case */))
  {
    std::string fqrn = Repository::GetFqrnFromUrl(ident);
    sanitizer::RepositorySanitizer sanitizer;
    if (!sanitizer.IsValid(fqrn)) {
      throw EPublish("malformed repository name: " + fqrn);
    }
    SettingsRepository settings(fqrn);
    settings.SetUrl(ident);
    return settings;
  }

  std::string alias = ident.empty() ? GetSingleAlias() : ident;
  std::string repo_path = config_path_ + "/" + alias;
  std::string server_path = repo_path + "/server.conf";
  std::string replica_path = repo_path + "/replica.conf";
  std::string fqrn = alias;

  delete options_mgr_;
  options_mgr_ = new BashOptionsManager();
  std::string arg;
  options_mgr_->set_taint_environment(false);
  options_mgr_->ParsePath(server_path, false /* external */);
  options_mgr_->ParsePath(replica_path, false /* external */);
  if (options_mgr_->GetValue("CVMFS_REPOSITORY_NAME", &arg))
    fqrn = arg;
  SettingsRepository settings(fqrn);

  if (options_mgr_->GetValue("CVMFS_PUBLIC_KEY", &arg))
    settings.GetKeychain()->SetKeychainDir(arg);
  if (options_mgr_->GetValue("CVMFS_STRATUM0", &arg))
    settings.SetUrl(arg);
  // For a replica, the stratum 1 url is the "local" location, hence it takes
  // precedence over the stratum 0 url
  if (options_mgr_->GetValue("CVMFS_STRATUM1", &arg))
    settings.SetUrl(arg);
  if (options_mgr_->GetValue("CVMFS_SPOOL_DIR", &arg))
    settings.SetTmpDir(arg + "/tmp");

  return settings;
}

SettingsPublisher SettingsBuilder::CreateSettingsPublisher(
  const std::string &ident, bool needs_managed)
{
  SettingsRepository settings_repository = CreateSettingsRepository(ident);
  if (needs_managed && !IsManagedRepository())
    throw EPublish("remote repositories are not supported in this context");

  if (options_mgr_->GetValueOrDie("CVMFS_REPOSITORY_TYPE") != "stratum0")
    throw EPublish("Not a stratum 0 repository");

  SettingsPublisher settings_publisher(settings_repository);
  settings_publisher.SetIsManaged(IsManagedRepository());
  settings_publisher.SetOwner(options_mgr_->GetValueOrDie("CVMFS_USER"));
  settings_publisher.GetStorage()->SetLocator(
    options_mgr_->GetValueOrDie("CVMFS_UPSTREAM_STORAGE"));

  std::string arg;
  if (options_mgr_->GetValue("CVMFS_AUTO_REPAIR_MOUNTPOINT", &arg)) {
    if (!options_mgr_->IsOn(arg)) {
      settings_publisher.GetTransaction()->GetSpoolArea()->SetRepairMode(
        kUnionMountRepairNever);
    }
  }

  // TODO(jblomer): process other parameters

  return settings_publisher;
}

}  // namespace publish
<commit_msg>Manage case when we don't find the server.conf configuratio file.<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "cvmfs_config.h"
#include "publish/settings.h"

#include <cstdlib>
#include <string>
#include <vector>

#include "options.h"
#include "publish/except.h"
#include "publish/repository.h"
#include "sanitizer.h"
#include "util/posix.h"
#include "util/string.h"

namespace publish {

void SettingsSpoolArea::UseSystemTempDir() {
  if (getenv("TMPDIR") != NULL)
    tmp_dir_ = getenv("TMPDIR");
  else
    tmp_dir_ = "/tmp";
}

void SettingsSpoolArea::SetSpoolArea(const std::string &path) {
  workspace_ = path;
  tmp_dir_ = workspace_() + "/tmp";
}

void SettingsSpoolArea::SetUnionMount(const std::string &path) {
  union_mnt_ = path;
}

void SettingsSpoolArea::SetRepairMode(const EUnionMountRepairMode val) {
  repair_mode_ = val;
}

//------------------------------------------------------------------------------

void SettingsTransaction::SetUnionFsType(const std::string &union_fs) {
  if (union_fs == "aufs") {
    union_fs_ = kUnionFsAufs;
  } else if ((union_fs == "overlay") || (union_fs == "overlayfs")) {
    union_fs_ = kUnionFsOverlay;
  } else if (union_fs == "tarball") {
    union_fs_ = kUnionFsTarball;
  } else {
    throw EPublish("unsupported union file system: " + union_fs);
  }
}

void SettingsTransaction::DetectUnionFsType() {
  // TODO(jblomer): shall we switch the order?
  if (DirectoryExists("/sys/fs/aufs")) {
    union_fs_ = kUnionFsAufs;
    return;
  }
  // TODO(jblomer): modprobe aufs, try again
  if (DirectoryExists("/sys/module/overlay")) {
    union_fs_ = kUnionFsOverlay;
    return;
  }
  // TODO(jblomer): modprobe overlay, try again
  throw EPublish("neither AUFS nor OverlayFS detected on the system");
}

bool SettingsTransaction::ValidateUnionFs() {
  // TODO(jblomer)
  return true;
}

void SettingsTransaction::SetTimeout(unsigned seconds) {
  timeout_s_ = seconds;
}

void SettingsTransaction::SetLeasePath(const std::string &path) {
  lease_path_ = path;
}

//------------------------------------------------------------------------------

std::string SettingsStorage::GetLocator() const {
  return std::string(upload::SpoolerDefinition::kDriverNames[type_]) +
    "," + tmp_dir_() +
    "," + endpoint_();
}

void SettingsStorage::MakeS3(
  const std::string &s3_config,
  const std::string &tmp_dir)
{
  type_ = upload::SpoolerDefinition::S3;
  tmp_dir_ = tmp_dir;
  endpoint_ = "cvmfs/" + fqrn_() + "@" + s3_config;
}

void SettingsStorage::MakeLocal(const std::string &path) {
  type_ = upload::SpoolerDefinition::Local;
  endpoint_ = path;
  tmp_dir_ = path + "/data/txn";
}

void SettingsStorage::MakeGateway(
  const std::string &host,
  unsigned int port,
  const std::string &tmp_dir)
{
  type_ = upload::SpoolerDefinition::Gateway;
  endpoint_ = "http://" + host + ":" + StringifyInt(port) + "/api/v1";
  tmp_dir_ = tmp_dir_;
}

void SettingsStorage::SetLocator(const std::string &locator) {
  std::vector<std::string> tokens = SplitString(locator, ',');
  if (tokens.size() != 3) {
    throw EPublish("malformed storage locator, expected format is "
                   "<type>,<temporary directory>,<endpoint>");
  }
  if (tokens[0] == "local") {
    type_ = upload::SpoolerDefinition::Local;
  } else if (tokens[0] == "S3") {
    type_ = upload::SpoolerDefinition::S3;
  } else if (tokens[0] == "gw") {
    type_ = upload::SpoolerDefinition::Gateway;
  } else {
    throw EPublish("unsupported storage type: " + tokens[0]);
  }
  tmp_dir_ = tokens[1];
  endpoint_ = tokens[2];
}

//------------------------------------------------------------------------------

void SettingsKeychain::SetKeychainDir(const std::string &keychain_dir) {
  keychain_dir_ = keychain_dir;
  master_private_key_path_ = keychain_dir + "/" + fqrn_() + ".masterkey";
  master_public_key_path_ = keychain_dir + "/" + fqrn_() + ".pub";
  private_key_path_ = keychain_dir + "/" + fqrn_() + ".key";
  certificate_path_ = keychain_dir + "/" + fqrn_() + ".crt";
  gw_key_path_ = keychain_dir + "/" + fqrn_() + ".gw";
}

bool SettingsKeychain::HasDanglingMasterKeys() const {
  return (FileExists(master_private_key_path_) &&
          !FileExists(master_public_key_path_)) ||
         (!FileExists(master_private_key_path_) &&
          FileExists(master_public_key_path_));
}

bool SettingsKeychain::HasMasterKeys() const {
  return FileExists(master_private_key_path_) &&
         FileExists(master_public_key_path_);
}

bool SettingsKeychain::HasDanglingRepositoryKeys() const {
  return (FileExists(private_key_path_) &&
          !FileExists(certificate_path_)) ||
         (!FileExists(private_key_path_) &&
          FileExists(certificate_path_));
}

bool SettingsKeychain::HasRepositoryKeys() const {
  return FileExists(private_key_path_) &&
         FileExists(certificate_path_);
}

bool SettingsKeychain::HasGatewayKey() const {
  return FileExists(gw_key_path_);
}

//------------------------------------------------------------------------------

SettingsRepository::SettingsRepository(
  const SettingsPublisher &settings_publisher)
  : fqrn_(settings_publisher.fqrn())
  , url_(settings_publisher.url())
  , tmp_dir_(settings_publisher.transaction().spool_area().tmp_dir())
  , keychain_(settings_publisher.fqrn())
{
  keychain_.SetKeychainDir(settings_publisher.keychain().keychain_dir());
}

void SettingsRepository::SetUrl(const std::string &url) {
  // TODO(jblomer): sanitiation, check availability
  url_ = url;
}

void SettingsRepository::SetTmpDir(const std::string &tmp_dir) {
  tmp_dir_ = tmp_dir;
}

//------------------------------------------------------------------------------

const unsigned SettingsPublisher::kDefaultWhitelistValidity = 30;

SettingsPublisher::SettingsPublisher(
  const SettingsRepository &settings_repository)
  : fqrn_(settings_repository.fqrn())
  , url_(settings_repository.url())
  , owner_uid_(0)
  , owner_gid_(0)
  , whitelist_validity_days_(kDefaultWhitelistValidity)
  , is_silent_(false)
  , is_managed_(false)
  , storage_(fqrn_)
  , transaction_(fqrn_)
  , keychain_(fqrn_)
{
  keychain_.SetKeychainDir(settings_repository.keychain().keychain_dir());
}

void SettingsPublisher::SetUrl(const std::string &url) {
  // TODO(jblomer): sanitiation, check availability
  url_ = url;
}

void SettingsPublisher::SetOwner(const std::string &user_name) {
  bool retval = GetUidOf(user_name, owner_uid_.GetPtr(), owner_gid_.GetPtr());
  if (!retval) {
    throw EPublish("unknown user name for repository owner");
  }
}

void SettingsPublisher::SetOwner(uid_t uid, gid_t gid) {
  owner_uid_ = uid;
  owner_gid_ = gid;
}

void SettingsPublisher::SetIsSilent(bool value) {
  is_silent_ = value;
}

void SettingsPublisher::SetIsManaged(bool value) {
  is_managed_ = value;
}

//------------------------------------------------------------------------------

SettingsBuilder::~SettingsBuilder() {
  delete options_mgr_;
}

std::string SettingsBuilder::GetSingleAlias() {
  std::vector<std::string> repositories = FindDirectories(config_path_);
  if (repositories.empty())
    throw EPublish("no repositories available in " + config_path_);
  if (repositories.size() > 1)
    throw EPublish("multiple repositories available in " + config_path_);
  return GetFileName(repositories[0]);
}

SettingsRepository SettingsBuilder::CreateSettingsRepository(
  const std::string &ident)
{
  if (HasPrefix(ident, "http://", true /* ignore case */) ||
      HasPrefix(ident, "https://", true /* ignore case */) ||
      HasPrefix(ident, "file://", true /* ignore case */))
  {
    std::string fqrn = Repository::GetFqrnFromUrl(ident);
    sanitizer::RepositorySanitizer sanitizer;
    if (!sanitizer.IsValid(fqrn)) {
      throw EPublish("malformed repository name: " + fqrn);
    }
    SettingsRepository settings(fqrn);
    settings.SetUrl(ident);
    return settings;
  }

  std::string alias = ident.empty() ? GetSingleAlias() : ident;
  std::string repo_path = config_path_ + "/" + alias;
  std::string server_path = repo_path + "/server.conf";
  std::string replica_path = repo_path + "/replica.conf";
  std::string fqrn = alias;

  delete options_mgr_;
  options_mgr_ = new BashOptionsManager();
  std::string arg;
  options_mgr_->set_taint_environment(false);
  options_mgr_->ParsePath(server_path, false /* external */);
  options_mgr_->ParsePath(replica_path, false /* external */);
  if (options_mgr_->GetValue("CVMFS_REPOSITORY_NAME", &arg))
    fqrn = arg;
  SettingsRepository settings(fqrn);

  if (options_mgr_->GetValue("CVMFS_PUBLIC_KEY", &arg))
    settings.GetKeychain()->SetKeychainDir(arg);
  if (options_mgr_->GetValue("CVMFS_STRATUM0", &arg))
    settings.SetUrl(arg);
  // For a replica, the stratum 1 url is the "local" location, hence it takes
  // precedence over the stratum 0 url
  if (options_mgr_->GetValue("CVMFS_STRATUM1", &arg))
    settings.SetUrl(arg);
  if (options_mgr_->GetValue("CVMFS_SPOOL_DIR", &arg))
    settings.SetTmpDir(arg + "/tmp");

  return settings;
}

SettingsPublisher SettingsBuilder::CreateSettingsPublisher(
  const std::string &ident, bool needs_managed)
{
  // we are creating a publisher, it need to have the `server.conf` file
  // present, otherwise something is wrong and we should exit early
  const std::string alias(ident.empty() ? GetSingleAlias() : ident);
  const std::string server_path = config_path_ + "/" + alias + "/server.conf";

  if (FileExists(server_path) == false)
    throw EPublish(
        "Unable to find the configuration file `server.conf` for the cvmfs "
        "publisher");

  SettingsRepository settings_repository = CreateSettingsRepository(alias);
  if (needs_managed && !IsManagedRepository())
    throw EPublish("remote repositories are not supported in this context");

  if (options_mgr_->GetValueOrDie("CVMFS_REPOSITORY_TYPE") != "stratum0")
    throw EPublish("Not a stratum 0 repository");

  SettingsPublisher settings_publisher(settings_repository);
  settings_publisher.SetIsManaged(IsManagedRepository());
  settings_publisher.SetOwner(options_mgr_->GetValueOrDie("CVMFS_USER"));
  settings_publisher.GetStorage()->SetLocator(
    options_mgr_->GetValueOrDie("CVMFS_UPSTREAM_STORAGE"));

  std::string arg;
  if (options_mgr_->GetValue("CVMFS_AUTO_REPAIR_MOUNTPOINT", &arg)) {
    if (!options_mgr_->IsOn(arg)) {
      settings_publisher.GetTransaction()->GetSpoolArea()->SetRepairMode(
        kUnionMountRepairNever);
    }
  }

  // TODO(jblomer): process other parameters

  return settings_publisher;
}

}  // namespace publish
<|endoftext|>