<commit_before>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "common/convert_UTF.h"
#include "processor/scoped_ptr.h"
#include "common/string_conversion.h"

using std::string;
using std::vector;

namespace google_airbag {

void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
  size_t source_length = strlen(in);
  const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
  const UTF8 *source_end_ptr = source_ptr + source_length;
  // Erase the contents and zero fill to the expected size
  out->empty();
  out->insert(out->begin(), source_length, 0);
  u_int16_t *target_ptr = &(*out)[0];
  u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
  ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
                                               &target_ptr, target_end_ptr,
                                               strictConversion);

  // Resize to be the size of the # of converted characters + NULL
  out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}

int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]) {
  const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
  const UTF8 *source_end_ptr = source_ptr + sizeof(char);
  u_int16_t *target_ptr = out;
  u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
  out[0] = out[1] = 0;

  // Process one character at a time
  while (1) {
    ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
                                                 &target_ptr, target_end_ptr,
                                                 strictConversion);

    if (result == conversionOK)
      return source_ptr - reinterpret_cast<const UTF8 *>(in);

    // Add another character to the input stream and try again
    source_ptr = reinterpret_cast<const UTF8 *>(in);
    ++source_end_ptr;

    if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length)
      break;
  }

  return 0;
}

void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out) {
  size_t source_length = wcslen(in);
  const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
  const UTF32 *source_end_ptr = source_ptr + source_length;
  // Erase the contents and zero fill to the expected size
  out->empty();
  out->insert(out->begin(), source_length, 0);
  u_int16_t *target_ptr = &(*out)[0];
  u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
  ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
                                                &target_ptr, target_end_ptr,
                                                strictConversion);

  // Resize to be the size of the # of converted characters + NULL
  out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}

void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]) {
  const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
  const UTF32 *source_end_ptr = source_ptr + sizeof(wchar_t);
  u_int16_t *target_ptr = out;
  u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
  out[0] = out[1] = 0;
  ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
                                                &target_ptr, target_end_ptr,
                                                strictConversion);

  if (result != conversionOK) {
    out[0] = out[1] = 0;
  }
}

static inline u_int16_t Swap(u_int16_t value) {
  return (value >> 8) | (value << 8);
}

string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap) {
  const UTF16 *source_ptr = &in[0];
  scoped_ptr<u_int16_t> source_buffer;

  // If we're to swap, we need to make a local copy and swap each byte pair
  if (swap) {
    int idx = 0;
    source_buffer.reset(new u_int16_t[in.size()]);
    UTF16 *source_buffer_ptr = source_buffer.get();
    for (vector<u_int16_t>::const_iterator it = in.begin();
         it != in.end(); ++it, ++idx)
      source_buffer_ptr[idx] = Swap(*it);

    source_ptr = source_buffer.get();
  }

  // The maximum expansion would be 4x the size of the input string.
  const UTF16 *source_end_ptr = source_ptr + in.size();
  int target_capacity = in.size() * 4;
  scoped_array<UTF8> target_buffer(new UTF8[target_capacity]);
  UTF8 *target_ptr = target_buffer.get();
  UTF8 *target_end_ptr = target_ptr + target_capacity;
  ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
                                               &target_ptr, target_end_ptr,
                                               strictConversion);

  if (result == conversionOK) {
    const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get());
    string result(targetPtr);
    return result;
  }

  return "";
}

}  // namespace google_airbag
<commit_msg>Fix UTF32ToUTF16Char() conversion.  Fixes issue #99. Reviewed by bryner.<commit_after>// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "common/convert_UTF.h"
#include "processor/scoped_ptr.h"
#include "common/string_conversion.h"

using std::string;
using std::vector;

namespace google_airbag {

void UTF8ToUTF16(const char *in, vector<u_int16_t> *out) {
  size_t source_length = strlen(in);
  const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
  const UTF8 *source_end_ptr = source_ptr + source_length;
  // Erase the contents and zero fill to the expected size
  out->empty();
  out->insert(out->begin(), source_length, 0);
  u_int16_t *target_ptr = &(*out)[0];
  u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
  ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
                                               &target_ptr, target_end_ptr,
                                               strictConversion);

  // Resize to be the size of the # of converted characters + NULL
  out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}

int UTF8ToUTF16Char(const char *in, int in_length, u_int16_t out[2]) {
  const UTF8 *source_ptr = reinterpret_cast<const UTF8 *>(in);
  const UTF8 *source_end_ptr = source_ptr + sizeof(char);
  u_int16_t *target_ptr = out;
  u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
  out[0] = out[1] = 0;

  // Process one character at a time
  while (1) {
    ConversionResult result = ConvertUTF8toUTF16(&source_ptr, source_end_ptr,
                                                 &target_ptr, target_end_ptr,
                                                 strictConversion);

    if (result == conversionOK)
      return source_ptr - reinterpret_cast<const UTF8 *>(in);

    // Add another character to the input stream and try again
    source_ptr = reinterpret_cast<const UTF8 *>(in);
    ++source_end_ptr;

    if (source_end_ptr > reinterpret_cast<const UTF8 *>(in) + in_length)
      break;
  }

  return 0;
}

void UTF32ToUTF16(const wchar_t *in, vector<u_int16_t> *out) {
  size_t source_length = wcslen(in);
  const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(in);
  const UTF32 *source_end_ptr = source_ptr + source_length;
  // Erase the contents and zero fill to the expected size
  out->empty();
  out->insert(out->begin(), source_length, 0);
  u_int16_t *target_ptr = &(*out)[0];
  u_int16_t *target_end_ptr = target_ptr + out->capacity() * sizeof(u_int16_t);
  ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
                                                &target_ptr, target_end_ptr,
                                                strictConversion);

  // Resize to be the size of the # of converted characters + NULL
  out->resize(result == conversionOK ? target_ptr - &(*out)[0] + 1: 0);
}

void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]) {
  const UTF32 *source_ptr = reinterpret_cast<const UTF32 *>(&in);
  const UTF32 *source_end_ptr = source_ptr + 1;
  u_int16_t *target_ptr = out;
  u_int16_t *target_end_ptr = target_ptr + 2 * sizeof(u_int16_t);
  out[0] = out[1] = 0;
  ConversionResult result = ConvertUTF32toUTF16(&source_ptr, source_end_ptr,
                                                &target_ptr, target_end_ptr,
                                                strictConversion);

  if (result != conversionOK) {
    out[0] = out[1] = 0;
  }
}

static inline u_int16_t Swap(u_int16_t value) {
  return (value >> 8) | (value << 8);
}

string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap) {
  const UTF16 *source_ptr = &in[0];
  scoped_ptr<u_int16_t> source_buffer;

  // If we're to swap, we need to make a local copy and swap each byte pair
  if (swap) {
    int idx = 0;
    source_buffer.reset(new u_int16_t[in.size()]);
    UTF16 *source_buffer_ptr = source_buffer.get();
    for (vector<u_int16_t>::const_iterator it = in.begin();
         it != in.end(); ++it, ++idx)
      source_buffer_ptr[idx] = Swap(*it);

    source_ptr = source_buffer.get();
  }

  // The maximum expansion would be 4x the size of the input string.
  const UTF16 *source_end_ptr = source_ptr + in.size();
  int target_capacity = in.size() * 4;
  scoped_array<UTF8> target_buffer(new UTF8[target_capacity]);
  UTF8 *target_ptr = target_buffer.get();
  UTF8 *target_end_ptr = target_ptr + target_capacity;
  ConversionResult result = ConvertUTF16toUTF8(&source_ptr, source_end_ptr,
                                               &target_ptr, target_end_ptr,
                                               strictConversion);

  if (result == conversionOK) {
    const char *targetPtr = reinterpret_cast<const char *>(target_buffer.get());
    string result(targetPtr);
    return result;
  }

  return "";
}

}  // namespace google_airbag
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 Tmplt <tmplt@dragons.rocks>
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <utility>

#include "components/command_line.hpp"
#include "fmt/format.h"

/* Create the instance */
cliparser::make_type cliparser::make(string &&progname, const options &&opts)
{
    return std::make_unique<cliparser>(
        "Usage: " + progname + " OPTION...", std::forward<decltype(opts)>(opts)
    );
}

/* Construct the parser. */
cliparser::parser(string &&synopsis, const options &&opts)
    : synopsis_(std::forward<decltype(synopsis)>(synopsis)), valid_opts_(std::forward<decltype(opts)>(opts))
{
}

/* Print program usage message. */
void cliparser::usage() const
{
    std::cout << synopsis_ << "\n\n";

    size_t maxlen = 0;

    /*
     * Get the length of the longest string in the flag column
     * which is used to align the description fields.
     */
    for (const auto &opt : valid_opts_) {
        size_t len = opt.flag_long.length() + opt.flag.length() + 4;
        maxlen = std::max(len, maxlen);
    }

    /*
     * Print each option, its description and token and possible
     * values for said token (if any).
     */
    for (auto &opt : valid_opts_) {
        /* Padding between flags and description. */
        size_t pad = maxlen - opt.flag_long.length() - opt.token.length();

        fmt::print("  {}, {}", opt.flag, opt.flag_long);

        if (!opt.token.empty()) {
            std::cout << '=' << opt.token;
            pad--;
        }

        /*
         * Output the list with accepted values.
         * This line is printed below the description.
         */
        if (!opt.values.empty()) {
            std::cout << std::setw(pad + opt.desc.length())
                      << opt.desc << '\n';

            pad = pad + opt.flag_long.length() + opt.token.length() + 7;

            std::cout << string(pad, ' ') << opt.token << " is one of: ";
            for (auto &v : opt.values)
                std::cout << v << (v != opt.values.back() ? ", " : "");
        } else {
            std::cout << std::setw(pad + opt.desc.length()) << opt.desc;
        }

        std::cout << std::endl;
    }
}

/* Check if the passed option was provided. */
bool cliparser::has(const string &option) const
{
    return passed_opts_.find(option) != passed_opts_.end();
}

/* Gets the value for a given option. */
string cliparser::get(string opt) const
{
    if (has(std::forward<string>(opt)))
        return passed_opts_.find(opt)->second;

    return "";
}

/* Compare option value with given string. */
bool cliparser::compare(string opt, const string_view &val) const
{
    return get(std::move(opt)) == val;
}

/* Compare option with its short version. */
auto cliparser::is_short(const string_view &option, const string_view &opt_short) const
{
    return option.compare(0, opt_short.length(), opt_short) == 0;
}

/* Compare option with its long version */
auto cliparser::is_long(const string_view &option, const string_view &opt_long) const
{
    return option.compare(0, opt_long.length(), opt_long) == 0;
}

/* Compare with both versions. */
auto cliparser::is(const string_view &option, string opt_short, string opt_long) const
{
    return is_short(option, std::move(opt_short)) || is_long(option, std::move(opt_long));
}

/* Process argument vector. */
void cliparser::process_arguments(const vector<string> &args)
{
    for (size_t i = 0; i < args.size(); i++) {
        const string_view &arg = args[i];
        const string_view &next_arg = args.size() > i + 1 ? args[i + 1] : "";

        parse(arg, next_arg);
    }
}

