<commit_before>// This file will be removed when the code is accepted into the Thrift library.
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 "config.h"

#ifdef HAVE_SASL_SASL_H
#include <stdint.h>
#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>

#include <thrift/transport/TBufferTransports.h>
#include "transport/TSaslTransport.h"

#include "common/names.h"

// Default size, in bytes, for the memory buffer used to stage reads.
const int32_t DEFAULT_MEM_BUF_SIZE = 32 * 1024;

namespace apache { namespace thrift { namespace transport {

  TSaslTransport::TSaslTransport(boost::shared_ptr<TTransport> transport)
      : transport_(transport),
        memBuf_(new TMemoryBuffer(DEFAULT_MEM_BUF_SIZE)),
        shouldWrap_(false),
        isClient_(false) {
  }

  TSaslTransport::TSaslTransport(boost::shared_ptr<sasl::TSasl> saslClient,
                                 boost::shared_ptr<TTransport> transport)
      : transport_(transport),
        memBuf_(new TMemoryBuffer()),
        sasl_(saslClient),
        shouldWrap_(false),
        isClient_(true) {
  }

  TSaslTransport::~TSaslTransport() {
    delete memBuf_;
  }

  bool TSaslTransport::isOpen() {
    return transport_->isOpen();
  }

  bool TSaslTransport::peek(){
    return (transport_->peek());
  }

  string TSaslTransport::getUsername() {
    return sasl_->getUsername();
  }

  void TSaslTransport::sendSaslMessage(const NegotiationStatus status,
      const uint8_t* payload, const uint32_t length, bool flush) {
    uint8_t messageHeader[STATUS_BYTES + PAYLOAD_LENGTH_BYTES];
    uint8_t dummy = 0;
    if (payload == NULL) {
      payload = &dummy;
    }
    messageHeader[0] = (uint8_t)status;
    encodeInt(length, messageHeader, STATUS_BYTES);
    transport_->write(messageHeader, HEADER_LENGTH);
    transport_->write(payload, length);
    if (flush) transport_->flush();
  }

  void TSaslTransport::open() {
    NegotiationStatus status = TSASL_INVALID;
    uint32_t resLength;

    // Only client should open the underlying transport.
    if (isClient_ && !transport_->isOpen()) {
      transport_->open();
    }

    // initiate  SASL message
    handleSaslStartMessage();

    // SASL connection handshake
    while (!sasl_->isComplete()) {
      uint8_t* message = receiveSaslMessage(&status, &resLength);
      if (status == TSASL_COMPLETE) {
        if (isClient_) break; // handshake complete
      } else if (status != TSASL_OK) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
      uint32_t challengeLength;
      uint8_t* challenge = sasl_->evaluateChallengeOrResponse(
          message, resLength, &challengeLength);
      sendSaslMessage(sasl_->isComplete() ? TSASL_COMPLETE : TSASL_OK,
                      challenge, challengeLength);
    }

    // If the server isn't complete yet, we need to wait for its response.
    // This will occur with ANONYMOUS auth, for example, where we send an
    // initial response and are immediately complete.
    if (isClient_ && (status == TSASL_INVALID || status == TSASL_OK)) {
      receiveSaslMessage(&status, &resLength);
      if (status != TSASL_COMPLETE) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
    }

    // TODO : need to set the shouldWrap_ based on QOP
    /*
    String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
    if (qop != null && !qop.equalsIgnoreCase("auth"))
      shouldWrap_ = true;
    */
  }

  void TSaslTransport::close() {
    transport_->close();
  }

  uint32_t TSaslTransport::readLength() {
    uint8_t lenBuf[PAYLOAD_LENGTH_BYTES];

    transport_->readAll(lenBuf, PAYLOAD_LENGTH_BYTES);
    int32_t len = decodeInt(lenBuf, 0);
    if (len < 0) {
      throw TTransportException("Frame size has negative value");
    }
    return static_cast<uint32_t>(len);
  }

  void TSaslTransport::shrinkBuffer() {
    // readEnd() returns the number of bytes already read, i.e. the number of 'junk' bytes
    // taking up space at the front of the memory buffer.
    uint32_t read_end = memBuf_->readEnd();

    // If the size of the junk space at the beginning of the buffer is too large, and
    // there's no data left in the buffer to read (number of bytes read == number of bytes
    // written), then shrink the buffer back to the default. We don't want to do this on
    // every read that exhausts the buffer, since the layer above often reads in small
    // chunks, which is why we only resize if there's too much junk. The write and read
    // pointers will eventually catch up after every RPC, so we will always take this path
    // eventually once the buffer becomes sufficiently full.
    //
    // readEnd() may reset the write / read pointers (but only once if there's no
    // intervening read or write between calls), so needs to be called a second time to
    // get their current position.
    if (read_end > DEFAULT_MEM_BUF_SIZE && memBuf_->writeEnd() == memBuf_->readEnd()) {
      memBuf_->resetBuffer(DEFAULT_MEM_BUF_SIZE);
    }
  }

  uint32_t TSaslTransport::read(uint8_t* buf, uint32_t len) {
    uint32_t read_bytes = memBuf_->read(buf, len);

    if (read_bytes > 0) {
      shrinkBuffer();
      return read_bytes;
    }

    // if there's not enough data in cache, read from underlying transport
    uint32_t dataLength = readLength();

    // Fast path
    if (len == dataLength && !shouldWrap_) {
      transport_->readAll(buf, len);
      return len;
    }

    uint8_t* tmpBuf = new uint8_t[dataLength];
    transport_->readAll(tmpBuf, dataLength);
    if (shouldWrap_) {
      tmpBuf = sasl_->unwrap(tmpBuf, 0, dataLength, &dataLength);
    }

    // We will consume all the data, no need to put it in the memory buffer.
    if (len == dataLength) {
      memcpy(buf, tmpBuf, len);
      delete[] tmpBuf;
      return len;
    }

    memBuf_->write(tmpBuf, dataLength);
    memBuf_->flush();
    delete[] tmpBuf;

    uint32_t ret = memBuf_->read(buf, len);
    shrinkBuffer();
    return ret;
  }

  void TSaslTransport::writeLength(uint32_t length) {
    uint8_t lenBuf[PAYLOAD_LENGTH_BYTES];

    encodeInt(length, lenBuf, 0);
    transport_->write(lenBuf, PAYLOAD_LENGTH_BYTES);
  }

  void TSaslTransport::write(const uint8_t* buf, uint32_t len) {
    const uint8_t* newBuf;

    if (shouldWrap_) {
      newBuf = sasl_->wrap((uint8_t*)buf, 0, len, &len);
    } else {
      newBuf = buf;
    }
    writeLength(len);
    transport_->write(newBuf, len);
  }

  void TSaslTransport::flush() {
    transport_->flush();
  }

  uint8_t* TSaslTransport::receiveSaslMessage(NegotiationStatus* status,
                                              uint32_t* length) {
    uint8_t messageHeader[HEADER_LENGTH];

    // read header
    transport_->readAll(messageHeader, HEADER_LENGTH);

    // get payload status
    *status = (NegotiationStatus)messageHeader[0];
    if ((*status < TSASL_START) || (*status > TSASL_COMPLETE)) {
      throw TTransportException("invalid sasl status");
    } else if (*status == TSASL_BAD || *status == TSASL_ERROR) {
        throw TTransportException("sasl Peer indicated failure: ");
    }

    // get the length
    *length = decodeInt(messageHeader, STATUS_BYTES);

    // get payload
    protoBuf_.reset(new uint8_t[*length]);
    transport_->readAll(protoBuf_.get(), *length);

    return protoBuf_.get();
  }
}
}
}

#endif
<commit_msg>IMPALA-5005: Don't allow server to send SASL COMPLETE msg out of order<commit_after>// This file will be removed when the code is accepted into the Thrift library.
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 "config.h"

#ifdef HAVE_SASL_SASL_H
#include <stdint.h>
#include <sstream>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>

#include <thrift/transport/TBufferTransports.h>
#include "transport/TSaslTransport.h"

#include "common/names.h"

// Default size, in bytes, for the memory buffer used to stage reads.
const int32_t DEFAULT_MEM_BUF_SIZE = 32 * 1024;

namespace apache { namespace thrift { namespace transport {

  TSaslTransport::TSaslTransport(boost::shared_ptr<TTransport> transport)
      : transport_(transport),
        memBuf_(new TMemoryBuffer(DEFAULT_MEM_BUF_SIZE)),
        shouldWrap_(false),
        isClient_(false) {
  }

  TSaslTransport::TSaslTransport(boost::shared_ptr<sasl::TSasl> saslClient,
                                 boost::shared_ptr<TTransport> transport)
      : transport_(transport),
        memBuf_(new TMemoryBuffer()),
        sasl_(saslClient),
        shouldWrap_(false),
        isClient_(true) {
  }

  TSaslTransport::~TSaslTransport() {
    delete memBuf_;
  }

  bool TSaslTransport::isOpen() {
    return transport_->isOpen();
  }

  bool TSaslTransport::peek(){
    return (transport_->peek());
  }

  string TSaslTransport::getUsername() {
    return sasl_->getUsername();
  }

  void TSaslTransport::sendSaslMessage(const NegotiationStatus status,
      const uint8_t* payload, const uint32_t length, bool flush) {
    uint8_t messageHeader[STATUS_BYTES + PAYLOAD_LENGTH_BYTES];
    uint8_t dummy = 0;
    if (payload == NULL) {
      payload = &dummy;
    }
    messageHeader[0] = (uint8_t)status;
    encodeInt(length, messageHeader, STATUS_BYTES);
    transport_->write(messageHeader, HEADER_LENGTH);
    transport_->write(payload, length);
    if (flush) transport_->flush();
  }

  void TSaslTransport::open() {
    NegotiationStatus status = TSASL_INVALID;
    uint32_t resLength;

    // Only client should open the underlying transport.
    if (isClient_ && !transport_->isOpen()) {
      transport_->open();
    }

    // initiate  SASL message
    handleSaslStartMessage();

    // SASL connection handshake
    while (!sasl_->isComplete()) {
      uint8_t* message = receiveSaslMessage(&status, &resLength);
      if (status == TSASL_COMPLETE) {
        if (isClient_) {
          if (!sasl_->isComplete()) {
            // Server sent COMPLETE out of order.
            throw TTransportException("Received COMPLETE but no handshake occurred");
          }
          break; // handshake complete
        }
      } else if (status != TSASL_OK) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
      uint32_t challengeLength;
      uint8_t* challenge = sasl_->evaluateChallengeOrResponse(
          message, resLength, &challengeLength);
      sendSaslMessage(sasl_->isComplete() ? TSASL_COMPLETE : TSASL_OK,
                      challenge, challengeLength);
    }

    // If the server isn't complete yet, we need to wait for its response.
    // This will occur with ANONYMOUS auth, for example, where we send an
    // initial response and are immediately complete.
    if (isClient_ && (status == TSASL_INVALID || status == TSASL_OK)) {
      receiveSaslMessage(&status, &resLength);
      if (status != TSASL_COMPLETE) {
        stringstream ss;
        ss << "Expected COMPLETE or OK, got " << status;
        throw TTransportException(ss.str());
      }
    }

    // TODO : need to set the shouldWrap_ based on QOP
    /*
    String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP);
    if (qop != null && !qop.equalsIgnoreCase("auth"))
      shouldWrap_ = true;
    */
  }