/* Parse option value. */
auto cliparser::parse_value(string input, const string_view &input_next, choices values) const
{
    string opt = std::move(input);
    size_t pos;
    string_view value;

    if (input_next.empty() && opt.compare(0, 2, "--") != 0)
        throw value_error("Missing value for " + string(opt.data()));
    else if ((pos = opt.find('=')) == string_view::npos && opt.compare(0, 2, "--") == 0)
        throw value_error("Missing value for " + string(opt.data()));
    else if (pos == string::npos && !input_next.empty())
        value = input_next;
    else {
        value = opt.substr(pos + 1);
        opt = opt.substr(0, pos);
    }

    if (!values.empty() && std::find(values.begin(), values.end(), value) == values.end())
        throw value_error(
            "Invalid value '" + string(value.data()) + "' for argument " + string(opt.data())
        );

    return value;
}

/* Parse and validate passed arguments and flags. */
void cliparser::parse(const string_view &input, const string_view &input_next)
{
    if (skipnext_) {
        skipnext_ = false;

        if (!input_next.empty())
            return;
    }

    for (auto &&opt : valid_opts_) {
        if (is(input, opt.flag, opt.flag_long)) {
            if (opt.token.empty()) {
                passed_opts_.insert(std::make_pair(opt.flag_long.substr(2), ""));
            } else {
                auto value = parse_value(input.data(), input_next, opt.values);
                skipnext_ = (value == input_next);
                passed_opts_.insert(make_pair(opt.flag_long.substr(2), value));
            }

            return;
        }
    }

    if (input.compare(0, 1, "-") == 0)
        throw argument_error("Unrecognized option " + string(input.data()));
}
<commit_msg>use const is able<commit_after>/*
 * Copyright (C) 2017 Tmplt <tmplt@dragons.rocks>
 *
 * 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 3 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, see <http://www.gnu.org/licenses/>.
 */

#include <iostream>
#include <algorithm>
#include <iomanip>
#include <utility>

#include "components/command_line.hpp"
#include "fmt/format.h"

/* Create the instance */
cliparser::make_type cliparser::make(string &&progname, const options &&opts)
{
    return std::make_unique<cliparser>(
        "Usage: " + progname + " OPTION...", std::forward<decltype(opts)>(opts)
    );
}

/* Construct the parser. */
cliparser::parser(string &&synopsis, const options &&opts)
    : synopsis_(std::forward<decltype(synopsis)>(synopsis)), valid_opts_(std::forward<decltype(opts)>(opts))
{
}

/* Print program usage message. */
void cliparser::usage() const
{
    std::cout << synopsis_ << "\n\n";

    size_t maxlen = 0;

    /*
     * Get the length of the longest string in the flag column
     * which is used to align the description fields.
     */
    for (const auto &opt : valid_opts_) {
        size_t len = opt.flag_long.length() + opt.flag.length() + 4;
        maxlen = std::max(len, maxlen);
    }

    /*
     * Print each option, its description and token and possible
     * values for said token (if any).
     */
    for (const auto &opt : valid_opts_) {
        /* Padding between flags and description. */
        size_t pad = maxlen - opt.flag_long.length() - opt.token.length();

        fmt::print("  {}, {}", opt.flag, opt.flag_long);

        if (!opt.token.empty()) {
            std::cout << '=' << opt.token;
            pad--;
        }

        /*
         * Output the list with accepted values.
         * This line is printed below the description.
         */
        if (!opt.values.empty()) {
            std::cout << std::setw(pad + opt.desc.length())
                      << opt.desc << '\n';

            pad = pad + opt.flag_long.length() + opt.token.length() + 7;

            std::cout << string(pad, ' ') << opt.token << " is one of: ";
            for (auto &v : opt.values)
                std::cout << v << (v != opt.values.back() ? ", " : "");
        } else {
            std::cout << std::setw(pad + opt.desc.length()) << opt.desc;
        }

        std::cout << std::endl;
    }
}

/* Check if the passed option was provided. */
bool cliparser::has(const string &option) const
{
    return passed_opts_.find(option) != passed_opts_.end();
}

/* Gets the value for a given option. */
string cliparser::get(string opt) const
{
    if (has(std::forward<string>(opt)))
        return passed_opts_.find(opt)->second;

    return "";
}

/* Compare option value with given string. */
bool cliparser::compare(string opt, const string_view &val) const
{
    return get(std::move(opt)) == val;
}

/* Compare option with its short version. */
auto cliparser::is_short(const string_view &option, const string_view &opt_short) const
{
    return option.compare(0, opt_short.length(), opt_short) == 0;
}

/* Compare option with its long version */
auto cliparser::is_long(const string_view &option, const string_view &opt_long) const
{
    return option.compare(0, opt_long.length(), opt_long) == 0;
}

/* Compare with both versions. */
auto cliparser::is(const string_view &option, string opt_short, string opt_long) const
{
    return is_short(option, std::move(opt_short)) || is_long(option, std::move(opt_long));
}

/* Process argument vector. */
void cliparser::process_arguments(const vector<string> &args)
{
    for (size_t i = 0; i < args.size(); i++) {
        const string_view &arg = args[i];
        const string_view &next_arg = args.size() > i + 1 ? args[i + 1] : "";

        parse(arg, next_arg);
    }
}

/* Parse option value. */
auto cliparser::parse_value(string input, const string_view &input_next, choices values) const
{
    string opt = std::move(input);
    size_t pos;
    string_view value;

    if (input_next.empty() && opt.compare(0, 2, "--") != 0)
        throw value_error("Missing value for " + string(opt.data()));
    else if ((pos = opt.find('=')) == string_view::npos && opt.compare(0, 2, "--") == 0)
        throw value_error("Missing value for " + string(opt.data()));
    else if (pos == string::npos && !input_next.empty())
        value = input_next;
    else {
        value = opt.substr(pos + 1);
        opt = opt.substr(0, pos);
    }

    if (!values.empty() && std::find(values.begin(), values.end(), value) == values.end())
        throw value_error(
            "Invalid value '" + string(value.data()) + "' for argument " + string(opt.data())
        );

    return value;
}

/* Parse and validate passed arguments and flags. */
void cliparser::parse(const string_view &input, const string_view &input_next)
{
    if (skipnext_) {
        skipnext_ = false;

        if (!input_next.empty())
            return;
    }

    for (auto &&opt : valid_opts_) {
        if (is(input, opt.flag, opt.flag_long)) {
            if (opt.token.empty()) {
                passed_opts_.insert(std::make_pair(opt.flag_long.substr(2), ""));
            } else {
                auto value = parse_value(input.data(), input_next, opt.values);
                skipnext_ = (value == input_next);
                passed_opts_.insert(make_pair(opt.flag_long.substr(2), value));
            }

            return;
        }
    }

    if (input.compare(0, 1, "-") == 0)
        throw argument_error("Unrecognized option " + string(input.data()));
}
<|endoftext|>


<commit_before>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "common/common.h"
#include <assert.h>
#include <time.h>

#include "store/api/iterator.h"
#include "store/api/temp_seq.h"
#include "store/api/item_factory.h"
#include "store/api/store.h"

#include "system/globalenv.h"

#include "context/dynamic_context.h"
#include "context/static_context.h"

#include "compiler/expression/var_expr.h"

#include "types/root_typemanager.h"

#include "runtime/api/plan_wrapper.h"

#include "zorbatypes/Unicode_util.h"

using namespace std;
namespace zorba {

bool dynamic_context::static_init = false;

void dynamic_context::init()
{
	if (!dynamic_context::static_init) {
		dynamic_context::static_init = true;
	}
}

dynamic_context::dynamic_context(dynamic_context *parent)
{
	this->parent = parent;
	if(!parent)
	{
    // set the current time
		time_t		t0 = time(NULL);
#if defined (WIN32)
		struct	::tm	gmtm;
    localtime_s(&gmtm, &t0); //thread safe localtime on Windows
#else
		struct	::tm	gmtm;
    localtime_r(&t0, &gmtm); //thread safe localtime on Linux
#endif

		implicit_timezone = 0;

    GENV_ITEMFACTORY->createDateTime(current_date_time_item, gmtm.tm_year, gmtm.tm_mon, gmtm.tm_mday,
                                                              gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec, implicit_timezone);

		ctxt_position = 0;
	}
	else
	{
		current_date_time_item = parent->current_date_time_item;
		implicit_timezone = parent->implicit_timezone;
		default_collection_uri = parent->default_collection_uri;

		ctxt_item = parent->ctxt_item;
		ctxt_position = parent->ctxt_position;
	}
}

void dynamic_context::destroy_dctx_value (const dctx_value_t* val) {
  switch (val->type) {
  case dynamic_context::dctx_value_t::no_val:
    break;
  case dynamic_context::dctx_value_t::var_iterator_val:
    RCHelper::removeReference (val->val.var_iterator);
    break;
  case dynamic_context::dctx_value_t::temp_seq_val:
    RCHelper::removeReference (val->val.temp_seq);
    break;
  default:
    assert (false);
  }
}

dynamic_context::~dynamic_context()
{
	///free the pointers from ctx_value_t from keymap
	checked_vector<hashmap<dctx_value_t>::entry>::const_iterator it;
	const char		*keybuff;//[50];

	for(it = keymap.begin(); it != keymap.end(); it++)
	{
		///it is an entry
		keybuff = (*it).key.c_str();
		if(strncmp(keybuff, "var:", 4) == 0)
		{
			destroy_dctx_value (&(*it).val);
		}
	}
}

string dynamic_context::var_key (void *var) {
  if (var == NULL) return "";
  var_expr *ve = static_cast<var_expr *> (var);
  return to_string (var) + ":" + xqp_string (ve->get_varname ()->getStringValue ());
}

xqp_string dynamic_context::expand_varname(static_context	*sctx, xqp_string qname) const
{
  if(!sctx) {
    ///actually the whole static context is missing
    ZORBA_ERROR_PARAM( XPST0001, "entire static context", "");
			return (const char*)NULL;
  }
  void *var = static_cast<void *> (sctx->lookup_var (qname));
  return var_key (var);
}

/*______________________________________________________________________
|
|	XQuery 1.0 context
|	[http://www.w3.org/TR/xquery/#id-xq-context-components]
|_______________________________________________________________________*/
/*
pair<xqp_string, xqp_string> parse_qname (xqp_string qname);
xqp_string qname_internal_key2 (xqp_string ns, xqp_string local);

xqp_string dynamic_context::qname_internal_key (QNameItem_t qname) const {
  return qname_internal_key2 (qname->getNamespace (), qname->getLocalName ());
}
xqp_string dynamic_context::qname_internal_key (xqp_string default_ns, xqp_string prefix, xqp_string local) const {
  return qname_internal_key2
    (prefix.empty () ? default_ns : sctx->lookup_ns (prefix), local);
}
xqp_string dynamic_context::qname_internal_key (xqp_string default_ns, xqp_string qname) const {
  pair<xqp_string, xqp_string> rqname = parse_qname (qname);
  return qname_internal_key (default_ns, rqname.first, rqname.second);
}
*/

void dynamic_context::set_context_item(store::Item_t context_item, unsigned long position)
{
	this->ctxt_item = context_item;
	this->ctxt_position = position;
}

store::Item_t dynamic_context::context_item() const
{
	return ctxt_item;
}

unsigned long dynamic_context::context_position()
{
	return ctxt_position;
}

xqtref_t dynamic_context::context_item_type() const
{
	return GENV_TYPESYSTEM.ITEM_TYPE_STAR;
}

void dynamic_context::set_context_item_type(
	xqtref_t v)
{
}

void	dynamic_context::set_current_date_time( const store::Item_t& aDateTimeItem )
{
  this->current_date_time_item = aDateTimeItem;
}

store::Item_t	dynamic_context::get_current_date_time()
{
	return current_date_time_item;
}

void  dynamic_context::set_implicit_timezone(int tzone_seconds)
{
	this->implicit_timezone = tzone_seconds;
}

int  dynamic_context::get_implicit_timezone()
{
  return implicit_timezone;
}

/*
var_name is expanded name localname:nsURI
constructed by static_context::qname_internal_key( .. )
*/
void dynamic_context::add_variable(xqp_string var_name, store::Iterator_t var_iterator)
{
  if (var_name.empty()) return;

  // TODO: lazy conversion to a temp sequence
  dctx_value_t v;
  string key = "var:" + var_name;
  if (keymap.get (key, v))
    destroy_dctx_value (&v);

  v.type = dynamic_context::dctx_value_t::no_val;
  v.in_progress = true;
  keymap.put (key, v);

  var_iterator->open ();
  store::TempSeq_t seq = GENV_STORE.createTempSeq (var_iterator.getp());
  var_iterator->close ();
  RCHelper::addReference (seq);
  v.type = dynamic_context::dctx_value_t::temp_seq_val;
  v.in_progress = false;
  v.val.temp_seq = seq.getp();
  keymap.put (key, v);
}

store::Iterator_t	dynamic_context::get_variable(store::Item_t varname) {
	return lookup_var_iter("var:" + xqp_string (&*varname->getStringValue ()));
}

store::Iterator_t dynamic_context::lookup_var_iter(xqp_string key) {
    dctx_value_t val = {dctx_value_t::no_val, false, {0} };

  if(!keymap.get (key, val))
	{
    if(parent)
      return parent->lookup_var_iter(key);
    else
      return NULL;///variable not found
	}
  if (val.in_progress)
    ZORBA_ERROR (XQST0054);
  assert (val.type == dynamic_context::dctx_value_t::temp_seq_val);
  return val.val.temp_seq->getIterator ();
}

xqp_string dynamic_context::get_default_collection()
{
	return default_collection_uri;
}

void dynamic_context::set_default_collection(xqp_string default_collection_uri)
{
	this->default_collection_uri = default_collection_uri;
}

}	/* namespace zorba */

<commit_msg>set current-dateTime properly<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "common/common.h"
#include <assert.h>
#include <time.h>

#include "store/api/iterator.h"
#include "store/api/temp_seq.h"
#include "store/api/item_factory.h"
#include "store/api/store.h"

#include "system/globalenv.h"

#include "context/dynamic_context.h"
#include "context/static_context.h"

#include "compiler/expression/var_expr.h"

#include "types/root_typemanager.h"

#include "runtime/api/plan_wrapper.h"

#include "zorbatypes/Unicode_util.h"

using namespace std;
namespace zorba {

bool dynamic_context::static_init = false;

void dynamic_context::init()
{
	if (!dynamic_context::static_init) {
		dynamic_context::static_init = true;
	}
}

dynamic_context::dynamic_context(dynamic_context *parent)
{
	this->parent = parent;
	if(!parent)
	{
    // set the current time
		time_t		t0 = time(NULL);
#if defined (WIN32)
		struct	::tm	gmtm;
    localtime_s(&gmtm, &t0); //thread safe localtime on Windows
#else
		struct	::tm	gmtm;
    localtime_r(&t0, &gmtm); //thread safe localtime on Linux
#endif

		implicit_timezone = 0;

    GENV_ITEMFACTORY->createDateTime(current_date_time_item, gmtm.tm_year + 1900, gmtm.tm_mon + 1, gmtm.tm_mday,
                                                              gmtm.tm_hour, gmtm.tm_min, gmtm.tm_sec, implicit_timezone);

		ctxt_position = 0;
	}
	else
	{
		current_date_time_item = parent->current_date_time_item;
		implicit_timezone = parent->implicit_timezone;
		default_collection_uri = parent->default_collection_uri;

		ctxt_item = parent->ctxt_item;
		ctxt_position = parent->ctxt_position;
	}
}

void dynamic_context::destroy_dctx_value (const dctx_value_t* val) {
  switch (val->type) {
  case dynamic_context::dctx_value_t::no_val:
    break;
  case dynamic_context::dctx_value_t::var_iterator_val:
    RCHelper::removeReference (val->val.var_iterator);
    break;
  case dynamic_context::dctx_value_t::temp_seq_val:
    RCHelper::removeReference (val->val.temp_seq);
    break;
  default:
    assert (false);
  }
}

dynamic_context::~dynamic_context()
{
	///free the pointers from ctx_value_t from keymap
	checked_vector<hashmap<dctx_value_t>::entry>::const_iterator it;
	const char		*keybuff;//[50];

	for(it = keymap.begin(); it != keymap.end(); it++)
	{
		///it is an entry
		keybuff = (*it).key.c_str();
		if(strncmp(keybuff, "var:", 4) == 0)
		{
			destroy_dctx_value (&(*it).val);
		}
	}
}

string dynamic_context::var_key (void *var) {
  if (var == NULL) return "";
  var_expr *ve = static_cast<var_expr *> (var);
  return to_string (var) + ":" + xqp_string (ve->get_varname ()->getStringValue ());
}

xqp_string dynamic_context::expand_varname(static_context	*sctx, xqp_string qname) const
{
  if(!sctx) {
    ///actually the whole static context is missing
    ZORBA_ERROR_PARAM( XPST0001, "entire static context", "");
			return (const char*)NULL;
  }
  void *var = static_cast<void *> (sctx->lookup_var (qname));
  return var_key (var);
}

/*______________________________________________________________________
|
|	XQuery 1.0 context
|	[http://www.w3.org/TR/xquery/#id-xq-context-components]
|_______________________________________________________________________*/
/*
pair<xqp_string, xqp_string> parse_qname (xqp_string qname);
xqp_string qname_internal_key2 (xqp_string ns, xqp_string local);

xqp_string dynamic_context::qname_internal_key (QNameItem_t qname) const {
  return qname_internal_key2 (qname->getNamespace (), qname->getLocalName ());
}
xqp_string dynamic_context::qname_internal_key (xqp_string default_ns, xqp_string prefix, xqp_string local) const {
  return qname_internal_key2
    (prefix.empty () ? default_ns : sctx->lookup_ns (prefix), local);
}
xqp_string dynamic_context::qname_internal_key (xqp_string default_ns, xqp_string qname) const {
  pair<xqp_string, xqp_string> rqname = parse_qname (qname);
  return qname_internal_key (default_ns, rqname.first, rqname.second);
}
*/

void dynamic_context::set_context_item(store::Item_t context_item, unsigned long position)
{
	this->ctxt_item = context_item;
	this->ctxt_position = position;
}

store::Item_t dynamic_context::context_item() const
{
	return ctxt_item;
}

unsigned long dynamic_context::context_position()
{
	return ctxt_position;
}

xqtref_t dynamic_context::context_item_type() const
{
	return GENV_TYPESYSTEM.ITEM_TYPE_STAR;
}

void dynamic_context::set_context_item_type(
	xqtref_t v)
{
}

void	dynamic_context::set_current_date_time( const store::Item_t& aDateTimeItem )
{
  this->current_date_time_item = aDateTimeItem;
}

store::Item_t	dynamic_context::get_current_date_time()
{
	return current_date_time_item;
}

void  dynamic_context::set_implicit_timezone(int tzone_seconds)
{
	this->implicit_timezone = tzone_seconds;
}

int  dynamic_context::get_implicit_timezone()
{
  return implicit_timezone;
}

/*
var_name is expanded name localname:nsURI
constructed by static_context::qname_internal_key( .. )
*/
void dynamic_context::add_variable(xqp_string var_name, store::Iterator_t var_iterator)
{
  if (var_name.empty()) return;

  // TODO: lazy conversion to a temp sequence
  dctx_value_t v;
  string key = "var:" + var_name;
  if (keymap.get (key, v))
    destroy_dctx_value (&v);

  v.type = dynamic_context::dctx_value_t::no_val;
  v.in_progress = true;
  keymap.put (key, v);

  var_iterator->open ();
  store::TempSeq_t seq = GENV_STORE.createTempSeq (var_iterator.getp());
  var_iterator->close ();
  RCHelper::addReference (seq);
  v.type = dynamic_context::dctx_value_t::temp_seq_val;
  v.in_progress = false;
  v.val.temp_seq = seq.getp();
  keymap.put (key, v);
}

store::Iterator_t	dynamic_context::get_variable(store::Item_t varname) {
	return lookup_var_iter("var:" + xqp_string (&*varname->getStringValue ()));
}

store::Iterator_t dynamic_context::lookup_var_iter(xqp_string key) {
    dctx_value_t val = {dctx_value_t::no_val, false, {0} };

  if(!keymap.get (key, val))
	{
    if(parent)
      return parent->lookup_var_iter(key);
    else
      return NULL;///variable not found
	}
  if (val.in_progress)
    ZORBA_ERROR (XQST0054);
  assert (val.type == dynamic_context::dctx_value_t::temp_seq_val);
  return val.val.temp_seq->getIterator ();
}

xqp_string dynamic_context::get_default_collection()
{
	return default_collection_uri;
}

void dynamic_context::set_default_collection(xqp_string default_collection_uri)
{
	this->default_collection_uri = default_collection_uri;
}

}	/* namespace zorba */

<|endoftext|>