  void TSaslTransport::close() {
    transport_->close();
  }

  uint32_t TSaslTransport::readLength() {
    uint8_t lenBuf[PAYLOAD_LENGTH_BYTES];

    transport_->readAll(lenBuf, PAYLOAD_LENGTH_BYTES);
    int32_t len = decodeInt(lenBuf, 0);
    if (len < 0) {
      throw TTransportException("Frame size has negative value");
    }
    return static_cast<uint32_t>(len);
  }

  void TSaslTransport::shrinkBuffer() {
    // readEnd() returns the number of bytes already read, i.e. the number of 'junk' bytes
    // taking up space at the front of the memory buffer.
    uint32_t read_end = memBuf_->readEnd();

    // If the size of the junk space at the beginning of the buffer is too large, and
    // there's no data left in the buffer to read (number of bytes read == number of bytes
    // written), then shrink the buffer back to the default. We don't want to do this on
    // every read that exhausts the buffer, since the layer above often reads in small
    // chunks, which is why we only resize if there's too much junk. The write and read
    // pointers will eventually catch up after every RPC, so we will always take this path
    // eventually once the buffer becomes sufficiently full.
    //
    // readEnd() may reset the write / read pointers (but only once if there's no
    // intervening read or write between calls), so needs to be called a second time to
    // get their current position.
    if (read_end > DEFAULT_MEM_BUF_SIZE && memBuf_->writeEnd() == memBuf_->readEnd()) {
      memBuf_->resetBuffer(DEFAULT_MEM_BUF_SIZE);
    }
  }

  uint32_t TSaslTransport::read(uint8_t* buf, uint32_t len) {
    uint32_t read_bytes = memBuf_->read(buf, len);

    if (read_bytes > 0) {
      shrinkBuffer();
      return read_bytes;
    }

    // if there's not enough data in cache, read from underlying transport
    uint32_t dataLength = readLength();

    // Fast path
    if (len == dataLength && !shouldWrap_) {
      transport_->readAll(buf, len);
      return len;
    }

    uint8_t* tmpBuf = new uint8_t[dataLength];
    transport_->readAll(tmpBuf, dataLength);
    if (shouldWrap_) {
      tmpBuf = sasl_->unwrap(tmpBuf, 0, dataLength, &dataLength);
    }

    // We will consume all the data, no need to put it in the memory buffer.
    if (len == dataLength) {
      memcpy(buf, tmpBuf, len);
      delete[] tmpBuf;
      return len;
    }

    memBuf_->write(tmpBuf, dataLength);
    memBuf_->flush();
    delete[] tmpBuf;

    uint32_t ret = memBuf_->read(buf, len);
    shrinkBuffer();
    return ret;
  }

  void TSaslTransport::writeLength(uint32_t length) {
    uint8_t lenBuf[PAYLOAD_LENGTH_BYTES];

    encodeInt(length, lenBuf, 0);
    transport_->write(lenBuf, PAYLOAD_LENGTH_BYTES);
  }

  void TSaslTransport::write(const uint8_t* buf, uint32_t len) {
    const uint8_t* newBuf;

    if (shouldWrap_) {
      newBuf = sasl_->wrap((uint8_t*)buf, 0, len, &len);
    } else {
      newBuf = buf;
    }
    writeLength(len);
    transport_->write(newBuf, len);
  }

  void TSaslTransport::flush() {
    transport_->flush();
  }

  uint8_t* TSaslTransport::receiveSaslMessage(NegotiationStatus* status,
                                              uint32_t* length) {
    uint8_t messageHeader[HEADER_LENGTH];

    // read header
    transport_->readAll(messageHeader, HEADER_LENGTH);

    // get payload status
    *status = (NegotiationStatus)messageHeader[0];
    if ((*status < TSASL_START) || (*status > TSASL_COMPLETE)) {
      throw TTransportException("invalid sasl status");
    } else if (*status == TSASL_BAD || *status == TSASL_ERROR) {
        throw TTransportException("sasl Peer indicated failure: ");
    }

    // get the length
    *length = decodeInt(messageHeader, STATUS_BYTES);

    // get payload
    protoBuf_.reset(new uint8_t[*length]);
    transport_->readAll(protoBuf_.get(), *length);

    return protoBuf_.get();
  }
}
}
}

#endif
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <memory>
#include <initializer_list>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

enum class token_type {
    identifier,
    literal,
    op,

    eof
};

std::ostream& operator<<(std::ostream& os,  token_type t) {
    switch (t) {
#define HANDLE_TOKEN_TYPE(t) case token_type::t: os << #t; break
    HANDLE_TOKEN_TYPE(identifier);
    HANDLE_TOKEN_TYPE(literal);
    HANDLE_TOKEN_TYPE(op);
    HANDLE_TOKEN_TYPE(eof);
#undef HANDLE_TOKEN_TYPE
    }
    return os;
}

static size_t try_parse(token_type t, const char* text, size_t length) {
    assert(length != 0);
    if (t == token_type::identifier) {
        size_t l = 0;
        while (l < length && isalpha(text[l])) {
            ++l;
        }
        return l;
    } else if (t == token_type::literal) {
        std::istringstream iss{std::string{text, text+length}};
        assert(iss.tellg() == 0);
        double value;
        if (iss >> value) {
            const auto l = iss.eof() ? length : static_cast<size_t>(iss.tellg());
            assert(l != 0);
            assert(l <= length);
            return l;
        }
    } else if (t == token_type::op) {
        for (const auto& op : "*+-/=") {
            if (*text == op) {
                return 1;
            }
        }
    } else {
        std::ostringstream oss;
        oss << "Unhandled token type '" << t << "' str='" << std::string{text, text+length} << "' in " << __func__;
        throw std::logic_error(oss.str());
    }
    return 0;
}

class token {
public:
    static const size_t nts = size_t(-1);
    static token eof_token() { return token{token_type::eof, "", 0}; }
    static token identifier_token(const char* str, size_t len = nts) {
        return token{token_type::identifier, str, len == nts ? strlen(str) : len};
    }
    static token literal_token(const char* str, size_t len = nts) {
        return token{token_type::literal, str, len == nts ? strlen(str) : len};
    }
    static token op_token(const char* str, size_t len = nts) {
        return token{token_type::op, str, len == nts ? strlen(str) : len};
    }

    token_type  type() const { return type_; }
    std::string str() const { return std::string(text_, text_ + length_); }
    size_t      length() const { return length_; }
private:
    friend class tokenizer;

    token(token_type type, const char* text, size_t length) : type_(type), text_(text), length_(length) {
        assert((type == token_type::eof && length == 0) || try_parse(type, text, length) == length);
    }

    token_type  type_;
    const char* text_;
    size_t      length_;

};

bool operator==(const token& a, const token& b) {
    return a.type() == b.type() && a.str() == b.str();
}

bool operator!=(const token& a, const token& b) {
    return !(a == b);
}

std::ostream& operator<<(std::ostream& os, const token& t) {
    os << "{" << t.type() << " '" << t.str() << "'}";
    return os;
}

class tokenizer {
public:
    tokenizer(const char* text, size_t length) : text_(text), length_(length), pos_(0), current_(token::eof_token()) {
        next_token();
    }

    const token& current() const {
        return current_;
    }

    token consume() {
        auto cur = current_;
        next_token();
        return cur;
    }

private:
    const char* text_;
    size_t      length_;
    size_t      pos_;
    token       current_;

    // initialize current_ with appropriate token type from pos_ bytes into text_
    // advance pos_ by the tokens length
    void next_token() {
        // loop until we reach eof or get a now whitespace character
        for (;;) {
            // handle end of text
            if (pos_ >= length_) {
                assert(pos_ == length_);
                current_ = token::eof_token();
                return;
            }

            // we can now safely extract text_[pos_]
            const char* const text_pos = text_ + pos_;
            const size_t      remaining = length_ - pos_;

            // skip whitespace
            if (isspace(*text_pos)) {
                pos_++;
                continue;
            }

            for (const auto& t : { token_type::identifier, token_type::literal, token_type::op}) {
                if (const auto l = try_parse(t, text_pos, remaining)) {
                    assert(l <= remaining);
                    pos_ += l;
                    current_ = token{t, text_pos, l};
                    return;
                }
            }

            throw std::runtime_error("Parse error at: " + std::string(text_pos, text_pos+remaining));
        }
    }
};

void test_tokenizer(const std::string& text, std::initializer_list<token> expected_tokens)
{
    tokenizer t{text.c_str(), text.length()};
    for (const auto& expected_token : expected_tokens) {
        auto current_token = t.consume();
        std::cout << current_token << " ";
        if (current_token != expected_token) {
            std::cerr << "Tokenizer error. Expeceted " << expected_token << " got " << current_token << std::endl;
            abort();
        }
    }
    assert(t.current().type() == token_type::eof);
    std::cout << "OK!\n";
}

int main()
{
    test_tokenizer("",{token::eof_token()});
    test_tokenizer("\t\n\r   ",{token::eof_token()});
    test_tokenizer(" id  ",{token::identifier_token("id"), token::eof_token()});
    test_tokenizer("3.14",{token::literal_token("3.14"), token::eof_token()});
    test_tokenizer("=\n",{token::op_token("="), token::eof_token()});
    test_tokenizer("\thello 42",{token::identifier_token("hello"), token::literal_token("42"), token::eof_token()});
    test_tokenizer("\tx + 1e3 = 20",{token::identifier_token("x"), token::op_token("+"), token::literal_token("1e3"), token::op_token("="), token::literal_token("20"), token::eof_token()});

#if 0
    const char* const program = R"(
        vals       = 2000
        valsize    = 8
        freq       = 1
        bspersec   = vals * valsize * freq
        bsperday   = bspersec * 60 * 60 * 24
    )";
    test_tokenizer(program, {make_token(token_type
#endif
}
<commit_msg>More tests<commit_after>#include <iostream>
#include <iomanip>
#include <string>
#include <sstream>
#include <memory>
#include <initializer_list>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <ctype.h>

enum class token_type {
    identifier,
    literal,
    op,

    eof
};

std::ostream& operator<<(std::ostream& os,  token_type t) {
    switch (t) {
#define HANDLE_TOKEN_TYPE(t) case token_type::t: os << #t; break
    HANDLE_TOKEN_TYPE(identifier);
    HANDLE_TOKEN_TYPE(literal);
    HANDLE_TOKEN_TYPE(op);
    HANDLE_TOKEN_TYPE(eof);
#undef HANDLE_TOKEN_TYPE
    }
    return os;
}

static size_t try_parse(token_type t, const char* text, size_t length) {
    assert(length != 0);
    if (t == token_type::identifier) {
        size_t l = 0;
        while (l < length && isalpha(text[l])) {
            ++l;
        }
        return l;
    } else if (t == token_type::literal) {
        std::istringstream iss{std::string{text, text+length}};
        assert(iss.tellg() == 0);
        double value;
        if (iss >> value) {
            const auto l = iss.eof() ? length : static_cast<size_t>(iss.tellg());
            assert(l != 0);
            assert(l <= length);
            return l;
        }
    } else if (t == token_type::op) {
        for (const auto& op : "*+-/=") {
            if (*text == op) {
                return 1;
            }
        }
    } else {
        std::ostringstream oss;
        oss << "Unhandled token type '" << t << "' str='" << std::string{text, text+length} << "' in " << __func__;
        throw std::logic_error(oss.str());
    }
    return 0;
}

class token {
public:
    static const size_t nts = size_t(-1);
    static token eof() { return token{token_type::eof, "", 0}; }
    static token identifier(const char* str, size_t len = nts) {
        return token{token_type::identifier, str, len == nts ? strlen(str) : len};
    }
    static token literal(const char* str, size_t len = nts) {
        return token{token_type::literal, str, len == nts ? strlen(str) : len};
    }
    static token op(const char* str, size_t len = nts) {
        return token{token_type::op, str, len == nts ? strlen(str) : len};
    }

    token_type  type() const { return type_; }
    std::string str() const { return std::string(text_, text_ + length_); }
    size_t      length() const { return length_; }
private:
    friend class tokenizer;

    token(token_type type, const char* text, size_t length) : type_(type), text_(text), length_(length) {
        assert((type == token_type::eof && length == 0) || try_parse(type, text, length) == length);
    }

    token_type  type_;
    const char* text_;
    size_t      length_;

};

bool operator==(const token& a, const token& b) {
    return a.type() == b.type() && a.str() == b.str();
}

bool operator!=(const token& a, const token& b) {
    return !(a == b);
}

std::ostream& operator<<(std::ostream& os, const token& t) {
    os << "{" << t.type() << " '" << t.str() << "'}";
    return os;
}

class tokenizer {
public:
    tokenizer(const char* text, size_t length) : text_(text), length_(length), pos_(0), current_(token::eof()) {
        next_token();
    }

    const token& current() const {
        return current_;
    }

    token consume() {
        auto cur = current_;
        next_token();
        return cur;
    }

private:
    const char* text_;
    size_t      length_;
    size_t      pos_;
    token       current_;

    // initialize current_ with appropriate token type from pos_ bytes into text_
    // advance pos_ by the tokens length
    void next_token() {
        // loop until we reach eof or get a now whitespace character
        for (;;) {
            // handle end of text
            if (pos_ >= length_) {
                assert(pos_ == length_);
                current_ = token::eof();
                return;
            }

            // we can now safely extract text_[pos_]
            const char* const text_pos = text_ + pos_;
            const size_t      remaining = length_ - pos_;

            // skip whitespace
            if (isspace(*text_pos)) {
                pos_++;
                continue;
            }

            for (const auto& t : { token_type::identifier, token_type::literal, token_type::op}) {
                if (const auto l = try_parse(t, text_pos, remaining)) {
                    assert(l <= remaining);
                    pos_ += l;
                    current_ = token{t, text_pos, l};
                    return;
                }
            }

            throw std::runtime_error("Parse error at: " + std::string(text_pos, text_pos+remaining));
        }
    }
};

void test_tokenizer(const std::string& text, std::initializer_list<token> expected_tokens)
{
    tokenizer t{text.c_str(), text.length()};
    for (const auto& expected_token : expected_tokens) {
        auto current_token = t.consume();
        std::cout << current_token << " " << std::flush;
        if (current_token != expected_token) {
            std::cerr << "Tokenizer error. Expeceted " << expected_token << " got " << current_token << std::endl;
            abort();
        }
    }
    assert(t.current().type() == token_type::eof);
    std::cout << "OK!\n";
}

int main()
{
    test_tokenizer("",{token::eof()});
    test_tokenizer("\t\n\r   ",{token::eof()});
    test_tokenizer(" id  ",{token::identifier("id"), token::eof()});
    test_tokenizer("3.14",{token::literal("3.14"), token::eof()});
    test_tokenizer("=\n",{token::op("="), token::eof()});
    test_tokenizer("\thello 42",{token::identifier("hello"), token::literal("42"), token::eof()});
    test_tokenizer("\tx + 1e3 = 20",{token::identifier("x"), token::op("+"), token::literal("1e3"), token::op("="), token::literal("20"), token::eof()});

    const char* const program = R"(
        vals       = 2000
        valsize    = 8
        freq       = 1
        bspersec   = vals * valsize * freq
        bsperday   = bspersec * 60 * 60 * 24
    )";
    test_tokenizer(program, {
        token::identifier("vals"),     token::op("="), token::literal("2000"),
        token::identifier("valsize"),  token::op("="), token::literal("8"),
        token::identifier("freq"),     token::op("="), token::literal("1"),
        token::identifier("bspersec"), token::op("="), token::identifier("vals"), token::op("*"), token::identifier("valsize"), token::op("*"), token::identifier("freq"),
        token::identifier("bsperday"), token::op("="), token::identifier("bspersec"), token::op("*"), token::literal("60"), token::op("*"), token::literal("60"), token::op("*"), token::literal("24"),
        token::eof(),
    });
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/icon_loader.h"

#include "base/message_loop.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "third_party/skia/include/core/SkBitmap.h"

IconLoader::IconLoader(const IconGroupID& group, IconSize size,
                       Delegate* delegate)
    : group_(group),
      icon_size_(size),
      bitmap_(NULL),
      delegate_(delegate) {
}

IconLoader::~IconLoader() {
  delete bitmap_;
}

void IconLoader::Start() {
  target_message_loop_ = MessageLoop::current();

  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &IconLoader::ReadIcon));
}

void IconLoader::NotifyDelegate() {
  delegate_->OnBitmapLoaded(this, bitmap_);
  bitmap_ = NULL;
}
<commit_msg>Icon loader: respect delegate's response to NotifyDelegate call (false means the delegate doesn't assume ownership).<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/icon_loader.h"

#include "base/message_loop.h"
#include "base/thread.h"
#include "chrome/browser/browser_process.h"
#include "third_party/skia/include/core/SkBitmap.h"

IconLoader::IconLoader(const IconGroupID& group, IconSize size,
                       Delegate* delegate)
    : group_(group),
      icon_size_(size),
      bitmap_(NULL),
      delegate_(delegate) {
}

IconLoader::~IconLoader() {
  delete bitmap_;
}

void IconLoader::Start() {
  target_message_loop_ = MessageLoop::current();

  g_browser_process->file_thread()->message_loop()->PostTask(FROM_HERE,
      NewRunnableMethod(this, &IconLoader::ReadIcon));
}

void IconLoader::NotifyDelegate() {
  if (delegate_->OnBitmapLoaded(this, bitmap_))
    bitmap_ = NULL;
}
<|endoftext|>


<commit_before>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

/*
 * Driver for OTV0P2BASE_SensorAmbientLightOccupancy tests.
 */

#include <stdint.h>
#include <gtest/gtest.h>
#include <OTV0p2Base.h>
#include "OTV0P2BASE_SensorAmbientLightOccupancy.h"

// Sanity test.
TEST(AmbientLightOccupancyDetection,SanityTest)
{
    EXPECT_EQ(42, 42);
}

// Basic test of update() behaviour.
TEST(AmbientLightOccupancyDetection,updateBasics)
{
    // Check that initial update never indicates occupancy.
	OTV0P2BASE::SensorAmbientLightOccupancyDetectorSimple ds1;
    EXPECT_FALSE(ds1.update(0)) << "no initial update should imply occupancy";
	OTV0P2BASE::SensorAmbientLightOccupancyDetectorSimple ds2;
    EXPECT_FALSE(ds2.update(255)) << "no initial update should imply occupancy";
    // Check that update from 0 to max does force occupancy indication (but steady does not).
    EXPECT_TRUE(ds1.update(255)) << "update from 0 to 255 (max) illumination should signal occupancy";
    EXPECT_FALSE(ds2.update(255)) << "unchanged 255 (max) light level should not imply occupancy";
}

class ALDataSample
    {
    public:
        const uint8_t d, H, M, L, expected;

		// Day/hour/minute and light level and expected result.
		// An expected result of 0 means no particular result expected from this (anything is acceptable).
		// An expected result of 1 means occupancy should NOT be reported for this sample.
		// An expected result of 2+ means occupancy should be reported for this sample.
	    ALDataSample(uint8_t dayOfMonth, uint8_t hour24, uint8_t minute, uint8_t lightLevel, uint8_t expectedResult = 0)
			: d(dayOfMonth), H(hour24), M(minute), L(lightLevel), expected(expectedResult)
			{ }

        // Create/mark a terminating entry; all input values invalid.
	    ALDataSample() : d(255), H(255), M(255), L(255), expected(0) { }

        // Compute current minute for this record.
        long currentMinute() const { return((((d * 24L) + H) * 60L) + M); }

	    // True for empty/termination data record.
	    bool isEnd() const { return(d > 31); }
    };

// Trivial sample, testing initial reaction to start transient.
static const ALDataSample trivialSample1[] =
    {
{ 0, 0, 0, 254, 1 }, // Should NOT predict occupancy on first tick.
{ 0, 0, 1, 0, 1 }, // Should NOT predict occupancy on falling level.
{ 0, 0, 5, 0 }, // Should NOT predict occupancy on falling level.
{ 0, 0, 9, 254, 2 }, // Should predict occupancy on level rising to (near) max.
{ }
    };