<commit_before>/* RTcmix  - Copyright (C) 2004  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <rtcmix_types.h>
#include <PField.h>
#include <utils.h>   // in ../../rtcmix
#include <PFBusPField.h>
#include <ugens.h>		// for warn, die

// -----------------------------------------------------------------------------
//
//		stream = makeconnection("pfbus", pfbus_no, default);
//
//		<pfbus_no>		the max object inlet number associated with this handle
//    <default>      default value (delivered while a PFSCHED() instrument
//								hasn't started executing yet)
//
//		score to use this might be:
//
//		delayed_envelope = maketable("line", 1000, 0,0.0,  1,1.0)
//		PFSCHED(3.5, 2.1, 1, delayed_envelope)
//		value = makeconnection("pfbus", 1, 0.0)
//		INSTRUMENT(0, 5.6, value, p3)
//
//		the "value" PField for INSTRUMENT will be 0.0 until time 3.5, then
//		the delayed_envelope table will start delivering values for 2.1 seconds
//		through the PFSCHED instrument.  The values will be set on pfbus #1
//		(pfbusses[1] internally).
//				BGG 11/2009

static RTNumberPField *
_pfbus_usage()
{
	die("makeconnection (pfbus)",
		"Usage: makeconnection(\"pfbus\", pfbus #, default)");
	return NULL;
}

static RTNumberPField *
create_pfield(const Arg args[], const int nargs)
{
	int pfbusval;
	double defaultval;

	if (nargs < 2)
		return _pfbus_usage();

	if (args[0].isType(DoubleType))
		pfbusval = (int)(args[0]);
	else
		return _pfbus_usage();

	if (args[1].isType(DoubleType))
		defaultval = args[1];
	else
		return _pfbus_usage();

	return new PFBusPField(pfbusval, defaultval);
}

// The following functions are the publically-visible ones called by the
// system.

extern "C" {
	Handle create_handle(const Arg args[], const int nargs);
	int register_dso();
};

Handle
create_handle(const Arg args[], const int nargs)
{
	PField *pField = create_pfield(args, nargs);
	Handle handle = NULL;
	if (pField != NULL) {
		handle = createPFieldHandle(pField);
	}
	return handle;
}

int register_dso()
{
   return 0;
}

<commit_msg>BGG:  added minor crash protection from unconnected pfbusses, 1/13/2011<commit_after>/* RTcmix  - Copyright (C) 2004  The RTcmix Development Team
   See ``AUTHORS'' for a list of contributors. See ``LICENSE'' for
   the license to this software and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <rtcmix_types.h>
#include <PField.h>
#include <utils.h>   // in ../../rtcmix
#include <PFBusPField.h>
#include <ugens.h>		// for warn, die

// -----------------------------------------------------------------------------
//
//		stream = makeconnection("pfbus", pfbus_no, default);
//
//		<pfbus_no>		the max object inlet number associated with this handle
//    <default>      default value (delivered while a PFSCHED() instrument
//								hasn't started executing yet)
//
//		score to use this might be:
//
//		delayed_envelope = maketable("line", 1000, 0,0.0,  1,1.0)
//		PFSCHED(3.5, 2.1, 1, delayed_envelope)
//		value = makeconnection("pfbus", 1, 0.0)
//		INSTRUMENT(0, 5.6, value, p3)
//
//		the "value" PField for INSTRUMENT will be 0.0 until time 3.5, then
//		the delayed_envelope table will start delivering values for 2.1 seconds
//		through the PFSCHED instrument.  The values will be set on pfbus #1
//		(pfbusses[1] internally).
//				BGG 11/2009

// BGG mm -- these are in insts/bgg/PFSCHED.h; catch a few crashes
extern struct pfbusdata pfbusses[];
extern int pfbus_is_connected[];

static RTNumberPField *
_pfbus_usage()
{
	die("makeconnection (pfbus)",
		"Usage: makeconnection(\"pfbus\", pfbus #, default)");
	return NULL;
}

static RTNumberPField *
create_pfield(const Arg args[], const int nargs)
{
	int pfbusval;
	double defaultval;

	if (nargs < 2)
		return _pfbus_usage();

	if (args[0].isType(DoubleType))
		pfbusval = (int)(args[0]);
	else
		return _pfbus_usage();

	if (args[1].isType(DoubleType))
		defaultval = args[1];
	else
		return _pfbus_usage();

	if (pfbusses[pfbusval].thepfield != NULL) {
		rterror("pfbusses", "pfbus %d is already connected", pfbusval);
		return (RTNumberPField*)(pfbusses[pfbusval].thepfield);
	}
	pfbus_is_connected[pfbusval] = 1;

	return new PFBusPField(pfbusval, defaultval);
}

// The following functions are the publically-visible ones called by the
// system.

extern "C" {
	Handle create_handle(const Arg args[], const int nargs);
	int register_dso();
};

Handle
create_handle(const Arg args[], const int nargs)
{
	PField *pField = create_pfield(args, nargs);
	Handle handle = NULL;
	if (pField != NULL) {
		handle = createPFieldHandle(pField);
	}
	return handle;
}

int register_dso()
{
   return 0;
}

<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"

#include <core/debug.h>
#include <core/io/LocalFileStream.h>
#include <core/config.h>
#include <core/support/Common.h>
#include <core/config.h>
#include <cstdio>
#include <iostream>

static const std::string TAG = "LocalFileStream";

using namespace musik::core::io;
using namespace musik::core::sdk;

LocalFileStream::LocalFileStream()
: file(nullptr)
, filesize(-1) {
}

LocalFileStream::~LocalFileStream() {
    try {
        this->Close();
    }
    catch (...) {
        musik::debug::err(TAG, "error closing file");
    }
}

bool LocalFileStream::Seekable() {
    return true;
}

bool LocalFileStream::Open(const char *filename, unsigned int options) {
    try {
        this->uri = filename;
        debug::info(TAG, "opening file: " + std::string(filename));

        boost::filesystem::path file(filename);

        if (!boost::filesystem::exists(file)) {
            debug::err(TAG, "open failed " + this->uri);
            return false;
        }

        if (!boost::filesystem::is_regular(file)) {
            debug::err(TAG, "not a regular file" + this->uri);
            return false;
        }

        this->filesize = (long)boost::filesystem::file_size(file);
        this->extension = file.extension().string();
#ifdef WIN32
        std::wstring u16fn = u8to16(this->uri);
        this->file = _wfopen(u16fn.c_str(), L"rb");
#else
        this->file = fopen(filename, "rb");
#endif

        if (this->file != NULL) {
            debug::info(TAG, "opened successfully");
            return true;
        }
    }
    catch(...) {
    }

    debug::err(TAG, "open failed " + std::string(filename));
    return false;
}

bool LocalFileStream::Close() {
    auto file = this->file.exchange(nullptr);
    if (file) {
        if (fclose(file) == 0) {
            return true;
        }
    }

    return false;
}

void LocalFileStream::Destroy() {
    delete this;
}

PositionType LocalFileStream::Read(void* buffer, PositionType readBytes) {
    if (!this->file) {
        return 0;
    }

    return (PositionType) fread(buffer, 1, readBytes, this->file);
}

bool LocalFileStream::SetPosition(PositionType position) {
    if (!this->file) {
        return false;
    }

    return fseek(this->file, position, SEEK_SET) == 0;
}

PositionType LocalFileStream::Position() {
    if (!this->file) {
        return -1;
    }

    return ftell(this->file);
}

bool LocalFileStream::Eof() {
    return !this->file || feof(this->file) != 0;
}

long LocalFileStream::Length() {
    return this->filesize;
}

const char* LocalFileStream::Type() {
    return this->extension.c_str();
}

const char* LocalFileStream::Uri() {
    return this->uri.c_str();
}
<commit_msg>Fixed win32 compile.<commit_after>//////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2007-2016 musikcube team
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//    * Redistributions of source code must retain the above copyright notice,
//      this list of conditions and the following disclaimer.
//
//    * Redistributions in binary form must reproduce the above copyright
//      notice, this list of conditions and the following disclaimer in the
//      documentation and/or other materials provided with the distribution.
//
//    * Neither the name of the author nor the names of other contributors may
//      be used to endorse or promote products derived from this software
//      without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////

#include "pch.hpp"

#include <core/debug.h>
#include <core/io/LocalFileStream.h>
#include <core/config.h>
#include <core/support/Common.h>
#include <core/config.h>
#include <cstdio>
#include <iostream>

static const std::string TAG = "LocalFileStream";

using namespace musik::core::io;
using namespace musik::core::sdk;

LocalFileStream::LocalFileStream()
: file(nullptr)
, filesize(-1) {
}

LocalFileStream::~LocalFileStream() {
    try {
        this->Close();
    }
    catch (...) {
        musik::debug::err(TAG, "error closing file");
    }
}

bool LocalFileStream::Seekable() {
    return true;
}

bool LocalFileStream::Open(const char *filename, unsigned int options) {
    try {
        this->uri = filename;
        debug::info(TAG, "opening file: " + std::string(filename));

        boost::filesystem::path file(filename);

        if (!boost::filesystem::exists(file)) {
            debug::err(TAG, "open failed " + this->uri);
            return false;
        }

        if (!boost::filesystem::is_regular(file)) {
            debug::err(TAG, "not a regular file" + this->uri);
            return false;
        }

        this->filesize = (long)boost::filesystem::file_size(file);
        this->extension = file.extension().string();
#ifdef WIN32
        std::wstring u16fn = u8to16(this->uri);
        this->file = _wfopen(u16fn.c_str(), L"rb");
#else
        this->file = fopen(filename, "rb");
#endif

        if (this->file.load()) {
            debug::info(TAG, "opened successfully");
            return true;
        }
    }
    catch(...) {
    }

    debug::err(TAG, "open failed " + std::string(filename));
    return false;
}

bool LocalFileStream::Close() {
    auto file = this->file.exchange(nullptr);
    if (file) {
        if (fclose(file) == 0) {
            return true;
        }
    }

    return false;
}

void LocalFileStream::Destroy() {
    delete this;
}

PositionType LocalFileStream::Read(void* buffer, PositionType readBytes) {
    if (!this->file.load()) {
        return 0;
    }

    return (PositionType) fread(buffer, 1, readBytes, this->file);
}

bool LocalFileStream::SetPosition(PositionType position) {
    if (!this->file.load()) {
        return false;
    }

    return fseek(this->file, position, SEEK_SET) == 0;
}

PositionType LocalFileStream::Position() {
    if (!this->file.load()) {
        return -1;
    }

    return ftell(this->file);
}

bool LocalFileStream::Eof() {
    return !this->file.load() || feof(this->file) != 0;
}

long LocalFileStream::Length() {
    return this->filesize;
}

const char* LocalFileStream::Type() {
    return this->extension.c_str();
}

const char* LocalFileStream::Uri() {
    return this->uri.c_str();
}
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/* Posix implementation for gpr threads. */

#include <grpc/support/port_platform.h>

#ifdef GPR_POSIX_SYNC

#include "src/core/lib/gprpp/thd.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd_id.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/memory.h"

namespace grpc_core {
namespace {
class ThreadInternalsPosix;
struct thd_arg {
  ThreadInternalsPosix* thread;
  void (*body)(void* arg); /* body of a thread */
  void* arg;               /* argument to a thread */
  const char* name;        /* name of thread. Can be nullptr. */
  bool joinable;
  bool tracked;
};

// TODO(yunjiaw): move this to a function-level static, or remove the use of a
// non-constexpr initializer when possible
const size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));

size_t RoundUpToPageSize(size_t size) {
  return (size + page_size - 1) & ~(page_size - 1);
}

// Returns the minimum valid stack size that can be passed to
// pthread_attr_setstacksize.
size_t MinValidStackSize(size_t request_size) {
  if (request_size < _SC_THREAD_STACK_MIN) {
    request_size = _SC_THREAD_STACK_MIN;
  }

  // On some systems, pthread_attr_setstacksize() can fail if stacksize is
  // not a multiple of the system page size.
  return RoundUpToPageSize(request_size);
}