// Do a simple run over the supplied data, one call per simulated minute until the terminating record is found.
// Ensures that any required predictions/detections in either direction are met.
// Uses only the update() call.
void simpleDataSampleRun(const ALDataSample *const data, OTV0P2BASE::SensorAmbientLightOccupancyDetectorInterface *const detector)
    {
    ASSERT_TRUE(NULL != data);
    ASSERT_TRUE(NULL != detector);
    ASSERT_FALSE(data->isEnd()) << "do not pass in empty data set";
    for(const ALDataSample *dp = data; !dp->isEnd(); ++dp)
        {
    	long currentMinute = dp->currentMinute();
    	do  {
            fprintf(stderr, "Mins: %ld\n", currentMinute);
            const bool prediction = detector->update(dp->L);
            const uint8_t expected = dp->expected;
            if(0 != expected)
                {
                // If a particular outcome was expected, test against it.
                const bool expectedOccupancy = (expected > 1);
                EXPECT_EQ(expectedOccupancy, prediction);
                }
            ++currentMinute;
    	    } while((!(dp+1)->isEnd()) && (currentMinute < (dp+1)->currentMinute()));
        }
	}

// Basic test of update() behaviour.
TEST(AmbientLightOccupancyDetection,simpleDataSampleRun)
{
	OTV0P2BASE::SensorAmbientLightOccupancyDetectorSimple ds1;
	simpleDataSampleRun(trivialSample1, &ds1);
}
<commit_msg>TODO-996: WIP<commit_after>/*
The OpenTRV project licenses this file to you
under the Apache Licence, Version 2.0 (the "Licence");
you may not use this file except in compliance
with the Licence. You may obtain a copy of the Licence at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the Licence is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the Licence for the
specific language governing permissions and limitations
under the Licence.

Author(s) / Copyright (s): Damon Hart-Davis 2016
*/

/*
 * Driver for OTV0P2BASE_SensorAmbientLightOccupancy tests.
 */

#include <stdint.h>
#include <gtest/gtest.h>
#include <OTV0p2Base.h>
#include "OTV0P2BASE_SensorAmbientLightOccupancy.h"

// Sanity test.
TEST(AmbientLightOccupancyDetection,SanityTest)
{
    EXPECT_EQ(42, 42);
}

// Basic test of update() behaviour.
TEST(AmbientLightOccupancyDetection,updateBasics)
{
    // Check that initial update never indicates occupancy.
	OTV0P2BASE::SensorAmbientLightOccupancyDetectorSimple ds1;
    EXPECT_FALSE(ds1.update(0)) << "no initial update should imply occupancy";
	OTV0P2BASE::SensorAmbientLightOccupancyDetectorSimple ds2;
    EXPECT_FALSE(ds2.update(255)) << "no initial update should imply occupancy";
    // Check that update from 0 to max does force occupancy indication (but steady does not).
    EXPECT_TRUE(ds1.update(255)) << "update from 0 to 255 (max) illumination should signal occupancy";
    EXPECT_FALSE(ds2.update(255)) << "unchanged 255 (max) light level should not imply occupancy";
}

class ALDataSample
    {
    public:
        const uint8_t d, H, M, L, expected;

		// Day/hour/minute and light level and expected result.
		// An expected result of 0 means no particular result expected from this (anything is acceptable).
		// An expected result of 1 means occupancy should NOT be reported for this sample.
		// An expected result of 2+ means occupancy should be reported for this sample.
	    ALDataSample(uint8_t dayOfMonth, uint8_t hour24, uint8_t minute, uint8_t lightLevel, uint8_t expectedResult = 0)
			: d(dayOfMonth), H(hour24), M(minute), L(lightLevel), expected(expectedResult)
			{ }

        // Create/mark a terminating entry; all input values invalid.
	    ALDataSample() : d(255), H(255), M(255), L(255), expected(0) { }

        // Compute current minute for this record.
        long currentMinute() const { return((((d * 24L) + H) * 60L) + M); }

	    // True for empty/termination data record.
	    bool isEnd() const { return(d > 31); }
    };

// Trivial sample, testing initial reaction to start transient.
static const ALDataSample trivialSample1[] =
    {
{ 0, 0, 0, 254, 1 }, // Should NOT predict occupancy on first tick.
{ 0, 0, 1, 0, 1 }, // Should NOT predict occupancy on falling level.
{ 0, 0, 5, 0 }, // Should NOT predict occupancy on falling level.
{ 0, 0, 9, 254, 2 }, // Should predict occupancy on level rising to (near) max.
{ }
    };

// Do a simple run over the supplied data, one call per simulated minute until the terminating record is found.
// Must be supplied in ascending order with a terminating (empty) entry.
// Repeated rows with the same light value and expected result can be omitted
// as they will be synthesised by this routine for each virtual minute until the next supplied item.
// Ensures that any required predictions/detections in either direction are met.
// Uses only the update() call.
void simpleDataSampleRun(const ALDataSample *const data, OTV0P2BASE::SensorAmbientLightOccupancyDetectorInterface *const detector)
    {
    ASSERT_TRUE(NULL != data);
    ASSERT_TRUE(NULL != detector);
    ASSERT_FALSE(data->isEnd()) << "do not pass in empty data set";
    for(const ALDataSample *dp = data; !dp->isEnd(); ++dp)
        {
    	long currentMinute = dp->currentMinute();
    	do  {
            fprintf(stderr, "Mins: %ld\n", currentMinute);
            const bool prediction = detector->update(dp->L);
            const uint8_t expected = dp->expected;
            if(0 != expected)
                {
                // If a particular outcome was expected, test against it.
                const bool expectedOccupancy = (expected > 1);
                EXPECT_EQ(expectedOccupancy, prediction);
                }
            ++currentMinute;
    	    } while((!(dp+1)->isEnd()) && (currentMinute < (dp+1)->currentMinute()));
        }
	}

// Basic test of update() behaviour.
TEST(AmbientLightOccupancyDetection,simpleDataSampleRun)
{
	OTV0P2BASE::SensorAmbientLightOccupancyDetectorSimple ds1;
	simpleDataSampleRun(trivialSample1, &ds1);
}
<|endoftext|>


<commit_before>#include <zlib.h>
#include <lcm/lcm-cpp.hpp>

#include <lcmtypes/bot_core/planar_lidar_t.hpp>
#include <lcmtypes/bot_core/pointcloud_t.hpp>
#include <lcmtypes/bot_core/pose_t.hpp>
#include <lcmtypes/bot_core/rigid_transform_t.hpp>

#include <boost/shared_ptr.hpp>
#include "lidar-odometry.hpp"
#include <ConciseArgs>

#include <bot_param/param_client.h>
#include <bot_frames/bot_frames.h>

using namespace std;

struct CommandLineConfig
{
  bool use_velodyne;
  bool init_with_message; // initialize off of a pose or vicon
  std::string output_channel;
  std::string init_channel;
};

class App{
  public:
    App(boost::shared_ptr<lcm::LCM> &lcm_, const CommandLineConfig& cl_cfg_);

    ~App(){
    }

  private:
    boost::shared_ptr<lcm::LCM> lcm_;
    const CommandLineConfig cl_cfg_;

    BotParam* botparam_;
    BotFrames* botframes_;

    void lidarHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::planar_lidar_t* msg);
    void pointCloudHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::pointcloud_t* msg);
    LidarOdom* lidarOdom_;

    Eigen::Isometry3d body_to_lidar_; // Fixed tf from the lidar to the robot's base link
    Eigen::Isometry3d world_to_body_init_; // Captures the position of the body frame in world at launch
    Eigen::Isometry3d world_to_body_now_; // running position estimate

    // Init handlers:
    void rigidTransformInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::rigid_transform_t* msg);
    void poseInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::pose_t* msg);
    void initState( const double trans[3], const double quat[4]);
    bool pose_initialized_;

    bot_core::pose_t getPoseAsBotPose(Eigen::Isometry3d pose, int64_t utime);

    int get_trans_with_utime(BotFrames *bot_frames,
        const char *from_frame, const char *to_frame, int64_t utime,
        Eigen::Isometry3d& mat);
};

App::App(boost::shared_ptr<lcm::LCM> &lcm_, const CommandLineConfig& cl_cfg_) :
       lcm_(lcm_), cl_cfg_(cl_cfg_){

  // Set up frames and config:
  botparam_ = bot_param_new_from_server(lcm_->getUnderlyingLCM(), 0);
  botframes_= bot_frames_get_global(lcm_->getUnderlyingLCM(), botparam_);

  if (cl_cfg_.use_velodyne){
    lcm_->subscribe("VELODYNE_HORIZONTAL",&App::pointCloudHandler,this);
    int status = get_trans_with_utime( botframes_ ,  "VELODYNE", "body"  , 0, body_to_lidar_);
  }else{
    lcm_->subscribe("SCAN",&App::lidarHandler,this);
    int status = get_trans_with_utime( botframes_ ,  "SCAN", "body"  , 0, body_to_lidar_);
  }

  pose_initialized_ = false;
  if (!cl_cfg_.init_with_message){
    std::cout << "Init internal est using default\n";
    world_to_body_init_ = Eigen::Isometry3d::Identity();

    /*
    world_to_body_init_.setIdentity();
    world_to_body_init_.translation()  << 1.2, 1.67, 0.32;
    Eigen::Quaterniond q(-0.045668, -0.004891, -0.00909, 0.9989);
    world_to_body_init_.rotate(q);
    bot_core::pose_t pose_msg_body = getPoseAsBotPose( world_to_lidar_init_ , 0);
    lcm_->publish("POSE_BODY_ALT", &pose_msg_body );
    pose_initialized_ = true;
    */

    pose_initialized_ = true;
  }else{
    lcm_->subscribe("VICON_BODY|VICON_FRONTPLATE",&App::rigidTransformInitHandler,this);
    lcm_->subscribe(cl_cfg_.init_channel,&App::poseInitHandler,this);
    std::cout << "Waiting for Init message to LIDAR estimator\n";
  }

  lidarOdom_ = new LidarOdom(lcm_);
}

int App::get_trans_with_utime(BotFrames *bot_frames,
        const char *from_frame, const char *to_frame, int64_t utime,
        Eigen::Isometry3d & mat){
  int status;
  double matx[16];
  status = bot_frames_get_trans_mat_4x4_with_utime( bot_frames, from_frame,  to_frame, utime, matx);
  for (int i = 0; i < 4; ++i) {
    for (int j = 0; j < 4; ++j) {
      mat(i,j) = matx[i*4+j];
    }
  }

  return status;
}

bot_core::pose_t App::getPoseAsBotPose(Eigen::Isometry3d pose, int64_t utime){
  bot_core::pose_t pose_msg;
  pose_msg.utime =   utime;
  pose_msg.pos[0] = pose.translation().x();
  pose_msg.pos[1] = pose.translation().y();
  pose_msg.pos[2] = pose.translation().z();
  Eigen::Quaterniond r_x(pose.rotation());
  pose_msg.orientation[0] =  r_x.w();
  pose_msg.orientation[1] =  r_x.x();
  pose_msg.orientation[2] =  r_x.y();
  pose_msg.orientation[3] =  r_x.z();
  return pose_msg;
}