class ThreadInternalsPosix : public internal::ThreadInternalsInterface {
 public:
  ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
                       void* arg, bool* success, const Thread::Options& options)
      : started_(false) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&ready_);
    pthread_attr_t attr;
    /* don't use gpr_malloc as we may cause an infinite recursion with
     * the profiling code */
    thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info)));
    GPR_ASSERT(info != nullptr);
    info->thread = this;
    info->body = thd_body;
    info->arg = arg;
    info->name = thd_name;
    info->joinable = options.joinable();
    info->tracked = options.tracked();
    if (options.tracked()) {
      Fork::IncThreadCount();
    }

    GPR_ASSERT(pthread_attr_init(&attr) == 0);
    if (options.joinable()) {
      GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
                 0);
    } else {
      GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
                 0);
    }

    if (options.stack_size() != 0) {
      size_t stack_size = MinValidStackSize(options.stack_size());
      GPR_ASSERT(pthread_attr_setstacksize(&attr, stack_size) == 0);
    }

    *success =
        (pthread_create(&pthread_id_, &attr,
                        [](void* v) -> void* {
                          thd_arg arg = *static_cast<thd_arg*>(v);
                          free(v);
                          if (arg.name != nullptr) {
#if GPR_APPLE_PTHREAD_NAME
                            /* Apple supports 64 characters, and will
                             * truncate if it's longer. */
                            pthread_setname_np(arg.name);
#elif GPR_LINUX_PTHREAD_NAME
                            /* Linux supports 16 characters max, and will
                             * error if it's longer. */
                            char buf[16];
                            size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
                            strncpy(buf, arg.name, buf_len);
                            buf[buf_len] = '\0';
                            pthread_setname_np(pthread_self(), buf);
#endif  // GPR_APPLE_PTHREAD_NAME
                          }

                          gpr_mu_lock(&arg.thread->mu_);
                          while (!arg.thread->started_) {
                            gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_,
                                        gpr_inf_future(GPR_CLOCK_MONOTONIC));
                          }
                          gpr_mu_unlock(&arg.thread->mu_);

                          if (!arg.joinable) {
                            Delete(arg.thread);
                          }

                          (*arg.body)(arg.arg);
                          if (arg.tracked) {
                            Fork::DecThreadCount();
                          }
                          return nullptr;
                        },
                        info) == 0);

    GPR_ASSERT(pthread_attr_destroy(&attr) == 0);

    if (!(*success)) {
      /* don't use gpr_free, as this was allocated using malloc (see above) */
      free(info);
      if (options.tracked()) {
        Fork::DecThreadCount();
      }
    }
  }

  ~ThreadInternalsPosix() override {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&ready_);
  }

  void Start() override {
    gpr_mu_lock(&mu_);
    started_ = true;
    gpr_cv_signal(&ready_);
    gpr_mu_unlock(&mu_);
  }

  void Join() override { pthread_join(pthread_id_, nullptr); }

 private:
  gpr_mu mu_;
  gpr_cv ready_;
  bool started_;
  pthread_t pthread_id_;
};

}  // namespace

Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
               bool* success, const Options& options)
    : options_(options) {
  bool outcome = false;
  impl_ = New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome, options);
  if (outcome) {
    state_ = ALIVE;
  } else {
    state_ = FAILED;
    Delete(impl_);
    impl_ = nullptr;
  }

  if (success != nullptr) {
    *success = outcome;
  }
}
}  // namespace grpc_core

// The following is in the external namespace as it is exposed as C89 API
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }

#endif /* GPR_POSIX_SYNC */
<commit_msg>Change page_size to local variable<commit_after>/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

/* Posix implementation for gpr threads. */

#include <grpc/support/port_platform.h>

#ifdef GPR_POSIX_SYNC

#include "src/core/lib/gprpp/thd.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/sync.h>
#include <grpc/support/thd_id.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include "src/core/lib/gpr/useful.h"
#include "src/core/lib/gprpp/fork.h"
#include "src/core/lib/gprpp/memory.h"

namespace grpc_core {
namespace {
class ThreadInternalsPosix;
struct thd_arg {
  ThreadInternalsPosix* thread;
  void (*body)(void* arg); /* body of a thread */
  void* arg;               /* argument to a thread */
  const char* name;        /* name of thread. Can be nullptr. */
  bool joinable;
  bool tracked;
};

size_t RoundUpToPageSize(size_t size) {
  // TODO(yunjiaw): Change this variable (page_size) to a function-level static
  // when possible
  size_t page_size = static_cast<size_t>(sysconf(_SC_PAGESIZE));
  return (size + page_size - 1) & ~(page_size - 1);
}

// Returns the minimum valid stack size that can be passed to
// pthread_attr_setstacksize.
size_t MinValidStackSize(size_t request_size) {
  if (request_size < _SC_THREAD_STACK_MIN) {
    request_size = _SC_THREAD_STACK_MIN;
  }

  // On some systems, pthread_attr_setstacksize() can fail if stacksize is
  // not a multiple of the system page size.
  return RoundUpToPageSize(request_size);
}

class ThreadInternalsPosix : public internal::ThreadInternalsInterface {
 public:
  ThreadInternalsPosix(const char* thd_name, void (*thd_body)(void* arg),
                       void* arg, bool* success, const Thread::Options& options)
      : started_(false) {
    gpr_mu_init(&mu_);
    gpr_cv_init(&ready_);
    pthread_attr_t attr;
    /* don't use gpr_malloc as we may cause an infinite recursion with
     * the profiling code */
    thd_arg* info = static_cast<thd_arg*>(malloc(sizeof(*info)));
    GPR_ASSERT(info != nullptr);
    info->thread = this;
    info->body = thd_body;
    info->arg = arg;
    info->name = thd_name;
    info->joinable = options.joinable();
    info->tracked = options.tracked();
    if (options.tracked()) {
      Fork::IncThreadCount();
    }

    GPR_ASSERT(pthread_attr_init(&attr) == 0);
    if (options.joinable()) {
      GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE) ==
                 0);
    } else {
      GPR_ASSERT(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) ==
                 0);
    }

    if (options.stack_size() != 0) {
      size_t stack_size = MinValidStackSize(options.stack_size());
      GPR_ASSERT(pthread_attr_setstacksize(&attr, stack_size) == 0);
    }

    *success =
        (pthread_create(&pthread_id_, &attr,
                        [](void* v) -> void* {
                          thd_arg arg = *static_cast<thd_arg*>(v);
                          free(v);
                          if (arg.name != nullptr) {
#if GPR_APPLE_PTHREAD_NAME
                            /* Apple supports 64 characters, and will
                             * truncate if it's longer. */
                            pthread_setname_np(arg.name);
#elif GPR_LINUX_PTHREAD_NAME
                            /* Linux supports 16 characters max, and will
                             * error if it's longer. */
                            char buf[16];
                            size_t buf_len = GPR_ARRAY_SIZE(buf) - 1;
                            strncpy(buf, arg.name, buf_len);
                            buf[buf_len] = '\0';
                            pthread_setname_np(pthread_self(), buf);
#endif  // GPR_APPLE_PTHREAD_NAME
                          }

                          gpr_mu_lock(&arg.thread->mu_);
                          while (!arg.thread->started_) {
                            gpr_cv_wait(&arg.thread->ready_, &arg.thread->mu_,
                                        gpr_inf_future(GPR_CLOCK_MONOTONIC));
                          }
                          gpr_mu_unlock(&arg.thread->mu_);

                          if (!arg.joinable) {
                            Delete(arg.thread);
                          }

                          (*arg.body)(arg.arg);
                          if (arg.tracked) {
                            Fork::DecThreadCount();
                          }
                          return nullptr;
                        },
                        info) == 0);

    GPR_ASSERT(pthread_attr_destroy(&attr) == 0);

    if (!(*success)) {
      /* don't use gpr_free, as this was allocated using malloc (see above) */
      free(info);
      if (options.tracked()) {
        Fork::DecThreadCount();
      }
    }
  }

  ~ThreadInternalsPosix() override {
    gpr_mu_destroy(&mu_);
    gpr_cv_destroy(&ready_);
  }

  void Start() override {
    gpr_mu_lock(&mu_);
    started_ = true;
    gpr_cv_signal(&ready_);
    gpr_mu_unlock(&mu_);
  }

  void Join() override { pthread_join(pthread_id_, nullptr); }

 private:
  gpr_mu mu_;
  gpr_cv ready_;
  bool started_;
  pthread_t pthread_id_;
};

}  // namespace

Thread::Thread(const char* thd_name, void (*thd_body)(void* arg), void* arg,
               bool* success, const Options& options)
    : options_(options) {
  bool outcome = false;
  impl_ = New<ThreadInternalsPosix>(thd_name, thd_body, arg, &outcome, options);
  if (outcome) {
    state_ = ALIVE;
  } else {
    state_ = FAILED;
    Delete(impl_);
    impl_ = nullptr;
  }

  if (success != nullptr) {
    *success = outcome;
  }
}
}  // namespace grpc_core

// The following is in the external namespace as it is exposed as C89 API
gpr_thd_id gpr_thd_currentid(void) { return (gpr_thd_id)pthread_self(); }

#endif /* GPR_POSIX_SYNC */
<|endoftext|>


<commit_before>#include "cozmo_description/cozmo.hpp"
#include "Eigen/Dense"
#include <cmath>
#include <chrono>
#include <thread>
#include "aikido/trajectory/Trajectory.hpp"
#include "aikido/trajectory/Interpolated.hpp"
#include "aikido/statespace/Interpolator.hpp"
#include "aikido/statespace/GeodesicInterpolator.hpp"
#include "aikido/statespace/SE2.hpp"