void App::lidarHandler(const lcm::ReceiveBuffer* rbuf,
     const std::string& channel, const  bot_core::planar_lidar_t* msg){
  if (!pose_initialized_){
    std::cout << "Estimate not initialised, exiting lidarHandler\n";
    return;
  }

  // 1. Update LIDAR Odometry
  std::vector<float> ranges_copy = msg->ranges;
  float* ranges = &ranges_copy[0];
  lidarOdom_->doOdometry(ranges, msg->nranges, msg->rad0, msg->radstep, msg->utime);

  // 2. Determine the body position using the LIDAR motion estimate:
  Eigen::Isometry3d lidar_init_to_lidar_now = lidarOdom_->getCurrentPose();
  Eigen::Isometry3d world_to_lidar_now = world_to_body_init_*body_to_lidar_*lidar_init_to_lidar_now;
  world_to_body_now_ = world_to_lidar_now * body_to_lidar_.inverse();

  //bot_core::pose_t pose_msg = getPoseAsBotPose( lidar_init_to_lidar_now , msg->utime);
  //lcm_->publish("POSE_BODY_ALT", &pose_msg );
  bot_core::pose_t pose_msg_body = getPoseAsBotPose( world_to_body_now_ , msg->utime);
  lcm_->publish(cl_cfg_.output_channel, &pose_msg_body );
}

void App::pointCloudHandler(const lcm::ReceiveBuffer* rbuf,
     const std::string& channel, const  bot_core::pointcloud_t* msg){
  if (!pose_initialized_){
    std::cout << "Estimate not initialised, exiting pointCloudHandler\n";
    return;
  }

  // 1. Update LIDAR Odometry
  std::vector<float> x;
  std::vector<float> y;
  for (int i=0;i<msg->n_points; i++){
    x.push_back( msg->points[i][0] );
    y.push_back( msg->points[i][1] );
  }

  lidarOdom_->doOdometry(x, y, msg->n_points, msg->utime);

  // 2. Determine the body position using the LIDAR motion estimate:
  Eigen::Isometry3d lidar_init_to_lidar_now = lidarOdom_->getCurrentPose();
  Eigen::Isometry3d world_to_lidar_now = world_to_body_init_*body_to_lidar_*lidar_init_to_lidar_now;
  world_to_body_now_ = world_to_lidar_now * body_to_lidar_.inverse();

  //bot_core::pose_t pose_msg = getPoseAsBotPose( world_to_lidar_now , msg->utime);
  //lcm_->publish("POSE_BODY_ALT", &pose_msg );
  bot_core::pose_t pose_msg_body = getPoseAsBotPose( world_to_body_now_ , msg->utime);
  lcm_->publish(cl_cfg_.output_channel, &pose_msg_body );
}

void App::initState(const double trans[3], const double quat[4]){
  if ( !cl_cfg_.init_with_message || pose_initialized_ ){
    return;
  }

  std::cout << "Init internal est using rigid transform or pose\n";

  world_to_body_init_.setIdentity();
  world_to_body_init_.translation()  << trans[0], trans[1] , trans[2];
  Eigen::Quaterniond quatE = Eigen::Quaterniond(quat[0], quat[1],
                                               quat[2], quat[3]);
  world_to_body_init_.rotate(quatE);
  pose_initialized_ = TRUE;
}

void App::rigidTransformInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::rigid_transform_t* msg){
  initState(msg->trans, msg->quat);
}

void App::poseInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::pose_t* msg){
  initState(msg->pos, msg->orientation);
}

int main(int argc, char **argv){
  CommandLineConfig cl_cfg;
  cl_cfg.use_velodyne = false;
  cl_cfg.init_with_message = TRUE;
  cl_cfg.output_channel = "POSE_BODY";

  ConciseArgs parser(argc, argv, "simple-fusion");
  parser.add(cl_cfg.init_with_message, "g", "init_with_message", "Bootstrap internal estimate using VICON or POSE_INIT");
  parser.add(cl_cfg.output_channel, "o", "output_channel", "Output message e.g POSE_BODY");
  parser.add(cl_cfg.use_velodyne, "v", "use_velodyne", "Use a velodyne instead of the LIDAR");
  parser.add(cl_cfg.init_channel, "i", "init_channel", "Read the init message from this channel, e.g., POSE_GROUND_TRUTH");
  parser.parse();

  boost::shared_ptr<lcm::LCM> lcm(new lcm::LCM);
  if(!lcm->good()){
    std::cerr <<"ERROR: lcm is not good()" <<std::endl;
  }
  App app= App(lcm, cl_cfg);
  while(0 == lcm->handle());
}
<commit_msg>setting default value for init message<commit_after>#include <zlib.h>
#include <lcm/lcm-cpp.hpp>

#include <lcmtypes/bot_core/planar_lidar_t.hpp>
#include <lcmtypes/bot_core/pointcloud_t.hpp>
#include <lcmtypes/bot_core/pose_t.hpp>
#include <lcmtypes/bot_core/rigid_transform_t.hpp>

#include <boost/shared_ptr.hpp>
#include "lidar-odometry.hpp"
#include <ConciseArgs>

#include <bot_param/param_client.h>
#include <bot_frames/bot_frames.h>

using namespace std;

struct CommandLineConfig
{
  bool use_velodyne;
  bool init_with_message; // initialize off of a pose or vicon
  std::string output_channel;
  std::string init_channel;
};

class App{
  public:
    App(boost::shared_ptr<lcm::LCM> &lcm_, const CommandLineConfig& cl_cfg_);

    ~App(){
    }

  private:
    boost::shared_ptr<lcm::LCM> lcm_;
    const CommandLineConfig cl_cfg_;

    BotParam* botparam_;
    BotFrames* botframes_;

    void lidarHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::planar_lidar_t* msg);
    void pointCloudHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::pointcloud_t* msg);
    LidarOdom* lidarOdom_;

    Eigen::Isometry3d body_to_lidar_; // Fixed tf from the lidar to the robot's base link
    Eigen::Isometry3d world_to_body_init_; // Captures the position of the body frame in world at launch
    Eigen::Isometry3d world_to_body_now_; // running position estimate

    // Init handlers:
    void rigidTransformInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::rigid_transform_t* msg);
    void poseInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::pose_t* msg);
    void initState( const double trans[3], const double quat[4]);
    bool pose_initialized_;

    bot_core::pose_t getPoseAsBotPose(Eigen::Isometry3d pose, int64_t utime);

    int get_trans_with_utime(BotFrames *bot_frames,
        const char *from_frame, const char *to_frame, int64_t utime,
        Eigen::Isometry3d& mat);
};

App::App(boost::shared_ptr<lcm::LCM> &lcm_, const CommandLineConfig& cl_cfg_) :
       lcm_(lcm_), cl_cfg_(cl_cfg_){

  // Set up frames and config:
  botparam_ = bot_param_new_from_server(lcm_->getUnderlyingLCM(), 0);
  botframes_= bot_frames_get_global(lcm_->getUnderlyingLCM(), botparam_);

  if (cl_cfg_.use_velodyne){
    lcm_->subscribe("VELODYNE_HORIZONTAL",&App::pointCloudHandler,this);
    int status = get_trans_with_utime( botframes_ ,  "VELODYNE", "body"  , 0, body_to_lidar_);
  }else{
    lcm_->subscribe("SCAN",&App::lidarHandler,this);
    int status = get_trans_with_utime( botframes_ ,  "SCAN", "body"  , 0, body_to_lidar_);
  }

  pose_initialized_ = false;
  if (!cl_cfg_.init_with_message){
    std::cout << "Init internal est using default\n";
    world_to_body_init_ = Eigen::Isometry3d::Identity();

    /*
    world_to_body_init_.setIdentity();
    world_to_body_init_.translation()  << 1.2, 1.67, 0.32;
    Eigen::Quaterniond q(-0.045668, -0.004891, -0.00909, 0.9989);
    world_to_body_init_.rotate(q);
    bot_core::pose_t pose_msg_body = getPoseAsBotPose( world_to_lidar_init_ , 0);
    lcm_->publish("POSE_BODY_ALT", &pose_msg_body );
    pose_initialized_ = true;
    */

    pose_initialized_ = true;
  }else{
    lcm_->subscribe("VICON_BODY|VICON_FRONTPLATE",&App::rigidTransformInitHandler,this);
    lcm_->subscribe(cl_cfg_.init_channel,&App::poseInitHandler,this);
    std::cout << "Waiting for Init message to LIDAR estimator\n";
  }

  lidarOdom_ = new LidarOdom(lcm_);
}

int App::get_trans_with_utime(BotFrames *bot_frames,
        const char *from_frame, const char *to_frame, int64_t utime,
        Eigen::Isometry3d & mat){
  int status;
  double matx[16];
  status = bot_frames_get_trans_mat_4x4_with_utime( bot_frames, from_frame,  to_frame, utime, matx);
  for (int i = 0; i < 4; ++i) {
    for (int j = 0; j < 4; ++j) {
      mat(i,j) = matx[i*4+j];
    }
  }

  return status;
}

bot_core::pose_t App::getPoseAsBotPose(Eigen::Isometry3d pose, int64_t utime){
  bot_core::pose_t pose_msg;
  pose_msg.utime =   utime;
  pose_msg.pos[0] = pose.translation().x();
  pose_msg.pos[1] = pose.translation().y();
  pose_msg.pos[2] = pose.translation().z();
  Eigen::Quaterniond r_x(pose.rotation());
  pose_msg.orientation[0] =  r_x.w();
  pose_msg.orientation[1] =  r_x.x();
  pose_msg.orientation[2] =  r_x.y();
  pose_msg.orientation[3] =  r_x.z();
  return pose_msg;
}

void App::lidarHandler(const lcm::ReceiveBuffer* rbuf,
     const std::string& channel, const  bot_core::planar_lidar_t* msg){
  if (!pose_initialized_){
    std::cout << "Estimate not initialised, exiting lidarHandler\n";
    return;
  }

  // 1. Update LIDAR Odometry
  std::vector<float> ranges_copy = msg->ranges;
  float* ranges = &ranges_copy[0];
  lidarOdom_->doOdometry(ranges, msg->nranges, msg->rad0, msg->radstep, msg->utime);

  // 2. Determine the body position using the LIDAR motion estimate:
  Eigen::Isometry3d lidar_init_to_lidar_now = lidarOdom_->getCurrentPose();
  Eigen::Isometry3d world_to_lidar_now = world_to_body_init_*body_to_lidar_*lidar_init_to_lidar_now;
  world_to_body_now_ = world_to_lidar_now * body_to_lidar_.inverse();

  //bot_core::pose_t pose_msg = getPoseAsBotPose( lidar_init_to_lidar_now , msg->utime);
  //lcm_->publish("POSE_BODY_ALT", &pose_msg );
  bot_core::pose_t pose_msg_body = getPoseAsBotPose( world_to_body_now_ , msg->utime);
  lcm_->publish(cl_cfg_.output_channel, &pose_msg_body );
}

void App::pointCloudHandler(const lcm::ReceiveBuffer* rbuf,
     const std::string& channel, const  bot_core::pointcloud_t* msg){
  if (!pose_initialized_){
    std::cout << "Estimate not initialised, exiting pointCloudHandler\n";
    return;
  }

  // 1. Update LIDAR Odometry
  std::vector<float> x;
  std::vector<float> y;
  for (int i=0;i<msg->n_points; i++){
    x.push_back( msg->points[i][0] );
    y.push_back( msg->points[i][1] );
  }

  lidarOdom_->doOdometry(x, y, msg->n_points, msg->utime);

  // 2. Determine the body position using the LIDAR motion estimate:
  Eigen::Isometry3d lidar_init_to_lidar_now = lidarOdom_->getCurrentPose();
  Eigen::Isometry3d world_to_lidar_now = world_to_body_init_*body_to_lidar_*lidar_init_to_lidar_now;
  world_to_body_now_ = world_to_lidar_now * body_to_lidar_.inverse();

  //bot_core::pose_t pose_msg = getPoseAsBotPose( world_to_lidar_now , msg->utime);
  //lcm_->publish("POSE_BODY_ALT", &pose_msg );
  bot_core::pose_t pose_msg_body = getPoseAsBotPose( world_to_body_now_ , msg->utime);
  lcm_->publish(cl_cfg_.output_channel, &pose_msg_body );
}

void App::initState(const double trans[3], const double quat[4]){
  if ( !cl_cfg_.init_with_message || pose_initialized_ ){
    return;
  }

  std::cout << "Init internal est using rigid transform or pose\n";

  world_to_body_init_.setIdentity();
  world_to_body_init_.translation()  << trans[0], trans[1] , trans[2];
  Eigen::Quaterniond quatE = Eigen::Quaterniond(quat[0], quat[1],
                                               quat[2], quat[3]);
  world_to_body_init_.rotate(quatE);
  pose_initialized_ = TRUE;
}

void App::rigidTransformInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::rigid_transform_t* msg){
  initState(msg->trans, msg->quat);
}

void App::poseInitHandler(const lcm::ReceiveBuffer* rbuf, const std::string& channel, const  bot_core::pose_t* msg){
  initState(msg->pos, msg->orientation);
}

int main(int argc, char **argv){
  CommandLineConfig cl_cfg;
  cl_cfg.use_velodyne = false;
  cl_cfg.init_with_message = TRUE;
  cl_cfg.output_channel = "POSE_BODY";
  cl_cfg.init_channel = "POSE_GROUND_TRUTH";

  ConciseArgs parser(argc, argv, "simple-fusion");
  parser.add(cl_cfg.init_with_message, "g", "init_with_message", "Bootstrap internal estimate using VICON or POSE_INIT");
  parser.add(cl_cfg.output_channel, "o", "output_channel", "Output message e.g POSE_BODY");
  parser.add(cl_cfg.use_velodyne, "v", "use_velodyne", "Use a velodyne instead of the LIDAR");
  parser.add(cl_cfg.init_channel, "i", "init_channel", "Read the init message from this channel, e.g., POSE_GROUND_TRUTH");
  parser.parse();

  boost::shared_ptr<lcm::LCM> lcm(new lcm::LCM);
  if(!lcm->good()){
    std::cerr <<"ERROR: lcm is not good()" <<std::endl;
  }
  App app= App(lcm, cl_cfg);
  while(0 == lcm->handle());
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/chrome_paths.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"

#if defined(OS_MACOSX)
#include "base/mac_util.h"
#endif

namespace {

// File name of the internal Flash plugin on different platforms.
const FilePath::CharType kInternalFlashPluginFileName[] =
#if defined(OS_MACOSX)
    FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin");
#elif defined(OS_WIN)
    FILE_PATH_LITERAL("gcswf32.dll");
#else  // OS_LINUX, etc.
    FILE_PATH_LITERAL("libgcflashplayer.so");
#endif

}  // namespace

namespace chrome {

// Gets the path for internal (or bundled) plugins.
bool GetInternalPluginsDirectory(FilePath* result) {
#if defined(OS_MACOSX)
  // If called from Chrome, get internal plugins from the versioned directory.
  if (mac_util::AmIBundled()) {
    *result = chrome::GetVersionedDirectory();
    DCHECK(!result->empty());
    return true;
  }
  // In tests, just look in the module directory (below).
#endif

  // The rest of the world expects plugins in the module directory.
  return PathService::Get(base::DIR_MODULE, result);
}

bool GetGearsPluginPathFromCommandLine(FilePath* path) {
#ifndef NDEBUG
  // for debugging, support a cmd line based override
  FilePath plugin_path =
      CommandLine::ForCurrentProcess()->GetSwitchValuePath(
          switches::kGearsPluginPathOverride);
  *path = plugin_path;
  return !plugin_path.empty();
#else
  return false;
#endif
}

bool PathProvider(int key, FilePath* result) {
  // Some keys are just aliases...
  switch (key) {
    case chrome::DIR_APP:
      return PathService::Get(base::DIR_MODULE, result);
    case chrome::DIR_LOGS:
#ifdef NDEBUG
      // Release builds write to the data dir
      return PathService::Get(chrome::DIR_USER_DATA, result);
#else
      // Debug builds write next to the binary (in the build tree)
#if defined(OS_MACOSX)
      if (!PathService::Get(base::DIR_EXE, result))
        return false;
      if (mac_util::AmIBundled()) {
        // If we're called from chrome, dump it beside the app (outside the
        // app bundle), if we're called from a unittest, we'll already
        // outside the bundle so use the exe dir.
        // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium.
        *result = result->DirName();
        *result = result->DirName();
        *result = result->DirName();
      }
      return true;
#else
      return PathService::Get(base::DIR_EXE, result);
#endif  // defined(OS_MACOSX)
#endif  // NDEBUG
    case chrome::FILE_RESOURCE_MODULE:
      return PathService::Get(base::FILE_MODULE, result);
  }

  // Assume that we will not need to create the directory if it does not exist.
  // This flag can be set to true for the cases where we want to create it.
  bool create_dir = false;

  FilePath cur;
  switch (key) {
    case chrome::DIR_USER_DATA:
      if (!GetDefaultUserDataDirectory(&cur)) {
        NOTREACHED();
        return false;
      }
      create_dir = true;
      break;
    case chrome::DIR_USER_DOCUMENTS:
      if (!GetUserDocumentsDirectory(&cur))
        return false;
      create_dir = true;
      break;
    case chrome::DIR_DEFAULT_DOWNLOADS_SAFE:
#if defined(OS_WIN)
      if (!GetUserDownloadsDirectorySafe(&cur))
        return false;
      break;
#else
      // Fall through for all other platforms.
#endif
    case chrome::DIR_DEFAULT_DOWNLOADS:
      if (!GetUserDownloadsDirectory(&cur))
        return false;
      // Do not create the download directory here, we have done it twice now
      // and annoyed a lot of users.
      break;
    case chrome::DIR_CRASH_DUMPS:
      // The crash reports are always stored relative to the default user data
      // directory.  This avoids the problem of having to re-initialize the
      // exception handler after parsing command line options, which may
      // override the location of the app's profile directory.
      if (!GetDefaultUserDataDirectory(&cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("Crash Reports"));
      create_dir = true;
      break;
    case chrome::DIR_USER_DESKTOP:
      if (!GetUserDesktop(&cur))
        return false;
      break;
    case chrome::DIR_RESOURCES:
#if defined(OS_MACOSX)
      cur = mac_util::MainAppBundlePath();
      cur = cur.Append(FILE_PATH_LITERAL("Resources"));
#else
      if (!PathService::Get(chrome::DIR_APP, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("resources"));
#endif
      break;
    case chrome::DIR_SHARED_RESOURCES:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("shared"));
      break;
    case chrome::DIR_BOOKMARK_MANAGER:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("bookmark_manager"));
      break;
    case chrome::DIR_INSPECTOR:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("inspector"));
      break;
    case chrome::DIR_NET_INTERNALS:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("net_internals"));
      break;
    case chrome::DIR_APP_DICTIONARIES:
#if defined(OS_LINUX) || defined(OS_MACOSX)
      // We can't write into the EXE dir on Linux, so keep dictionaries
      // alongside the safe browsing database in the user data dir.
      // And we don't want to write into the bundle on the Mac, so push
      // it to the user data dir there also.
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
#else
      if (!PathService::Get(base::DIR_EXE, &cur))
        return false;
#endif
      cur = cur.Append(FILE_PATH_LITERAL("Dictionaries"));
      create_dir = true;
      break;
    case chrome::DIR_USER_DATA_TEMP:
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("Temp"));
      create_dir = true;
      break;
    case chrome::DIR_INTERNAL_PLUGINS:
      if (!GetInternalPluginsDirectory(&cur))
        return false;
      break;
    case chrome::FILE_LOCAL_STATE:
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
      cur = cur.Append(chrome::kLocalStateFilename);
      break;
    case chrome::FILE_RECORDED_SCRIPT:
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("script.log"));
      break;
    case chrome::FILE_GEARS_PLUGIN:
      if (!GetGearsPluginPathFromCommandLine(&cur)) {
#if defined(OS_WIN)
        // Search for gears.dll alongside chrome.dll first.  This new model
        // allows us to package gears.dll with the Chrome installer and update
        // it while Chrome is running.
        if (!GetInternalPluginsDirectory(&cur))
          return false;
        cur = cur.Append(FILE_PATH_LITERAL("gears.dll"));

        if (!file_util::PathExists(cur)) {
          if (!PathService::Get(base::DIR_EXE, &cur))
            return false;
          cur = cur.Append(FILE_PATH_LITERAL("plugins"));
          cur = cur.Append(FILE_PATH_LITERAL("gears"));
          cur = cur.Append(FILE_PATH_LITERAL("gears.dll"));
        }
#else
        // No gears.dll on non-Windows systems.
        return false;
#endif
      }
      break;
    case chrome::FILE_FLASH_PLUGIN:
      if (!GetInternalPluginsDirectory(&cur))
        return false;
      cur = cur.Append(kInternalFlashPluginFileName);
      if (!file_util::PathExists(cur))
        return false;
      break;
    case chrome::FILE_PDF_PLUGIN:
      if (!PathService::Get(base::DIR_MODULE, &cur))
        return false;