namespace libcozmo{
using BoxShape = dart::dynamics::BoxShape;
using MeshShape = dart::dynamics::MeshShape;
using FreeJoint = dart::dynamics::FreeJoint;
using RevoluteJoint = dart::dynamics::RevoluteJoint;
using VisualAspect = dart::dynamics::VisualAspect;
using Skeleton = dart::dynamics::Skeleton;
using WeldJointConstraint = dart::constraint::WeldJointConstraint;
using InverseKinematicsPtr = dart::dynamics::InverseKinematicsPtr;
using Interpolator = aikido::statespace::Interpolator;
using GeodesicInterpolator = aikido::statespace::GeodesicInterpolator;
using Interpolated = aikido::trajectory::Interpolated;
using aikido::statespace::SE2;

Cozmo::Cozmo(const std::string& mesh_dir){
  createCozmo(mesh_dir);
}

void Cozmo::createIKModule()
{
    ik = dart::dynamics::InverseKinematics::create(ghost_strut);
    ik->useChain();
}

void Cozmo::setForkliftPosition(double pos)
{
    lower_forklift_strut_right->getParentJoint()->setPosition(0, pos);
    upper_forklift_strut_right->getParentJoint()->setPosition(0, pos + 0.08);
    lower_forklift_strut_left->getParentJoint()->setPosition(0, pos);
    upper_forklift_strut_left->getParentJoint()->setPosition(0, pos + 0.08);

    Eigen::Isometry3d goal_pose;
    goal_pose = lower_forklift_strut_right->getTransform(base);

    // Solve IK
    ik->getTarget()->setTransform(goal_pose, base);
    Eigen::VectorXd ik_solution;
    if (ik->solve(ik_solution, true)) {
        std::cout << "IK solution found!\n";
    } else {
        std::cout << "No IK solution found.\n" << std::endl;
    }
}

BodyNodePtr Cozmo::makeRootBody(const SkeletonPtr& cozmo,
				const std::string& mesh_name,
				const std::string& mesh_dir)
{
    FreeJoint::Properties properties;

    BodyNodePtr bn = cozmo->createJointAndBodyNodePair<FreeJoint>(
        nullptr,
		properties,
		dart::dynamics::BodyNode::AspectProperties(mesh_name)).second;

    std::shared_ptr<MeshShape> base(new MeshShape(Eigen::Vector3d(1., 1., 1.),
						  MeshShape::loadMesh(mesh_dir + "/cozmo_base.STL")));

    auto shapeNode = bn->createShapeNodeWith<VisualAspect>(std::static_pointer_cast<dart::dynamics::Shape>(base));

    Eigen::Isometry3d tf = Eigen::Isometry3d::Identity();
    Eigen::Matrix3d R = Eigen::Matrix3d::Identity();

    R = Eigen::AngleAxisd(-M_PI/2, Eigen::Vector3d::UnitX());
    tf.linear() = R;

    bn->getParentJoint()->setTransformFromChildBodyNode(tf);
    shapeNode->getVisualAspect()->setRGB(Eigen::Vector3d(190/255., 190/255., 190/255.));

    return bn;
}

BodyNodePtr Cozmo::addBody(const SkeletonPtr& cozmo,
			   BodyNodePtr parent,
			   const std::string& mesh_name,
			   const std::string& mesh_dir,
	                   Eigen::Vector3d transformFromParent,
			   Eigen::Vector3d transformFromChild)
{
    RevoluteJoint::Properties properties;
    properties.mName = mesh_name;

    auto joint_bn = cozmo->createJointAndBodyNodePair<RevoluteJoint>(parent,
								     properties,
								     dart::dynamics::BodyNode::AspectProperties(mesh_name));
    auto bn = joint_bn.second;
    auto joint = joint_bn.first;

    // Assumes that all mesh file names are at most 20 characters
    // Pulls the file name out of the longer body node name and creates file path
    const std::string& filepath = mesh_dir + "/"  + mesh_name.substr(0,20) + ".STL";

    std::shared_ptr<MeshShape> child(new MeshShape(Eigen::Vector3d(1., 1., 1.),
						   MeshShape::loadMesh(filepath)));

    auto shapeNode = bn->createShapeNodeWith<VisualAspect>(std::static_pointer_cast<dart::dynamics::Shape>(child));

    Eigen::Isometry3d tf = Eigen::Isometry3d::Identity();
    Eigen::Matrix3d R = Eigen::Matrix3d::Identity();

    shapeNode->getVisualAspect()->setRGB(Eigen::Vector3d(190/255., 190/255., 190/255.));

    tf.translation() = transformFromParent;
    joint->setTransformFromParentBodyNode(tf);

    tf.translation() = transformFromChild;
    joint->setTransformFromChildBodyNode(tf);

    return bn;
}

SkeletonPtr Cozmo::createCozmo(const std::string& mesh_dir)
{
    cozmo = Skeleton::create("cozmo");
    base = makeRootBody(cozmo, "body", mesh_dir);
    head = addBody(cozmo,
    		  base,
    		  "head",
    		  mesh_dir,
    		  Eigen::Vector3d(0.03, 0.0615, 0.0385),
    		  Eigen::Vector3d(0.022, 0.02, 0.0));

    upper_forklift_strut_left = addBody(cozmo,
					base,
					"upper_forklift_strut_left",
					mesh_dir,
					Eigen::Vector3d(-0.0045, 0.058, 0.0805),
					Eigen::Vector3d(0.003, 0.021, 0.0));

    upper_forklift_strut_right = addBody(cozmo,
					base,
					"upper_forklift_strut_right",
					mesh_dir,
					Eigen::Vector3d(-0.0045, 0.058, 0.0315),
					Eigen::Vector3d(0.003, 0.021, 0.0));

    lower_forklift_strut_left = addBody(cozmo,
					base,
					"lower_forklift_strut_left",
					mesh_dir,
					Eigen::Vector3d(-0.0025, 0.044, 0.0805),
					Eigen::Vector3d(0.006, 0.015, 0.0));

    lower_forklift_strut_right = addBody(cozmo,
					base,
					"lower_forklift_strut_right",
					mesh_dir,
					Eigen::Vector3d(-0.0025, 0.044, 0.0315),
					Eigen::Vector3d(0.006, 0.015, 0.0));

    forklift = addBody(cozmo,
		      upper_forklift_strut_right,
		      "forklift",
		      mesh_dir,
		      Eigen::Vector3d(0.066, 0.001, 0.0032),
		      Eigen::Vector3d(0.0028, 0.025, 0.0));

    // We solve IK in the setForkliftPosition to make this strut exactly
    // match lower_forklift_strut_right in order to compensate for the
    // inability to model closed chains
    ghost_strut = addBody(cozmo,
  			  forklift,
  			  "lower_forklift_strut_ghost",
  			  mesh_dir,
  			  Eigen::Vector3d(0.003, 0.01, 0.0),
  			  Eigen::Vector3d(0.0691, 0.0032, 0.0032));

    createIKModule();
    setForkliftPosition(0.0);

    return cozmo;
}

void Cozmo::executeTrajectory(
    std::chrono::milliseconds period,
    TrajectoryPtr traj)
{
    using std::chrono::system_clock;
    using std::chrono::duration;
    using std::chrono::duration_cast;

    system_clock::time_point startTime = system_clock::now();
    bool trajInExecution = true;

    while (trajInExecution) {
        auto space = traj->getStateSpace();
        if (space == NULL) { std::cout << "State space is NULL" << std::endl; }
        auto scopedState = space->createState();

        system_clock::time_point const now = system_clock::now();
        double t = duration_cast<duration<double> >(now - startTime).count();

        traj->evaluate(t, scopedState);

        std::unique_lock<std::mutex> skeleton_lock(cozmo->getMutex());

        auto state = static_cast<SE2::State*>(scopedState.getState());
        Eigen::Isometry2d trans = state->getIsometry();

        Eigen::Isometry3d trans_3d = Eigen::Isometry3d::Identity();
        trans_3d.translation() << trans.translation()[0], trans.translation()[1], 0.;
        trans_3d.linear().block<2,2>(0,0) = trans.linear();

        base->getParentJoint()->setPositions(
            dart::dynamics::FreeJoint::convertToPositions(trans_3d));

        skeleton_lock.unlock();

        bool const is_done = (t >= traj->getEndTime());
        if (is_done) trajInExecution = false;

        std::this_thread::sleep_until(now + period);
    }
}

SE2::State Cozmo::createState(const double x, const double y, const double th)
{
    SE2::State s;
    Eigen::Isometry2d t = Eigen::Isometry2d::Identity();
    const Eigen::Rotation2D<double> rot(th);
    t.linear() = rot.toRotationMatrix();
    Eigen::Vector2d trans;
    trans << x, y;
    t.translation() = trans;
    s.setIsometry(t);
    return s;
}

std::shared_ptr<Interpolated> Cozmo::createInterpolatedTraj(
  std::vector<Waypoint> waypoints)
{
    std::shared_ptr<SE2> statespace = std::make_shared<SE2>();
    std::shared_ptr<Interpolator> interpolator =
      std::make_shared<GeodesicInterpolator>(statespace);

    const int num_waypoints = waypoints.size();
    Waypoint *w = new Waypoint;

    SE2::State s;
    std::shared_ptr<Interpolated> traj;
    traj = std::make_shared<Interpolated>(statespace, interpolator);

    for (int i=0; i < num_waypoints; i++) {
      w = &waypoints.at(i);
      s = createState(w->x, w->y, w->th);
      traj->addWaypoint(w->t, &s);
    }

    return traj;
}

}  // namespace libcozmo
<commit_msg>changed deprecated function<commit_after>#include "cozmo_description/cozmo.hpp"
#include "Eigen/Dense"
#include <cmath>
#include <chrono>
#include <thread>
#include "aikido/trajectory/Trajectory.hpp"
#include "aikido/trajectory/Interpolated.hpp"
#include "aikido/statespace/Interpolator.hpp"
#include "aikido/statespace/GeodesicInterpolator.hpp"
#include "aikido/statespace/SE2.hpp"