#if defined(OS_WIN)
      cur = cur.Append(FILE_PATH_LITERAL("pdf.dll"));
#elif defined(OS_MACOSX)
      NOTIMPLEMENTED();
      return false;
#else  // Linux and Chrome OS
      cur = cur.Append(FILE_PATH_LITERAL("libpdf.so"));
#endif
      if (!file_util::PathExists(cur))
        return false;
      break;
#if defined(OS_CHROMEOS)
    case chrome::FILE_CHROMEOS_API:
      if (!PathService::Get(base::DIR_MODULE, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("chromeos"));
      cur = cur.Append(FILE_PATH_LITERAL("libcros.so"));
      break;
#endif
    // The following are only valid in the development environment, and
    // will fail if executed from an installed executable (because the
    // generated path won't exist).
    case chrome::DIR_TEST_DATA:
      if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("chrome"));
      cur = cur.Append(FILE_PATH_LITERAL("test"));
      cur = cur.Append(FILE_PATH_LITERAL("data"));
      if (!file_util::PathExists(cur))  // we don't want to create this
        return false;
      break;
    case chrome::DIR_TEST_TOOLS:
      if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("chrome"));
      cur = cur.Append(FILE_PATH_LITERAL("tools"));
      cur = cur.Append(FILE_PATH_LITERAL("test"));
      if (!file_util::PathExists(cur))  // we don't want to create this
        return false;
      break;
    default:
      return false;
  }

  if (create_dir && !file_util::PathExists(cur) &&
      !file_util::CreateDirectory(cur))
    return false;

  *result = cur;
  return true;
}

// This cannot be done as a static initializer sadly since Visual Studio will
// eliminate this object file if there is no direct entry point into it.
void RegisterPathProvider() {
  PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
}

}  // namespace chrome
<commit_msg>[Mac] stop the output that is slowing down all the tests that seem to walk this code path.<commit_after>// Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/common/chrome_paths.h"

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "base/string_util.h"
#include "base/sys_info.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths_internal.h"
#include "chrome/common/chrome_switches.h"

#if defined(OS_MACOSX)
#include "base/mac_util.h"
#endif

namespace {

// File name of the internal Flash plugin on different platforms.
const FilePath::CharType kInternalFlashPluginFileName[] =
#if defined(OS_MACOSX)
    FILE_PATH_LITERAL("Flash Player Plugin for Chrome.plugin");
#elif defined(OS_WIN)
    FILE_PATH_LITERAL("gcswf32.dll");
#else  // OS_LINUX, etc.
    FILE_PATH_LITERAL("libgcflashplayer.so");
#endif

}  // namespace

namespace chrome {

// Gets the path for internal (or bundled) plugins.
bool GetInternalPluginsDirectory(FilePath* result) {
#if defined(OS_MACOSX)
  // If called from Chrome, get internal plugins from the versioned directory.
  if (mac_util::AmIBundled()) {
    *result = chrome::GetVersionedDirectory();
    DCHECK(!result->empty());
    return true;
  }
  // In tests, just look in the module directory (below).
#endif

  // The rest of the world expects plugins in the module directory.
  return PathService::Get(base::DIR_MODULE, result);
}

bool GetGearsPluginPathFromCommandLine(FilePath* path) {
#ifndef NDEBUG
  // for debugging, support a cmd line based override
  FilePath plugin_path =
      CommandLine::ForCurrentProcess()->GetSwitchValuePath(
          switches::kGearsPluginPathOverride);
  *path = plugin_path;
  return !plugin_path.empty();
#else
  return false;
#endif
}

bool PathProvider(int key, FilePath* result) {
  // Some keys are just aliases...
  switch (key) {
    case chrome::DIR_APP:
      return PathService::Get(base::DIR_MODULE, result);
    case chrome::DIR_LOGS:
#ifdef NDEBUG
      // Release builds write to the data dir
      return PathService::Get(chrome::DIR_USER_DATA, result);
#else
      // Debug builds write next to the binary (in the build tree)
#if defined(OS_MACOSX)
      if (!PathService::Get(base::DIR_EXE, result))
        return false;
      if (mac_util::AmIBundled()) {
        // If we're called from chrome, dump it beside the app (outside the
        // app bundle), if we're called from a unittest, we'll already
        // outside the bundle so use the exe dir.
        // exe_dir gave us .../Chromium.app/Contents/MacOS/Chromium.
        *result = result->DirName();
        *result = result->DirName();
        *result = result->DirName();
      }
      return true;
#else
      return PathService::Get(base::DIR_EXE, result);
#endif  // defined(OS_MACOSX)
#endif  // NDEBUG
    case chrome::FILE_RESOURCE_MODULE:
      return PathService::Get(base::FILE_MODULE, result);
  }

  // Assume that we will not need to create the directory if it does not exist.
  // This flag can be set to true for the cases where we want to create it.
  bool create_dir = false;

  FilePath cur;
  switch (key) {
    case chrome::DIR_USER_DATA:
      if (!GetDefaultUserDataDirectory(&cur)) {
        NOTREACHED();
        return false;
      }
      create_dir = true;
      break;
    case chrome::DIR_USER_DOCUMENTS:
      if (!GetUserDocumentsDirectory(&cur))
        return false;
      create_dir = true;
      break;
    case chrome::DIR_DEFAULT_DOWNLOADS_SAFE:
#if defined(OS_WIN)
      if (!GetUserDownloadsDirectorySafe(&cur))
        return false;
      break;
#else
      // Fall through for all other platforms.
#endif
    case chrome::DIR_DEFAULT_DOWNLOADS:
      if (!GetUserDownloadsDirectory(&cur))
        return false;
      // Do not create the download directory here, we have done it twice now
      // and annoyed a lot of users.
      break;
    case chrome::DIR_CRASH_DUMPS:
      // The crash reports are always stored relative to the default user data
      // directory.  This avoids the problem of having to re-initialize the
      // exception handler after parsing command line options, which may
      // override the location of the app's profile directory.
      if (!GetDefaultUserDataDirectory(&cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("Crash Reports"));
      create_dir = true;
      break;
    case chrome::DIR_USER_DESKTOP:
      if (!GetUserDesktop(&cur))
        return false;
      break;
    case chrome::DIR_RESOURCES:
#if defined(OS_MACOSX)
      cur = mac_util::MainAppBundlePath();
      cur = cur.Append(FILE_PATH_LITERAL("Resources"));
#else
      if (!PathService::Get(chrome::DIR_APP, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("resources"));
#endif
      break;
    case chrome::DIR_SHARED_RESOURCES:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("shared"));
      break;
    case chrome::DIR_BOOKMARK_MANAGER:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("bookmark_manager"));
      break;
    case chrome::DIR_INSPECTOR:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("inspector"));
      break;
    case chrome::DIR_NET_INTERNALS:
      if (!PathService::Get(chrome::DIR_RESOURCES, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("net_internals"));
      break;
    case chrome::DIR_APP_DICTIONARIES:
#if defined(OS_LINUX) || defined(OS_MACOSX)
      // We can't write into the EXE dir on Linux, so keep dictionaries
      // alongside the safe browsing database in the user data dir.
      // And we don't want to write into the bundle on the Mac, so push
      // it to the user data dir there also.
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
#else
      if (!PathService::Get(base::DIR_EXE, &cur))
        return false;
#endif
      cur = cur.Append(FILE_PATH_LITERAL("Dictionaries"));
      create_dir = true;
      break;
    case chrome::DIR_USER_DATA_TEMP:
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("Temp"));
      create_dir = true;
      break;
    case chrome::DIR_INTERNAL_PLUGINS:
      if (!GetInternalPluginsDirectory(&cur))
        return false;
      break;
    case chrome::FILE_LOCAL_STATE:
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
      cur = cur.Append(chrome::kLocalStateFilename);
      break;
    case chrome::FILE_RECORDED_SCRIPT:
      if (!PathService::Get(chrome::DIR_USER_DATA, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("script.log"));
      break;
    case chrome::FILE_GEARS_PLUGIN:
      if (!GetGearsPluginPathFromCommandLine(&cur)) {
#if defined(OS_WIN)
        // Search for gears.dll alongside chrome.dll first.  This new model
        // allows us to package gears.dll with the Chrome installer and update
        // it while Chrome is running.
        if (!GetInternalPluginsDirectory(&cur))
          return false;
        cur = cur.Append(FILE_PATH_LITERAL("gears.dll"));

        if (!file_util::PathExists(cur)) {
          if (!PathService::Get(base::DIR_EXE, &cur))
            return false;
          cur = cur.Append(FILE_PATH_LITERAL("plugins"));
          cur = cur.Append(FILE_PATH_LITERAL("gears"));
          cur = cur.Append(FILE_PATH_LITERAL("gears.dll"));
        }
#else
        // No gears.dll on non-Windows systems.
        return false;
#endif
      }
      break;
    case chrome::FILE_FLASH_PLUGIN:
      if (!GetInternalPluginsDirectory(&cur))
        return false;
      cur = cur.Append(kInternalFlashPluginFileName);
      if (!file_util::PathExists(cur))
        return false;
      break;
    case chrome::FILE_PDF_PLUGIN:
      if (!PathService::Get(base::DIR_MODULE, &cur))
        return false;
#if defined(OS_WIN)
      cur = cur.Append(FILE_PATH_LITERAL("pdf.dll"));
#elif defined(OS_MACOSX)
      // http://crbug.com/44900
      return false;
#else  // Linux and Chrome OS
      cur = cur.Append(FILE_PATH_LITERAL("libpdf.so"));
#endif
      if (!file_util::PathExists(cur))
        return false;
      break;
#if defined(OS_CHROMEOS)
    case chrome::FILE_CHROMEOS_API:
      if (!PathService::Get(base::DIR_MODULE, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("chromeos"));
      cur = cur.Append(FILE_PATH_LITERAL("libcros.so"));
      break;
#endif
    // The following are only valid in the development environment, and
    // will fail if executed from an installed executable (because the
    // generated path won't exist).
    case chrome::DIR_TEST_DATA:
      if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("chrome"));
      cur = cur.Append(FILE_PATH_LITERAL("test"));
      cur = cur.Append(FILE_PATH_LITERAL("data"));
      if (!file_util::PathExists(cur))  // we don't want to create this
        return false;
      break;
    case chrome::DIR_TEST_TOOLS:
      if (!PathService::Get(base::DIR_SOURCE_ROOT, &cur))
        return false;
      cur = cur.Append(FILE_PATH_LITERAL("chrome"));
      cur = cur.Append(FILE_PATH_LITERAL("tools"));
      cur = cur.Append(FILE_PATH_LITERAL("test"));
      if (!file_util::PathExists(cur))  // we don't want to create this
        return false;
      break;
    default:
      return false;
  }

  if (create_dir && !file_util::PathExists(cur) &&
      !file_util::CreateDirectory(cur))
    return false;

  *result = cur;
  return true;
}

// This cannot be done as a static initializer sadly since Visual Studio will
// eliminate this object file if there is no direct entry point into it.
void RegisterPathProvider() {
  PathService::RegisterProvider(PathProvider, PATH_START, PATH_END);
}

}  // namespace chrome
<|endoftext|>