namespace libcozmo{
using BoxShape = dart::dynamics::BoxShape;
using MeshShape = dart::dynamics::MeshShape;
using FreeJoint = dart::dynamics::FreeJoint;
using RevoluteJoint = dart::dynamics::RevoluteJoint;
using VisualAspect = dart::dynamics::VisualAspect;
using Skeleton = dart::dynamics::Skeleton;
using WeldJointConstraint = dart::constraint::WeldJointConstraint;
using InverseKinematicsPtr = dart::dynamics::InverseKinematicsPtr;
using Interpolator = aikido::statespace::Interpolator;
using GeodesicInterpolator = aikido::statespace::GeodesicInterpolator;
using Interpolated = aikido::trajectory::Interpolated;
using aikido::statespace::SE2;

Cozmo::Cozmo(const std::string& mesh_dir){
  createCozmo(mesh_dir);
}

void Cozmo::createIKModule()
{
    ik = dart::dynamics::InverseKinematics::create(ghost_strut);
    ik->useChain();
}

void Cozmo::setForkliftPosition(double pos)
{
    lower_forklift_strut_right->getParentJoint()->setPosition(0, pos);
    upper_forklift_strut_right->getParentJoint()->setPosition(0, pos + 0.08);
    lower_forklift_strut_left->getParentJoint()->setPosition(0, pos);
    upper_forklift_strut_left->getParentJoint()->setPosition(0, pos + 0.08);

    Eigen::Isometry3d goal_pose;
    goal_pose = lower_forklift_strut_right->getTransform(base);

    // Solve IK
    ik->getTarget()->setTransform(goal_pose, base);
    Eigen::VectorXd ik_solution;
    if (ik->solveAndApply(ik_solution, true)) {
        std::cout << "IK solution found!\n";
    } else {
        std::cout << "No IK solution found.\n" << std::endl;
    }
}

BodyNodePtr Cozmo::makeRootBody(const SkeletonPtr& cozmo,
				const std::string& mesh_name,
				const std::string& mesh_dir)
{
    FreeJoint::Properties properties;

    BodyNodePtr bn = cozmo->createJointAndBodyNodePair<FreeJoint>(
        nullptr,
		properties,
		dart::dynamics::BodyNode::AspectProperties(mesh_name)).second;

    std::shared_ptr<MeshShape> base(new MeshShape(Eigen::Vector3d(1., 1., 1.),
						  MeshShape::loadMesh(mesh_dir + "/cozmo_base.STL")));

    auto shapeNode = bn->createShapeNodeWith<VisualAspect>(std::static_pointer_cast<dart::dynamics::Shape>(base));

    Eigen::Isometry3d tf = Eigen::Isometry3d::Identity();
    Eigen::Matrix3d R = Eigen::Matrix3d::Identity();

    R = Eigen::AngleAxisd(-M_PI/2, Eigen::Vector3d::UnitX());
    tf.linear() = R;

    bn->getParentJoint()->setTransformFromChildBodyNode(tf);
    shapeNode->getVisualAspect()->setRGB(Eigen::Vector3d(190/255., 190/255., 190/255.));

    return bn;
}

BodyNodePtr Cozmo::addBody(const SkeletonPtr& cozmo,
			   BodyNodePtr parent,
			   const std::string& mesh_name,
			   const std::string& mesh_dir,
	                   Eigen::Vector3d transformFromParent,
			   Eigen::Vector3d transformFromChild)
{
    RevoluteJoint::Properties properties;
    properties.mName = mesh_name;

    auto joint_bn = cozmo->createJointAndBodyNodePair<RevoluteJoint>(parent,
								     properties,
								     dart::dynamics::BodyNode::AspectProperties(mesh_name));
    auto bn = joint_bn.second;
    auto joint = joint_bn.first;

    // Assumes that all mesh file names are at most 20 characters
    // Pulls the file name out of the longer body node name and creates file path
    const std::string& filepath = mesh_dir + "/"  + mesh_name.substr(0,20) + ".STL";

    std::shared_ptr<MeshShape> child(new MeshShape(Eigen::Vector3d(1., 1., 1.),
						   MeshShape::loadMesh(filepath)));

    auto shapeNode = bn->createShapeNodeWith<VisualAspect>(std::static_pointer_cast<dart::dynamics::Shape>(child));

    Eigen::Isometry3d tf = Eigen::Isometry3d::Identity();
    Eigen::Matrix3d R = Eigen::Matrix3d::Identity();

    shapeNode->getVisualAspect()->setRGB(Eigen::Vector3d(190/255., 190/255., 190/255.));

    tf.translation() = transformFromParent;
    joint->setTransformFromParentBodyNode(tf);

    tf.translation() = transformFromChild;
    joint->setTransformFromChildBodyNode(tf);

    return bn;
}

SkeletonPtr Cozmo::createCozmo(const std::string& mesh_dir)
{
    cozmo = Skeleton::create("cozmo");
    base = makeRootBody(cozmo, "body", mesh_dir);
    head = addBody(cozmo,
    		  base,
    		  "head",
    		  mesh_dir,
    		  Eigen::Vector3d(0.03, 0.0615, 0.0385),
    		  Eigen::Vector3d(0.022, 0.02, 0.0));

    upper_forklift_strut_left = addBody(cozmo,
					base,
					"upper_forklift_strut_left",
					mesh_dir,
					Eigen::Vector3d(-0.0045, 0.058, 0.0805),
					Eigen::Vector3d(0.003, 0.021, 0.0));

    upper_forklift_strut_right = addBody(cozmo,
					base,
					"upper_forklift_strut_right",
					mesh_dir,
					Eigen::Vector3d(-0.0045, 0.058, 0.0315),
					Eigen::Vector3d(0.003, 0.021, 0.0));

    lower_forklift_strut_left = addBody(cozmo,
					base,
					"lower_forklift_strut_left",
					mesh_dir,
					Eigen::Vector3d(-0.0025, 0.044, 0.0805),
					Eigen::Vector3d(0.006, 0.015, 0.0));

    lower_forklift_strut_right = addBody(cozmo,
					base,
					"lower_forklift_strut_right",
					mesh_dir,
					Eigen::Vector3d(-0.0025, 0.044, 0.0315),
					Eigen::Vector3d(0.006, 0.015, 0.0));

    forklift = addBody(cozmo,
		      upper_forklift_strut_right,
		      "forklift",
		      mesh_dir,
		      Eigen::Vector3d(0.066, 0.001, 0.0032),
		      Eigen::Vector3d(0.0028, 0.025, 0.0));

    // We solve IK in the setForkliftPosition to make this strut exactly
    // match lower_forklift_strut_right in order to compensate for the
    // inability to model closed chains
    ghost_strut = addBody(cozmo,
  			  forklift,
  			  "lower_forklift_strut_ghost",
  			  mesh_dir,
  			  Eigen::Vector3d(0.003, 0.01, 0.0),
  			  Eigen::Vector3d(0.0691, 0.0032, 0.0032));

    createIKModule();
    setForkliftPosition(0.0);

    return cozmo;
}

void Cozmo::executeTrajectory(
    std::chrono::milliseconds period,
    TrajectoryPtr traj)
{
    using std::chrono::system_clock;
    using std::chrono::duration;
    using std::chrono::duration_cast;

    system_clock::time_point startTime = system_clock::now();
    bool trajInExecution = true;

    while (trajInExecution) {
        auto space = traj->getStateSpace();
        if (space == NULL) { std::cout << "State space is NULL" << std::endl; }
        auto scopedState = space->createState();

        system_clock::time_point const now = system_clock::now();
        double t = duration_cast<duration<double> >(now - startTime).count();

        traj->evaluate(t, scopedState);

        std::unique_lock<std::mutex> skeleton_lock(cozmo->getMutex());

        auto state = static_cast<SE2::State*>(scopedState.getState());
        Eigen::Isometry2d trans = state->getIsometry();

        Eigen::Isometry3d trans_3d = Eigen::Isometry3d::Identity();
        trans_3d.translation() << trans.translation()[0], trans.translation()[1], 0.;
        trans_3d.linear().block<2,2>(0,0) = trans.linear();

        base->getParentJoint()->setPositions(
            dart::dynamics::FreeJoint::convertToPositions(trans_3d));

        skeleton_lock.unlock();

        bool const is_done = (t >= traj->getEndTime());
        if (is_done) trajInExecution = false;

        std::this_thread::sleep_until(now + period);
    }
}

SE2::State Cozmo::createState(const double x, const double y, const double th)
{
    SE2::State s;
    Eigen::Isometry2d t = Eigen::Isometry2d::Identity();
    const Eigen::Rotation2D<double> rot(th);
    t.linear() = rot.toRotationMatrix();
    Eigen::Vector2d trans;
    trans << x, y;
    t.translation() = trans;
    s.setIsometry(t);
    return s;
}

std::shared_ptr<Interpolated> Cozmo::createInterpolatedTraj(
  std::vector<Waypoint> waypoints)
{
    std::shared_ptr<SE2> statespace = std::make_shared<SE2>();
    std::shared_ptr<Interpolator> interpolator =
      std::make_shared<GeodesicInterpolator>(statespace);

    const int num_waypoints = waypoints.size();
    Waypoint *w = new Waypoint;

    SE2::State s;
    std::shared_ptr<Interpolated> traj;
    traj = std::make_shared<Interpolated>(statespace, interpolator);

    for (int i=0; i < num_waypoints; i++) {
      w = &waypoints.at(i);
      s = createState(w->x, w->y, w->th);
      traj->addWaypoint(w->t, &s);
    }

    return traj;
}

}  // namespace libcozmo
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Author: jmarantz@google.com (Joshua Marantz)

#include "net/instaweb/rewriter/public/domain_rewrite_filter.h"

#include <memory>

#include "net/instaweb/htmlparse/public/html_element.h"
#include "net/instaweb/htmlparse/public/html_name.h"
#include "net/instaweb/http/public/meta_data.h"
#include "net/instaweb/http/public/response_headers.h"
#include "net/instaweb/http/public/semantic_type.h"
#include "net/instaweb/rewriter/public/domain_lawyer.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "net/instaweb/rewriter/public/resource_tag_scanner.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/static_asset_manager.h"
#include "net/instaweb/util/public/basictypes.h"
#include "net/instaweb/util/public/google_url.h"
#include "net/instaweb/util/public/statistics.h"
#include "net/instaweb/util/public/string.h"
#include "net/instaweb/util/public/string_hash.h"
#include "net/instaweb/util/public/string_util.h"

namespace {

// Names for Statistics variables.
const char kDomainRewrites[] = "domain_rewrites";

}  // namespace