<commit_before>#include <string>
#include "nbind/api.h"
#include "control.h"
#include "ui.h"
#include "values.h"

class UiWindow {
	DEFINE_EVENT(onClosing)
	DEFINE_EVENT(onContentSizeChanged)

  private:
	uiWindow *win;

  public:
	UiWindow(std::string title, int width, int height, bool hasMenubar);
	uiWindow *getHandle();
	void show();
	void close();
	void setMargined(bool margined);
	bool getMargined();
	void setChild(UiControl *control);
	void setTitle(std::string title);
	std::string getTitle();
	bool getFullscreen();
	void setFullscreen(bool value);
	bool getBorderless();
	void setBorderless(bool value);
	Size getContentSize();
	void setContentSize(Size value);
};

static int UiWindow_onClosing(uiWindow *w, void *data) {
	nbind::cbFunction *cb = (nbind::cbFunction *)data;
	(*cb)();
	return 0;
}

void UiWindow::onClosing(nbind::cbFunction &cb) {
	onClosingCallback = new nbind::cbFunction(cb);
	uiWindowOnClosing(uiWindow(getHandle()), UiWindow_onClosing,
					  onClosingCallback);
}

static void UiWindow_onContentSizeChanged(uiWindow *w, void *data) {
	nbind::cbFunction *cb = (nbind::cbFunction *)data;
	(*cb)();
}

void UiWindow::onContentSizeChanged(nbind::cbFunction &cb) {
	onContentSizeChangedCallback = new nbind::cbFunction(cb);
	uiWindowOnContentSizeChanged(uiWindow(getHandle()),
								 UiWindow_onContentSizeChanged,
								 onContentSizeChangedCallback);
}

UiWindow::UiWindow(std::string title, int width, int height, bool hasMenubar) {
	win = uiNewWindow(title.c_str(), width, height, hasMenubar);
}

uiWindow *UiWindow::getHandle() {
	return win;
}

void UiWindow::show() {
	uiControlShow(uiControl(win));
}

void UiWindow::close() {
	uiControlDestroy(uiControl(win));
}

void UiWindow::setMargined(bool margined) {
	uiWindowSetMargined(win, margined);
}

bool UiWindow::getMargined() {
	return uiWindowMargined(win);
}

void UiWindow::setChild(UiControl *control) {
	uiWindowSetChild(win, control->getHandle());
}

void UiWindow::setTitle(std::string title) {
	uiWindowSetTitle(win, title.c_str());
}

std::string UiWindow::getTitle() {
	char *char_ptr = uiWindowTitle(win);
	std::string s(char_ptr);
	uiFreeText(char_ptr);
	return s;
}

bool UiWindow::getFullscreen() {
	return uiWindowFullscreen(win);
}

void UiWindow::setFullscreen(bool value) {
	uiWindowSetFullscreen(win, value);
}

void UiWindow::setBorderless(bool value) {
	uiWindowSetBorderless(win, value);
}
bool UiWindow::getBorderless() {
	return uiWindowBorderless(win);
}

void UiWindow::setContentSize(Size value) {
	uiWindowSetContentSize(win, value.getWidth(), value.getHeight());
}

Size UiWindow::getContentSize() {
	int w = 0;
	int h = 0;
	uiWindowContentSize(win, &w, &h);
	return Size(w, h);
}

NBIND_CLASS(UiWindow) {
	construct<std::string, int, int, bool>();
	method(show);
	method(close);
	method(setChild);
	method(onClosing);
	method(onContentSizeChanged);
	getset(getMargined, setMargined);
	getset(getTitle, setTitle);

	getset(getContentSize, setContentSize);
	method(getContentSize);
	method(setContentSize);
	method(onContentSizeChanged);

	getset(getFullscreen, setFullscreen);
	method(getFullscreen);
	method(setFullscreen);
	getset(getBorderless, setBorderless);
	method(getBorderless);
	method(setBorderless);
}

struct UiDialogs {

	static std::string openFile(UiWindow *parent) {
		char *char_ptr = uiOpenFile(parent->getHandle());
		std::string s(char_ptr);
		uiFreeText(char_ptr);
		return s;
	}

	static std::string saveFile(UiWindow *parent) {
		char *char_ptr = uiSaveFile(parent->getHandle());
		std::string s(char_ptr);
		uiFreeText(char_ptr);
		return s;
	}

	static void msgBox(UiWindow *parent, std::string title,
					   std::string description) {
		uiMsgBox(parent->getHandle(), title.c_str(), description.c_str());
	}

	static void msgBoxError(UiWindow *parent, std::string title,
							std::string description) {
		uiMsgBoxError(parent->getHandle(), title.c_str(), description.c_str());
	}
};

NBIND_CLASS(UiDialogs) {
	method(openFile);
	method(saveFile);
	method(msgBox);
	method(msgBoxError);
}
<commit_msg>Freeing event callbacks on close to allow JS to garbage collect UiWindow<commit_after>#include <string>
#include "nbind/api.h"
#include "control.h"
#include "ui.h"
#include "values.h"

class UiWindow {
	DEFINE_EVENT(onClosing)
	DEFINE_EVENT(onContentSizeChanged)

  private:
	uiWindow *win;

  public:
	UiWindow(std::string title, int width, int height, bool hasMenubar);
	uiWindow *getHandle();
	void show();
	void close();
	void setMargined(bool margined);
	bool getMargined();
	void setChild(UiControl *control);
	void setTitle(std::string title);
	std::string getTitle();
	bool getFullscreen();
	void setFullscreen(bool value);
	bool getBorderless();
	void setBorderless(bool value);
	Size getContentSize();
	void setContentSize(Size value);
};

static int UiWindow_onClosing(uiWindow *w, void *data) {
	nbind::cbFunction *cb = (nbind::cbFunction *)data;
	(*cb)();
	return 0;
}

void UiWindow::onClosing(nbind::cbFunction &cb) {
	onClosingCallback = new nbind::cbFunction(cb);
	uiWindowOnClosing(uiWindow(getHandle()), UiWindow_onClosing,
					  onClosingCallback);
}

static void UiWindow_onContentSizeChanged(uiWindow *w, void *data) {
	nbind::cbFunction *cb = (nbind::cbFunction *)data;
	(*cb)();
}

void UiWindow::onContentSizeChanged(nbind::cbFunction &cb) {
	onContentSizeChangedCallback = new nbind::cbFunction(cb);
	uiWindowOnContentSizeChanged(uiWindow(getHandle()),
								 UiWindow_onContentSizeChanged,
								 onContentSizeChangedCallback);
}

UiWindow::UiWindow(std::string title, int width, int height, bool hasMenubar) {
	win = uiNewWindow(title.c_str(), width, height, hasMenubar);
}

uiWindow *UiWindow::getHandle() {
	return win;
}

void UiWindow::show() {
	uiControlShow(uiControl(win));
}

void UiWindow::close() {
	uiControlDestroy(uiControl(win));
	/*
		freeing event callbacks to allow JS to garbage collect this class
		when there are no references to it left in JS code.
	*/
	if (onClosingCallback != nullptr) {
		delete onClosingCallback;
		onClosingCallback = nullptr;
	}

	if (onContentSizeChangedCallback != nullptr) {
		delete onContentSizeChangedCallback;
		onContentSizeChangedCallback = nullptr;
	}
}

void UiWindow::setMargined(bool margined) {
	uiWindowSetMargined(win, margined);
}

bool UiWindow::getMargined() {
	return uiWindowMargined(win);
}

void UiWindow::setChild(UiControl *control) {
	uiWindowSetChild(win, control->getHandle());
}

void UiWindow::setTitle(std::string title) {
	uiWindowSetTitle(win, title.c_str());
}

std::string UiWindow::getTitle() {
	char *char_ptr = uiWindowTitle(win);
	std::string s(char_ptr);
	uiFreeText(char_ptr);
	return s;
}

bool UiWindow::getFullscreen() {
	return uiWindowFullscreen(win);
}

void UiWindow::setFullscreen(bool value) {
	uiWindowSetFullscreen(win, value);
}

void UiWindow::setBorderless(bool value) {
	uiWindowSetBorderless(win, value);
}
bool UiWindow::getBorderless() {
	return uiWindowBorderless(win);
}

void UiWindow::setContentSize(Size value) {
	uiWindowSetContentSize(win, value.getWidth(), value.getHeight());
}

Size UiWindow::getContentSize() {
	int w = 0;
	int h = 0;
	uiWindowContentSize(win, &w, &h);
	return Size(w, h);
}

NBIND_CLASS(UiWindow) {
	construct<std::string, int, int, bool>();
	method(show);
	method(close);
	method(setChild);
	method(onClosing);
	method(onContentSizeChanged);
	getset(getMargined, setMargined);
	getset(getTitle, setTitle);

	getset(getContentSize, setContentSize);
	method(getContentSize);
	method(setContentSize);
	method(onContentSizeChanged);

	getset(getFullscreen, setFullscreen);
	method(getFullscreen);
	method(setFullscreen);
	getset(getBorderless, setBorderless);
	method(getBorderless);
	method(setBorderless);
}

struct UiDialogs {

	static std::string openFile(UiWindow *parent) {
		char *char_ptr = uiOpenFile(parent->getHandle());
		std::string s(char_ptr);
		uiFreeText(char_ptr);
		return s;
	}

	static std::string saveFile(UiWindow *parent) {
		char *char_ptr = uiSaveFile(parent->getHandle());
		std::string s(char_ptr);
		uiFreeText(char_ptr);
		return s;
	}

	static void msgBox(UiWindow *parent, std::string title,
					   std::string description) {
		uiMsgBox(parent->getHandle(), title.c_str(), description.c_str());
	}

	static void msgBoxError(UiWindow *parent, std::string title,
							std::string description) {
		uiMsgBoxError(parent->getHandle(), title.c_str(), description.c_str());
	}
};

NBIND_CLASS(UiDialogs) {
	method(openFile);
	method(saveFile);
	method(msgBox);
	method(msgBoxError);
}
<|endoftext|>