namespace net_instaweb {

DomainRewriteFilter::DomainRewriteFilter(RewriteDriver* rewrite_driver,
                                         Statistics *stats)
    : CommonFilter(rewrite_driver),
      rewrite_count_(stats->GetVariable(kDomainRewrites)) {}

void DomainRewriteFilter::StartDocumentImpl() {
  bool rewrite_hyperlinks = driver_->options()->domain_rewrite_hyperlinks();

  if (rewrite_hyperlinks) {
    // TODO(nikhilmadan): Rewrite the domain for cookies.
    // Rewrite the Location header for redirects.
    UpdateLocationHeader(driver_->base_url(), driver_,
                         driver_->mutable_response_headers());
  }
}

DomainRewriteFilter::~DomainRewriteFilter() {}

void DomainRewriteFilter::InitStats(Statistics* statistics) {
  statistics->AddVariable(kDomainRewrites);
}

void DomainRewriteFilter::UpdateLocationHeader(const GoogleUrl& base_url,
                                               RewriteDriver* driver,
                                               ResponseHeaders* headers) const {
  if (headers != NULL) {
    const char* location = headers->Lookup1(HttpAttributes::kLocation);
    if (location != NULL) {
      GoogleString new_location;
      DomainRewriteFilter::RewriteResult status = Rewrite(
          location, base_url, driver, false /* !apply_sharding */,
          &new_location);
      if (status == kRewroteDomain) {
        headers->Replace(HttpAttributes::kLocation, new_location);
      }
    }
  }
}

void DomainRewriteFilter::StartElementImpl(HtmlElement* element) {
  resource_tag_scanner::UrlCategoryVector attributes;
  resource_tag_scanner::ScanElement(element, driver_->options(), &attributes);
  for (int i = 0, n = attributes.size(); i < n; ++i) {
    // Disable domain_rewrite for non-image, non-script, non-stylesheet urls
    // unless ModPagespeedDomainRewriteHyperlinks is on
    if (attributes[i].category != semantic_type::kImage &&
        attributes[i].category != semantic_type::kScript &&
        attributes[i].category != semantic_type::kStylesheet &&
        !driver_->options()->domain_rewrite_hyperlinks()) {
      continue;
    }
    StringPiece val(attributes[i].url->DecodedValueOrNull());
    GoogleString rewritten_val;
    // Don't shard hyperlinks, prefetch, embeds, frames, or iframes.
    bool apply_sharding = (
        attributes[i].category != semantic_type::kHyperlink &&
        attributes[i].category != semantic_type::kPrefetch &&
        element->keyword() != HtmlName::kEmbed &&
        element->keyword() != HtmlName::kFrame &&
        element->keyword() != HtmlName::kIframe);
    if (!val.empty() && BaseUrlIsValid() &&
        (Rewrite(val, driver_->base_url(), driver_,
                 apply_sharding, &rewritten_val) == kRewroteDomain)) {
      attributes[i].url->SetValue(rewritten_val);
      rewrite_count_->Add(1);
    }
  }
}

// Resolve the url we want to rewrite, and then shard as appropriate.
DomainRewriteFilter::RewriteResult DomainRewriteFilter::Rewrite(
    const StringPiece& url_to_rewrite, const GoogleUrl& base_url,
    const RewriteDriver* driver,
    bool apply_sharding, GoogleString* rewritten_url) const {
  if (url_to_rewrite.empty()) {
    rewritten_url->clear();
    return kDomainUnchanged;
  }

  GoogleUrl orig_url(base_url, url_to_rewrite);
  if (!orig_url.IsWebOrDataValid()) {
    return kFail;
  }

  if (!orig_url.IsWebValid()) {
    url_to_rewrite.CopyToString(rewritten_url);
    return kDomainUnchanged;
  }

  StringPiece orig_spec = orig_url.Spec();
  const RewriteOptions* options = driver->options();

  if (!options->IsAllowed(orig_spec) ||
      // Don't rewrite a domain from an already-rewritten resource.
      server_context_->IsPagespeedResource(orig_url)) {
    // Even though domain is unchanged, we need to store absolute URL in
    // rewritten_url.
    orig_url.Spec().CopyToString(rewritten_url);
    return kDomainUnchanged;
  }

  // Apply any domain rewrites.
  //
  // TODO(jmarantz): There are two things going on: resolving URLs
  // against base and mapping them.  We should (a) factor those out
  // so they are distinct and (b) only do the resolution once, as it
  // is expensive.  I think the ResourceSlot system offers a good
  // framework to do this.
  const DomainLawyer* lawyer = options->domain_lawyer();
  GoogleString mapped_domain_name;
  GoogleUrl resolved_request;
  if (!lawyer->MapRequestToDomain(base_url, url_to_rewrite,
                                  &mapped_domain_name, &resolved_request,
                                  driver->message_handler())) {
    // Even though domain is unchanged, we need to store absolute URL in
    // rewritten_url.
    orig_url.Spec().CopyToString(rewritten_url);
    return kDomainUnchanged;
  }

  // Next, apply any sharding.
  GoogleString sharded_domain;
  GoogleString domain = StrCat(resolved_request.Origin(), "/");
  resolved_request.Spec().CopyToString(rewritten_url);
  uint32 int_hash = HashString<CasePreserve, uint32>(
      rewritten_url->data(), rewritten_url->size());
  if (apply_sharding &&
      lawyer->ShardDomain(domain, int_hash, &sharded_domain)) {
    *rewritten_url = StrCat(sharded_domain,
                            resolved_request.PathAndLeaf().substr(1));
  }

  // Return true if really changed the url with this rewrite.
  if (orig_spec == *rewritten_url) {
    return kDomainUnchanged;
  } else {
    return kRewroteDomain;
  }
}

void DomainRewriteFilter::EndDocument() {
  if (!driver_->options()->client_domain_rewrite()) {
    return;
  }
  const DomainLawyer* lawyer = driver_->options()->domain_lawyer();
  ConstStringStarVector from_domains;
  lawyer->FindDomainsRewrittenTo(driver_->base_url(), &from_domains);

  if (from_domains.empty()) {
    return;
  }

  GoogleString comma_separated_from_domains;
  for (int i = 0, n = from_domains.size(); i < n; i++) {
    StrAppend(&comma_separated_from_domains, "\"", *(from_domains[i]), "\"");
    if (i != n - 1) {
      StrAppend(&comma_separated_from_domains, ",");
    }
  }

  HtmlElement* script_node = driver_->NewElement(NULL, HtmlName::kScript);
  InsertNodeAtBodyEnd(script_node);
  StaticAssetManager* static_asset_manager =
      driver_->server_context()->static_asset_manager();
  GoogleString js =
      StrCat(static_asset_manager->GetAsset(
                 StaticAssetManager::kClientDomainRewriter, driver_->options()),
             "pagespeed.clientDomainRewriterInit([",
             comma_separated_from_domains, "]);");
  static_asset_manager->AddJsToElement(js, script_node, driver_);
}

}  // namespace net_instaweb
<commit_msg>Fix the performance of DomainRewriteFilter::StartElement by moving a loop invariant out of the loop. (from matterbury)<commit_after>/*
 * Copyright 2011 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Author: jmarantz@google.com (Joshua Marantz)

#include "net/instaweb/rewriter/public/domain_rewrite_filter.h"

#include <memory>

#include "net/instaweb/htmlparse/public/html_element.h"
#include "net/instaweb/htmlparse/public/html_name.h"
#include "net/instaweb/http/public/meta_data.h"
#include "net/instaweb/http/public/response_headers.h"
#include "net/instaweb/http/public/semantic_type.h"
#include "net/instaweb/rewriter/public/domain_lawyer.h"
#include "net/instaweb/rewriter/public/server_context.h"
#include "net/instaweb/rewriter/public/resource_tag_scanner.h"
#include "net/instaweb/rewriter/public/rewrite_driver.h"
#include "net/instaweb/rewriter/public/rewrite_options.h"
#include "net/instaweb/rewriter/public/static_asset_manager.h"
#include "net/instaweb/util/public/basictypes.h"
#include "net/instaweb/util/public/google_url.h"
#include "net/instaweb/util/public/statistics.h"
#include "net/instaweb/util/public/string.h"
#include "net/instaweb/util/public/string_hash.h"
#include "net/instaweb/util/public/string_util.h"

namespace {

// Names for Statistics variables.
const char kDomainRewrites[] = "domain_rewrites";

}  // namespace

namespace net_instaweb {

DomainRewriteFilter::DomainRewriteFilter(RewriteDriver* rewrite_driver,
                                         Statistics *stats)
    : CommonFilter(rewrite_driver),
      rewrite_count_(stats->GetVariable(kDomainRewrites)) {}

void DomainRewriteFilter::StartDocumentImpl() {
  bool rewrite_hyperlinks = driver_->options()->domain_rewrite_hyperlinks();

  if (rewrite_hyperlinks) {
    // TODO(nikhilmadan): Rewrite the domain for cookies.
    // Rewrite the Location header for redirects.
    UpdateLocationHeader(driver_->base_url(), driver_,
                         driver_->mutable_response_headers());
  }
}

DomainRewriteFilter::~DomainRewriteFilter() {}

void DomainRewriteFilter::InitStats(Statistics* statistics) {
  statistics->AddVariable(kDomainRewrites);
}

void DomainRewriteFilter::UpdateLocationHeader(const GoogleUrl& base_url,
                                               RewriteDriver* driver,
                                               ResponseHeaders* headers) const {
  if (headers != NULL) {
    const char* location = headers->Lookup1(HttpAttributes::kLocation);
    if (location != NULL) {
      GoogleString new_location;
      DomainRewriteFilter::RewriteResult status = Rewrite(
          location, base_url, driver, false /* !apply_sharding */,
          &new_location);
      if (status == kRewroteDomain) {
        headers->Replace(HttpAttributes::kLocation, new_location);
      }
    }
  }
}

void DomainRewriteFilter::StartElementImpl(HtmlElement* element) {
  if (!BaseUrlIsValid()) {
    // The base URL is used to rewrite the attribute URL, which is all this
    // method does; if it isn't valid we can't so there's no point in going on.
    return;
  }
  resource_tag_scanner::UrlCategoryVector attributes;
  resource_tag_scanner::ScanElement(element, driver_->options(), &attributes);
  bool element_is_embed_or_frame_or_iframe = (
      element->keyword() == HtmlName::kEmbed ||
      element->keyword() == HtmlName::kFrame ||
      element->keyword() == HtmlName::kIframe);
  for (int i = 0, n = attributes.size(); i < n; ++i) {
    // Disable domain_rewrite for non-image, non-script, non-stylesheet urls
    // unless ModPagespeedDomainRewriteHyperlinks is on
    if (attributes[i].category != semantic_type::kImage &&
        attributes[i].category != semantic_type::kScript &&
        attributes[i].category != semantic_type::kStylesheet &&
        !driver_->options()->domain_rewrite_hyperlinks()) {
      continue;
    }
    StringPiece val(attributes[i].url->DecodedValueOrNull());
    if (val.empty()) {
      // We don't rewrite empty URLs so bail early in that case.
      continue;
    }
    GoogleString rewritten_val;
    // Don't shard hyperlinks, prefetch, embeds, frames, or iframes.
    bool apply_sharding = (
        !element_is_embed_or_frame_or_iframe &&
        attributes[i].category != semantic_type::kHyperlink &&
        attributes[i].category != semantic_type::kPrefetch);
    if (Rewrite(val, driver_->base_url(), driver_,
                apply_sharding, &rewritten_val) == kRewroteDomain) {
      attributes[i].url->SetValue(rewritten_val);
      rewrite_count_->Add(1);
    }
  }
}

// Resolve the url we want to rewrite, and then shard as appropriate.
DomainRewriteFilter::RewriteResult DomainRewriteFilter::Rewrite(
    const StringPiece& url_to_rewrite, const GoogleUrl& base_url,
    const RewriteDriver* driver,
    bool apply_sharding, GoogleString* rewritten_url) const {
  if (url_to_rewrite.empty()) {
    rewritten_url->clear();
    return kDomainUnchanged;
  }

  GoogleUrl orig_url(base_url, url_to_rewrite);
  if (!orig_url.IsWebOrDataValid()) {
    return kFail;
  }

  if (!orig_url.IsWebValid()) {
    url_to_rewrite.CopyToString(rewritten_url);
    return kDomainUnchanged;
  }

  StringPiece orig_spec = orig_url.Spec();
  const RewriteOptions* options = driver->options();

  if (!options->IsAllowed(orig_spec) ||
      // Don't rewrite a domain from an already-rewritten resource.
      server_context_->IsPagespeedResource(orig_url)) {
    // Even though domain is unchanged, we need to store absolute URL in
    // rewritten_url.
    orig_url.Spec().CopyToString(rewritten_url);
    return kDomainUnchanged;
  }

  // Apply any domain rewrites.
  //
  // TODO(jmarantz): There are two things going on: resolving URLs
  // against base and mapping them.  We should (a) factor those out
  // so they are distinct and (b) only do the resolution once, as it
  // is expensive.  I think the ResourceSlot system offers a good
  // framework to do this.
  const DomainLawyer* lawyer = options->domain_lawyer();
  GoogleString mapped_domain_name;
  GoogleUrl resolved_request;
  if (!lawyer->MapRequestToDomain(base_url, url_to_rewrite,
                                  &mapped_domain_name, &resolved_request,
                                  driver->message_handler())) {
    // Even though domain is unchanged, we need to store absolute URL in
    // rewritten_url.
    orig_url.Spec().CopyToString(rewritten_url);
    return kDomainUnchanged;
  }

  // Next, apply any sharding.
  GoogleString sharded_domain;
  GoogleString domain = StrCat(resolved_request.Origin(), "/");
  resolved_request.Spec().CopyToString(rewritten_url);
  uint32 int_hash = HashString<CasePreserve, uint32>(
      rewritten_url->data(), rewritten_url->size());
  if (apply_sharding &&
      lawyer->ShardDomain(domain, int_hash, &sharded_domain)) {
    *rewritten_url = StrCat(sharded_domain,
                            resolved_request.PathAndLeaf().substr(1));
  }

  // Return true if really changed the url with this rewrite.
  if (orig_spec == *rewritten_url) {
    return kDomainUnchanged;
  } else {
    return kRewroteDomain;
  }
}

void DomainRewriteFilter::EndDocument() {
  if (!driver_->options()->client_domain_rewrite()) {
    return;
  }
  const DomainLawyer* lawyer = driver_->options()->domain_lawyer();
  ConstStringStarVector from_domains;
  lawyer->FindDomainsRewrittenTo(driver_->base_url(), &from_domains);

  if (from_domains.empty()) {
    return;
  }

  GoogleString comma_separated_from_domains;
  for (int i = 0, n = from_domains.size(); i < n; i++) {
    StrAppend(&comma_separated_from_domains, "\"", *(from_domains[i]), "\"");
    if (i != n - 1) {
      StrAppend(&comma_separated_from_domains, ",");
    }
  }

  HtmlElement* script_node = driver_->NewElement(NULL, HtmlName::kScript);
  InsertNodeAtBodyEnd(script_node);
  StaticAssetManager* static_asset_manager =
      driver_->server_context()->static_asset_manager();
  GoogleString js =
      StrCat(static_asset_manager->GetAsset(
                 StaticAssetManager::kClientDomainRewriter, driver_->options()),
             "pagespeed.clientDomainRewriterInit([",
             comma_separated_from_domains, "]);");
  static_asset_manager->AddJsToElement(js, script_node, driver_);
}

}  // namespace net_instaweb
<|endoftext|>