<commit_before>/*
 *
 * Copyright 2016, 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 <memory>
#include <mutex>

#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/generic/async_generic_service.h>
#include <grpc++/generic/generic_stub.h>
#include <grpc++/impl/codegen/proto_utils.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/support/config.h>
#include <grpc++/support/slice.h>
#include <grpc/grpc.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include <gtest/gtest.h>

#include "src/cpp/common/channel_filter.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/byte_buffer_proto_helper.h"

using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
using std::chrono::system_clock;

namespace grpc {
namespace testing {
namespace {

void* tag(int i) { return (void*)(intptr_t)i; }

void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
  bool ok;
  void* got_tag;
  EXPECT_TRUE(cq->Next(&got_tag, &ok));
  EXPECT_EQ(expect_ok, ok);
  EXPECT_EQ(tag(i), got_tag);
}

namespace {

int global_num_connections = 0;
int global_num_calls = 0;
mutex global_mu;

void IncrementConnectionCounter() {
  unique_lock<mutex> lock(global_mu);
  ++global_num_connections;
}

void ResetConnectionCounter() {
  unique_lock<mutex> lock(global_mu);
  global_num_connections = 0;
}

int GetConnectionCounterValue() {
  unique_lock<mutex> lock(global_mu);
  return global_num_connections;
}

void IncrementCallCounter() {
  unique_lock<mutex> lock(global_mu);
  ++global_num_calls;
}

void ResetCallCounter() {
  unique_lock<mutex> lock(global_mu);
  global_num_calls = 0;
}

int GetCallCounterValue() {
  unique_lock<mutex> lock(global_mu);
  return global_num_calls;
}

}  // namespace

class ChannelDataImpl : public ChannelData {
 public:
  ChannelDataImpl(const grpc_channel_args& args, const char* peer)
      : ChannelData(args, peer) {
    IncrementConnectionCounter();
  }
};

class CallDataImpl : public CallData {
 public:
  explicit CallDataImpl(const ChannelDataImpl& channel_data)
      : CallData(channel_data) {}

  void StartTransportStreamOp(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                              TransportStreamOp* op) GRPC_OVERRIDE {
    // Incrementing the counter could be done from the ctor, but we want
    // to test that the individual methods are actually called correctly.
    if (op->recv_initial_metadata() != nullptr) IncrementCallCounter();
    grpc_call_next_op(exec_ctx, elem, op->op());
  }
};

class FilterEnd2endTest : public ::testing::Test {
 protected:
  FilterEnd2endTest() : server_host_("localhost") {}

  void SetUp() GRPC_OVERRIDE {
    int port = grpc_pick_unused_port_or_die();
    server_address_ << server_host_ << ":" << port;
    // Setup server
    ServerBuilder builder;
    builder.AddListeningPort(server_address_.str(),
                             InsecureServerCredentials());
    builder.RegisterAsyncGenericService(&generic_service_);
    srv_cq_ = builder.AddCompletionQueue();
    server_ = builder.BuildAndStart();
  }

  void TearDown() GRPC_OVERRIDE {
    server_->Shutdown();
    void* ignored_tag;
    bool ignored_ok;
    cli_cq_.Shutdown();
    srv_cq_->Shutdown();
    while (cli_cq_.Next(&ignored_tag, &ignored_ok))
      ;
    while (srv_cq_->Next(&ignored_tag, &ignored_ok))
      ;
  }

  void ResetStub() {
    std::shared_ptr<Channel> channel =
        CreateChannel(server_address_.str(), InsecureChannelCredentials());
    generic_stub_.reset(new GenericStub(channel));
    ResetConnectionCounter();
    ResetCallCounter();
  }

  void server_ok(int i) { verify_ok(srv_cq_.get(), i, true); }
  void client_ok(int i) { verify_ok(&cli_cq_, i, true); }
  void server_fail(int i) { verify_ok(srv_cq_.get(), i, false); }
  void client_fail(int i) { verify_ok(&cli_cq_, i, false); }

  void SendRpc(int num_rpcs) {
    const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo");
    for (int i = 0; i < num_rpcs; i++) {
      EchoRequest send_request;
      EchoRequest recv_request;
      EchoResponse send_response;
      EchoResponse recv_response;
      Status recv_status;

      ClientContext cli_ctx;
      GenericServerContext srv_ctx;
      GenericServerAsyncReaderWriter stream(&srv_ctx);

      // The string needs to be long enough to test heap-based slice.
      send_request.set_message("Hello world. Hello world. Hello world.");
      std::unique_ptr<GenericClientAsyncReaderWriter> call =
          generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
      client_ok(1);
      std::unique_ptr<ByteBuffer> send_buffer =
          SerializeToByteBuffer(&send_request);
      call->Write(*send_buffer, tag(2));
      // Send ByteBuffer can be destroyed after calling Write.
      send_buffer.reset();
      client_ok(2);
      call->WritesDone(tag(3));
      client_ok(3);

      generic_service_.RequestCall(&srv_ctx, &stream, srv_cq_.get(),
                                   srv_cq_.get(), tag(4));

      verify_ok(srv_cq_.get(), 4, true);
      EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length()));
      EXPECT_EQ(kMethodName, srv_ctx.method());
      ByteBuffer recv_buffer;
      stream.Read(&recv_buffer, tag(5));
      server_ok(5);
      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
      EXPECT_EQ(send_request.message(), recv_request.message());

      send_response.set_message(recv_request.message());
      send_buffer = SerializeToByteBuffer(&send_response);
      stream.Write(*send_buffer, tag(6));
      send_buffer.reset();
      server_ok(6);

      stream.Finish(Status::OK, tag(7));
      server_ok(7);

      recv_buffer.Clear();
      call->Read(&recv_buffer, tag(8));
      client_ok(8);
      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));

      call->Finish(&recv_status, tag(9));
      client_ok(9);

      EXPECT_EQ(send_response.message(), recv_response.message());
      EXPECT_TRUE(recv_status.ok());
    }
  }

  CompletionQueue cli_cq_;
  std::unique_ptr<ServerCompletionQueue> srv_cq_;
  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
  std::unique_ptr<grpc::GenericStub> generic_stub_;
  std::unique_ptr<Server> server_;
  AsyncGenericService generic_service_;
  const grpc::string server_host_;
  std::ostringstream server_address_;
};

TEST_F(FilterEnd2endTest, SimpleRpc) {
  ResetStub();
  EXPECT_EQ(0, GetConnectionCounterValue());
  EXPECT_EQ(0, GetCallCounterValue());
  SendRpc(1);
  EXPECT_EQ(1, GetConnectionCounterValue());
  EXPECT_EQ(1, GetCallCounterValue());
}

TEST_F(FilterEnd2endTest, SequentialRpcs) {
  ResetStub();
  EXPECT_EQ(0, GetConnectionCounterValue());
  EXPECT_EQ(0, GetCallCounterValue());
  SendRpc(10);
  EXPECT_EQ(1, GetConnectionCounterValue());
  EXPECT_EQ(10, GetCallCounterValue());
}

// One ping, one pong.
TEST_F(FilterEnd2endTest, SimpleBidiStreaming) {
  ResetStub();
  EXPECT_EQ(0, GetConnectionCounterValue());
  EXPECT_EQ(0, GetCallCounterValue());

  const grpc::string kMethodName(
      "/grpc.cpp.test.util.EchoTestService/BidiStream");
  EchoRequest send_request;
  EchoRequest recv_request;
  EchoResponse send_response;
  EchoResponse recv_response;
  Status recv_status;
  ClientContext cli_ctx;
  GenericServerContext srv_ctx;
  GenericServerAsyncReaderWriter srv_stream(&srv_ctx);

  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
  send_request.set_message("Hello");
  std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
      generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
  client_ok(1);

  generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(),
                               srv_cq_.get(), tag(2));

  verify_ok(srv_cq_.get(), 2, true);
  EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length()));
  EXPECT_EQ(kMethodName, srv_ctx.method());

  std::unique_ptr<ByteBuffer> send_buffer =
      SerializeToByteBuffer(&send_request);
  cli_stream->Write(*send_buffer, tag(3));
  send_buffer.reset();
  client_ok(3);

  ByteBuffer recv_buffer;
  srv_stream.Read(&recv_buffer, tag(4));
  server_ok(4);
  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
  EXPECT_EQ(send_request.message(), recv_request.message());

  send_response.set_message(recv_request.message());
  send_buffer = SerializeToByteBuffer(&send_response);
  srv_stream.Write(*send_buffer, tag(5));
  send_buffer.reset();
  server_ok(5);

  cli_stream->Read(&recv_buffer, tag(6));
  client_ok(6);
  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
  EXPECT_EQ(send_response.message(), recv_response.message());

  cli_stream->WritesDone(tag(7));
  client_ok(7);

  srv_stream.Read(&recv_buffer, tag(8));
  server_fail(8);

  srv_stream.Finish(Status::OK, tag(9));
  server_ok(9);

  cli_stream->Finish(&recv_status, tag(10));
  client_ok(10);

  EXPECT_EQ(send_response.message(), recv_response.message());
  EXPECT_TRUE(recv_status.ok());

  EXPECT_EQ(1, GetCallCounterValue());
  EXPECT_EQ(1, GetConnectionCounterValue());
}

}  // namespace
}  // namespace testing
}  // namespace grpc

int main(int argc, char** argv) {
  grpc_test_init(argc, argv);
  ::testing::InitGoogleTest(&argc, argv);
  grpc::RegisterChannelFilter<grpc::testing::ChannelDataImpl,
                              grpc::testing::CallDataImpl>(
      "test-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr);
  return RUN_ALL_TESTS();
}
<commit_msg>Move use of nullptr into grpc namespace, so that the hack in config.h can be used.<commit_after>/*
 *
 * Copyright 2016, 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 <memory>
#include <mutex>

#include <grpc++/channel.h>
#include <grpc++/client_context.h>
#include <grpc++/create_channel.h>
#include <grpc++/generic/async_generic_service.h>
#include <grpc++/generic/generic_stub.h>
#include <grpc++/impl/codegen/proto_utils.h>
#include <grpc++/server.h>
#include <grpc++/server_builder.h>
#include <grpc++/server_context.h>
#include <grpc++/support/config.h>
#include <grpc++/support/slice.h>
#include <grpc/grpc.h>
#include <grpc/support/thd.h>
#include <grpc/support/time.h>
#include <gtest/gtest.h>

#include "src/cpp/common/channel_filter.h"
#include "src/proto/grpc/testing/echo.grpc.pb.h"
#include "test/core/util/port.h"
#include "test/core/util/test_config.h"
#include "test/cpp/util/byte_buffer_proto_helper.h"

using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
using std::chrono::system_clock;

namespace grpc {
namespace testing {
namespace {

void* tag(int i) { return (void*)(intptr_t)i; }

void verify_ok(CompletionQueue* cq, int i, bool expect_ok) {
  bool ok;
  void* got_tag;
  EXPECT_TRUE(cq->Next(&got_tag, &ok));
  EXPECT_EQ(expect_ok, ok);
  EXPECT_EQ(tag(i), got_tag);
}

namespace {

int global_num_connections = 0;
int global_num_calls = 0;
mutex global_mu;

void IncrementConnectionCounter() {
  unique_lock<mutex> lock(global_mu);
  ++global_num_connections;
}

void ResetConnectionCounter() {
  unique_lock<mutex> lock(global_mu);
  global_num_connections = 0;
}

int GetConnectionCounterValue() {
  unique_lock<mutex> lock(global_mu);
  return global_num_connections;
}

void IncrementCallCounter() {
  unique_lock<mutex> lock(global_mu);
  ++global_num_calls;
}

void ResetCallCounter() {
  unique_lock<mutex> lock(global_mu);
  global_num_calls = 0;
}

int GetCallCounterValue() {
  unique_lock<mutex> lock(global_mu);
  return global_num_calls;
}

}  // namespace

class ChannelDataImpl : public ChannelData {
 public:
  ChannelDataImpl(const grpc_channel_args& args, const char* peer)
      : ChannelData(args, peer) {
    IncrementConnectionCounter();
  }
};

class CallDataImpl : public CallData {
 public:
  explicit CallDataImpl(const ChannelDataImpl& channel_data)
      : CallData(channel_data) {}

  void StartTransportStreamOp(grpc_exec_ctx* exec_ctx, grpc_call_element* elem,
                              TransportStreamOp* op) GRPC_OVERRIDE {
    // Incrementing the counter could be done from the ctor, but we want
    // to test that the individual methods are actually called correctly.
    if (op->recv_initial_metadata() != nullptr) IncrementCallCounter();
    grpc_call_next_op(exec_ctx, elem, op->op());
  }
};

class FilterEnd2endTest : public ::testing::Test {
 protected:
  FilterEnd2endTest() : server_host_("localhost") {}

  void SetUp() GRPC_OVERRIDE {
    int port = grpc_pick_unused_port_or_die();
    server_address_ << server_host_ << ":" << port;
    // Setup server
    ServerBuilder builder;
    builder.AddListeningPort(server_address_.str(),
                             InsecureServerCredentials());
    builder.RegisterAsyncGenericService(&generic_service_);
    srv_cq_ = builder.AddCompletionQueue();
    server_ = builder.BuildAndStart();
  }

  void TearDown() GRPC_OVERRIDE {
    server_->Shutdown();
    void* ignored_tag;
    bool ignored_ok;
    cli_cq_.Shutdown();
    srv_cq_->Shutdown();
    while (cli_cq_.Next(&ignored_tag, &ignored_ok))
      ;
    while (srv_cq_->Next(&ignored_tag, &ignored_ok))
      ;
  }

  void ResetStub() {
    std::shared_ptr<Channel> channel =
        CreateChannel(server_address_.str(), InsecureChannelCredentials());
    generic_stub_.reset(new GenericStub(channel));
    ResetConnectionCounter();
    ResetCallCounter();
  }

  void server_ok(int i) { verify_ok(srv_cq_.get(), i, true); }
  void client_ok(int i) { verify_ok(&cli_cq_, i, true); }
  void server_fail(int i) { verify_ok(srv_cq_.get(), i, false); }
  void client_fail(int i) { verify_ok(&cli_cq_, i, false); }

  void SendRpc(int num_rpcs) {
    const grpc::string kMethodName("/grpc.cpp.test.util.EchoTestService/Echo");
    for (int i = 0; i < num_rpcs; i++) {
      EchoRequest send_request;
      EchoRequest recv_request;
      EchoResponse send_response;
      EchoResponse recv_response;
      Status recv_status;

      ClientContext cli_ctx;
      GenericServerContext srv_ctx;
      GenericServerAsyncReaderWriter stream(&srv_ctx);

      // The string needs to be long enough to test heap-based slice.
      send_request.set_message("Hello world. Hello world. Hello world.");
      std::unique_ptr<GenericClientAsyncReaderWriter> call =
          generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
      client_ok(1);
      std::unique_ptr<ByteBuffer> send_buffer =
          SerializeToByteBuffer(&send_request);
      call->Write(*send_buffer, tag(2));
      // Send ByteBuffer can be destroyed after calling Write.
      send_buffer.reset();
      client_ok(2);
      call->WritesDone(tag(3));
      client_ok(3);

      generic_service_.RequestCall(&srv_ctx, &stream, srv_cq_.get(),
                                   srv_cq_.get(), tag(4));

      verify_ok(srv_cq_.get(), 4, true);
      EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length()));
      EXPECT_EQ(kMethodName, srv_ctx.method());
      ByteBuffer recv_buffer;
      stream.Read(&recv_buffer, tag(5));
      server_ok(5);
      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
      EXPECT_EQ(send_request.message(), recv_request.message());

      send_response.set_message(recv_request.message());
      send_buffer = SerializeToByteBuffer(&send_response);
      stream.Write(*send_buffer, tag(6));
      send_buffer.reset();
      server_ok(6);

      stream.Finish(Status::OK, tag(7));
      server_ok(7);

      recv_buffer.Clear();
      call->Read(&recv_buffer, tag(8));
      client_ok(8);
      EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));

      call->Finish(&recv_status, tag(9));
      client_ok(9);

      EXPECT_EQ(send_response.message(), recv_response.message());
      EXPECT_TRUE(recv_status.ok());
    }
  }

  CompletionQueue cli_cq_;
  std::unique_ptr<ServerCompletionQueue> srv_cq_;
  std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_;
  std::unique_ptr<grpc::GenericStub> generic_stub_;
  std::unique_ptr<Server> server_;
  AsyncGenericService generic_service_;
  const grpc::string server_host_;
  std::ostringstream server_address_;
};

TEST_F(FilterEnd2endTest, SimpleRpc) {
  ResetStub();
  EXPECT_EQ(0, GetConnectionCounterValue());
  EXPECT_EQ(0, GetCallCounterValue());
  SendRpc(1);
  EXPECT_EQ(1, GetConnectionCounterValue());
  EXPECT_EQ(1, GetCallCounterValue());
}

TEST_F(FilterEnd2endTest, SequentialRpcs) {
  ResetStub();
  EXPECT_EQ(0, GetConnectionCounterValue());
  EXPECT_EQ(0, GetCallCounterValue());
  SendRpc(10);
  EXPECT_EQ(1, GetConnectionCounterValue());
  EXPECT_EQ(10, GetCallCounterValue());
}

// One ping, one pong.
TEST_F(FilterEnd2endTest, SimpleBidiStreaming) {
  ResetStub();
  EXPECT_EQ(0, GetConnectionCounterValue());
  EXPECT_EQ(0, GetCallCounterValue());

  const grpc::string kMethodName(
      "/grpc.cpp.test.util.EchoTestService/BidiStream");
  EchoRequest send_request;
  EchoRequest recv_request;
  EchoResponse send_response;
  EchoResponse recv_response;
  Status recv_status;
  ClientContext cli_ctx;
  GenericServerContext srv_ctx;
  GenericServerAsyncReaderWriter srv_stream(&srv_ctx);

  cli_ctx.set_compression_algorithm(GRPC_COMPRESS_GZIP);
  send_request.set_message("Hello");
  std::unique_ptr<GenericClientAsyncReaderWriter> cli_stream =
      generic_stub_->Call(&cli_ctx, kMethodName, &cli_cq_, tag(1));
  client_ok(1);

  generic_service_.RequestCall(&srv_ctx, &srv_stream, srv_cq_.get(),
                               srv_cq_.get(), tag(2));

  verify_ok(srv_cq_.get(), 2, true);
  EXPECT_EQ(server_host_, srv_ctx.host().substr(0, server_host_.length()));
  EXPECT_EQ(kMethodName, srv_ctx.method());

  std::unique_ptr<ByteBuffer> send_buffer =
      SerializeToByteBuffer(&send_request);
  cli_stream->Write(*send_buffer, tag(3));
  send_buffer.reset();
  client_ok(3);

  ByteBuffer recv_buffer;
  srv_stream.Read(&recv_buffer, tag(4));
  server_ok(4);
  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_request));
  EXPECT_EQ(send_request.message(), recv_request.message());

  send_response.set_message(recv_request.message());
  send_buffer = SerializeToByteBuffer(&send_response);
  srv_stream.Write(*send_buffer, tag(5));
  send_buffer.reset();
  server_ok(5);

  cli_stream->Read(&recv_buffer, tag(6));
  client_ok(6);
  EXPECT_TRUE(ParseFromByteBuffer(&recv_buffer, &recv_response));
  EXPECT_EQ(send_response.message(), recv_response.message());

  cli_stream->WritesDone(tag(7));
  client_ok(7);

  srv_stream.Read(&recv_buffer, tag(8));
  server_fail(8);

  srv_stream.Finish(Status::OK, tag(9));
  server_ok(9);

  cli_stream->Finish(&recv_status, tag(10));
  client_ok(10);

  EXPECT_EQ(send_response.message(), recv_response.message());
  EXPECT_TRUE(recv_status.ok());

  EXPECT_EQ(1, GetCallCounterValue());
  EXPECT_EQ(1, GetConnectionCounterValue());
}

void RegisterFilter() {
  grpc::RegisterChannelFilter<ChannelDataImpl, CallDataImpl>(
      "test-filter", GRPC_SERVER_CHANNEL, INT_MAX, nullptr);
}

}  // namespace
}  // namespace testing
}  // namespace grpc

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


<commit_before>#include <thread>
#include <memory>

#include "Daemon.h"

#include "Config.h"
#include "Log.h"
#include "Base.h"
#include "version.h"
#include "Transports.h"
#include "NTCPSession.h"
#include "RouterInfo.h"
#include "RouterContext.h"
#include "Tunnel.h"
#include "NetDb.h"
#include "Garlic.h"
#include "util.h"
#include "Streaming.h"
#include "Destination.h"
#include "HTTPServer.h"
#include "I2PControl.h"
#include "ClientContext.h"
#include "Crypto.h"

#ifdef USE_UPNP
#include "UPnP.h"
#endif

namespace i2p
{
	namespace util
	{
		class Daemon_Singleton::Daemon_Singleton_Private
		{
		public:
			Daemon_Singleton_Private() {};
			~Daemon_Singleton_Private() {};

			std::unique_ptr<i2p::util::HTTPServer> httpServer;
			std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;

#ifdef USE_UPNP
			i2p::transport::UPnP m_UPnP;
#endif
		};

		Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
		Daemon_Singleton::~Daemon_Singleton() {
			delete &d;
		};

		bool Daemon_Singleton::IsService () const
		{
			bool service = false;
#ifndef _WIN32
			i2p::config::GetOption("service", service);
#endif
			return service;
		}

		bool Daemon_Singleton::init(int argc, char* argv[])
		{
			i2p::config::Init();
			i2p::config::ParseCmdline(argc, argv);

			std::string config  = i2p::util::filesystem::GetConfigFile().string();
			std::string tunconf = i2p::util::filesystem::GetTunnelsConfigFile().string();
			std::string datadir = i2p::util::filesystem::GetDataDir().string();

			LogPrint(eLogInfo,  "i2pd v", VERSION, " starting");
			LogPrint(eLogDebug, "FS: main config file: ", config);
			LogPrint(eLogDebug, "FS: tunnels config: ",   tunconf);
			LogPrint(eLogDebug, "FS: data directory: ", datadir);

			i2p::config::ParseConfig(config);
			i2p::config::Finalize();

			i2p::crypto::InitCrypto ();
			i2p::context.Init ();

			i2p::config::GetOption("daemon", isDaemon);

			// temporary hack
			std::string logs = "";
			i2p::config::GetOption("log", logs);
			if (isDaemon || logs != "") isLogging = true;

			uint16_t port; i2p::config::GetOption("port", port);
			if (port)
			{
				LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
				i2p::context.UpdatePort (port);
			}

			std::string host; i2p::config::GetOption("host", host);
			if (host != "")
			{
				LogPrint(eLogInfo, "Daemon: address for incoming connections is ", host);
				i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
			}

			bool ipv6;    i2p::config::GetOption("ipv6", ipv6);
			bool transit; i2p::config::GetOption("notransit", transit);
			i2p::context.SetSupportsV6     (ipv6);
			i2p::context.SetAcceptsTunnels (!transit);

			bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
			char bandwidth;   i2p::config::GetOption("bandwidth", bandwidth);

			if (isFloodfill)
			{
				LogPrint(eLogInfo, "Daemon: router will be floodfill");
				i2p::context.SetFloodfill (true);
			}
			if (bandwidth != '-')
			{
				LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth);
				if (bandwidth > 'O')
					i2p::context.SetExtraBandwidth ();
				else if (bandwidth > 'L')
					i2p::context.SetHighBandwidth ();
				else
					i2p::context.SetLowBandwidth ();
			}
			else if (isFloodfill)
			{
				LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
				i2p::context.SetExtraBandwidth ();
			}
			else
				i2p::context.SetLowBandwidth ();

			return true;
		}

		bool Daemon_Singleton::start()
		{
			std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);

			if (isLogging)
			{
				// set default to stdout
				std::string logfile  = ""; i2p::config::GetOption("logfile",  logfile);

				if (logfile == "")
				{
					// can't log to stdout, use autodetect of logfile
					logfile = IsService () ? "/var/log" : i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
					logfile.append("/i2pd.log");
#else
					logfile.append("\\i2pd.log");
#endif
				}
				StartLog (logfile);
			}
			else
				StartLog ("");
			SetLogLevel(loglevel);

			bool http; i2p::config::GetOption("http.enabled", http);
			if (http) {
				std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
				uint16_t    httpPort; i2p::config::GetOption("http.port",    httpPort);
				LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
				d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(httpAddr, httpPort));
				d.httpServer->Start();
			}

			LogPrint(eLogInfo, "Daemon: starting NetDB");
			i2p::data::netdb.Start();

#ifdef USE_UPNP
			LogPrint(eLogInfo, "Daemon: starting UPnP");
			d.m_UPnP.Start ();
#endif
			LogPrint(eLogInfo, "Daemon: starting Transports");
			i2p::transport::transports.Start();

			LogPrint(eLogInfo, "Daemon: starting Tunnels");
			i2p::tunnel::tunnels.Start();

			LogPrint(eLogInfo, "Daemon: starting Client");
			i2p::client::context.Start ();

			// I2P Control Protocol
			bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
			if (i2pcontrol) {
				std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
				uint16_t    i2pcpPort; i2p::config::GetOption("i2pcontrol.port",    i2pcpPort);
				LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
				d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
				d.m_I2PControlService->Start ();
			}
			return true;
		}

		bool Daemon_Singleton::stop()
		{
			LogPrint(eLogInfo, "Daemon: shutting down");
			LogPrint(eLogInfo, "Daemon: stopping Client");
			i2p::client::context.Stop();
			LogPrint(eLogInfo, "Daemon: stopping Tunnels");
			i2p::tunnel::tunnels.Stop();
#ifdef USE_UPNP
			LogPrint(eLogInfo, "Daemon: stopping UPnP");
			d.m_UPnP.Stop ();
#endif
			LogPrint(eLogInfo, "Daemon: stopping Transports");
			i2p::transport::transports.Stop();
			LogPrint(eLogInfo, "Daemon: stopping NetDB");
			i2p::data::netdb.Stop();
			LogPrint(eLogInfo, "Daemon: stopping HTTP Server");
			d.httpServer->Stop();
			d.httpServer = nullptr;
			if (d.m_I2PControlService)
			{
				LogPrint(eLogInfo, "Daemon: stopping I2PControl");
				d.m_I2PControlService->Stop ();
				d.m_I2PControlService = nullptr;
			}
			i2p::crypto::TerminateCrypto ();
			StopLog ();

			return true;
		}
	}
}
<commit_msg>* Daemon.cpp : move logs init to single place<commit_after>#include <thread>
#include <memory>

#include "Daemon.h"

#include "Config.h"
#include "Log.h"
#include "Base.h"
#include "version.h"
#include "Transports.h"
#include "NTCPSession.h"
#include "RouterInfo.h"
#include "RouterContext.h"
#include "Tunnel.h"
#include "NetDb.h"
#include "Garlic.h"
#include "util.h"
#include "Streaming.h"
#include "Destination.h"
#include "HTTPServer.h"
#include "I2PControl.h"
#include "ClientContext.h"
#include "Crypto.h"

#ifdef USE_UPNP
#include "UPnP.h"
#endif

namespace i2p
{
	namespace util
	{
		class Daemon_Singleton::Daemon_Singleton_Private
		{
		public:
			Daemon_Singleton_Private() {};
			~Daemon_Singleton_Private() {};

			std::unique_ptr<i2p::util::HTTPServer> httpServer;
			std::unique_ptr<i2p::client::I2PControlService> m_I2PControlService;

#ifdef USE_UPNP
			i2p::transport::UPnP m_UPnP;
#endif
		};

		Daemon_Singleton::Daemon_Singleton() : running(1), d(*new Daemon_Singleton_Private()) {};
		Daemon_Singleton::~Daemon_Singleton() {
			delete &d;
		};

		bool Daemon_Singleton::IsService () const
		{
			bool service = false;
#ifndef _WIN32
			i2p::config::GetOption("service", service);
#endif
			return service;
		}

		bool Daemon_Singleton::init(int argc, char* argv[])
		{
			i2p::config::Init();
			i2p::config::ParseCmdline(argc, argv);

			std::string config  = i2p::util::filesystem::GetConfigFile().string();
			std::string tunconf = i2p::util::filesystem::GetTunnelsConfigFile().string();
			std::string datadir = i2p::util::filesystem::GetDataDir().string();

			i2p::config::ParseConfig(config);
			i2p::config::Finalize();

			i2p::crypto::InitCrypto ();
			i2p::context.Init ();

			i2p::config::GetOption("daemon", isDaemon);

			// TODO: move log init here

			LogPrint(eLogInfo,  "i2pd v", VERSION, " starting");
			LogPrint(eLogDebug, "FS: main config file: ", config);
			LogPrint(eLogDebug, "FS: tunnels config: ",   tunconf);
			LogPrint(eLogDebug, "FS: data directory: ", datadir);

			uint16_t port; i2p::config::GetOption("port", port);
			if (port)
			{
				LogPrint(eLogInfo, "Daemon: accepting incoming connections at port ", port);
				i2p::context.UpdatePort (port);
			}

			std::string host; i2p::config::GetOption("host", host);
			if (host != "")
			{
				LogPrint(eLogInfo, "Daemon: address for incoming connections is ", host);
				i2p::context.UpdateAddress (boost::asio::ip::address::from_string (host));
			}

			bool ipv6;    i2p::config::GetOption("ipv6", ipv6);
			bool transit; i2p::config::GetOption("notransit", transit);
			i2p::context.SetSupportsV6     (ipv6);
			i2p::context.SetAcceptsTunnels (!transit);

			bool isFloodfill; i2p::config::GetOption("floodfill", isFloodfill);
			char bandwidth;   i2p::config::GetOption("bandwidth", bandwidth);

			if (isFloodfill)
			{
				LogPrint(eLogInfo, "Daemon: router will be floodfill");
				i2p::context.SetFloodfill (true);
			}
			if (bandwidth != '-')
			{
				LogPrint(eLogInfo, "Daemon: bandwidth set to ", bandwidth);
				if (bandwidth > 'O')
					i2p::context.SetExtraBandwidth ();
				else if (bandwidth > 'L')
					i2p::context.SetHighBandwidth ();
				else
					i2p::context.SetLowBandwidth ();
			}
			else if (isFloodfill)
			{
				LogPrint(eLogInfo, "Daemon: floodfill bandwidth set to 'extra'");
				i2p::context.SetExtraBandwidth ();
			}
			else
				i2p::context.SetLowBandwidth ();

			return true;
		}

		bool Daemon_Singleton::start()
		{
			std::string logs     = ""; i2p::config::GetOption("log",      logs);
			std::string logfile  = ""; i2p::config::GetOption("logfile",  logfile);
			std::string loglevel = ""; i2p::config::GetOption("loglevel", loglevel);

			// temporary hack
			if (isDaemon || logs != "") isLogging = true;

			if (isLogging)
			{
				if (logfile == "")
				{
					// use autodetect of logfile
					logfile = IsService () ? "/var/log" : i2p::util::filesystem::GetDataDir().string();
#ifndef _WIN32
					logfile.append("/i2pd.log");
#else
					logfile.append("\\i2pd.log");
#endif
				}
				StartLog (logfile);
			} else {
				// use stdout
				StartLog ("");
			}
			SetLogLevel(loglevel);

			bool http; i2p::config::GetOption("http.enabled", http);
			if (http) {
				std::string httpAddr; i2p::config::GetOption("http.address", httpAddr);
				uint16_t    httpPort; i2p::config::GetOption("http.port",    httpPort);
				LogPrint(eLogInfo, "Daemon: starting HTTP Server at ", httpAddr, ":", httpPort);
				d.httpServer = std::unique_ptr<i2p::util::HTTPServer>(new i2p::util::HTTPServer(httpAddr, httpPort));
				d.httpServer->Start();
			}

			LogPrint(eLogInfo, "Daemon: starting NetDB");
			i2p::data::netdb.Start();

#ifdef USE_UPNP
			LogPrint(eLogInfo, "Daemon: starting UPnP");
			d.m_UPnP.Start ();
#endif
			LogPrint(eLogInfo, "Daemon: starting Transports");
			i2p::transport::transports.Start();

			LogPrint(eLogInfo, "Daemon: starting Tunnels");
			i2p::tunnel::tunnels.Start();

			LogPrint(eLogInfo, "Daemon: starting Client");
			i2p::client::context.Start ();

			// I2P Control Protocol
			bool i2pcontrol; i2p::config::GetOption("i2pcontrol.enabled", i2pcontrol);
			if (i2pcontrol) {
				std::string i2pcpAddr; i2p::config::GetOption("i2pcontrol.address", i2pcpAddr);
				uint16_t    i2pcpPort; i2p::config::GetOption("i2pcontrol.port",    i2pcpPort);
				LogPrint(eLogInfo, "Daemon: starting I2PControl at ", i2pcpAddr, ":", i2pcpPort);
				d.m_I2PControlService = std::unique_ptr<i2p::client::I2PControlService>(new i2p::client::I2PControlService (i2pcpAddr, i2pcpPort));
				d.m_I2PControlService->Start ();
			}
			return true;
		}

		bool Daemon_Singleton::stop()
		{
			LogPrint(eLogInfo, "Daemon: shutting down");
			LogPrint(eLogInfo, "Daemon: stopping Client");
			i2p::client::context.Stop();
			LogPrint(eLogInfo, "Daemon: stopping Tunnels");
			i2p::tunnel::tunnels.Stop();
#ifdef USE_UPNP
			LogPrint(eLogInfo, "Daemon: stopping UPnP");
			d.m_UPnP.Stop ();
#endif
			LogPrint(eLogInfo, "Daemon: stopping Transports");
			i2p::transport::transports.Stop();
			LogPrint(eLogInfo, "Daemon: stopping NetDB");
			i2p::data::netdb.Stop();
			LogPrint(eLogInfo, "Daemon: stopping HTTP Server");
			d.httpServer->Stop();
			d.httpServer = nullptr;
			if (d.m_I2PControlService)
			{
				LogPrint(eLogInfo, "Daemon: stopping I2PControl");
				d.m_I2PControlService->Stop ();
				d.m_I2PControlService = nullptr;
			}
			i2p::crypto::TerminateCrypto ();
			StopLog ();

			return true;
		}
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 by Robert Bosch GmbH. All rights reserved.
//
// 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 "test.hpp"

#include "iceoryx_posh/roudi/memory/iceoryx_roudi_memory_manager.hpp"

using namespace ::testing;

using iox::roudi::IceOryxRouDiMemoryManager;

namespace iox
{
namespace test
{

/// @brief This test file verifies that the BaseClass IceoryxRouDiMemoryManager is tested
class IceoryxRoudiMemoryManager_test : public Test
{
  public:
    IceOryxRouDiMemoryManager* m_roudiMemoryManagerTest{nullptr};

    void SetUp() override
    {
      auto config = iox::RouDiConfig_t().setDefaults();
      m_roudiMemoryManagerTest = new IceOryxRouDiMemoryManager(config);
    }

    void TearDown() override
    {
  delete m_roudiMemoryManagerTest;
    }
};

/// @brief test to check function introspectionMemoryManager
TEST_F(IceoryxRoudiMemoryManager_test, IntrospectionMemoryManagerNotInitialized)
{
    auto result = m_roudiMemoryManagerTest->introspectionMemoryManager();
    EXPECT_THAT(result, Eq(iox::cxx::nullopt_t()));
}

/// @brief test to check function segmentManager
TEST_F(IceoryxRoudiMemoryManager_test, segmentManagerNotInitialized)
{
    auto resultTest = m_roudiMemoryManagerTest->segmentManager();
    EXPECT_THAT(resultTest, Eq(iox::cxx::nullopt_t()));
}

/// @brief test to check function portPool
TEST_F(IceoryxRoudiMemoryManager_test, portPoolNotInitialized)
{
    auto testResult = m_roudiMemoryManagerTest->portPool();
    EXPECT_THAT(testResult, Eq(iox::cxx::nullopt_t()));
}

} // namespace test
} // iox
<commit_msg>iox-#454 fix review findings<commit_after>// Copyright (c) 2021 by Robert Bosch GmbH. All rights reserved.
//
// 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 "test.hpp"

#include "iceoryx_posh/roudi/memory/iceoryx_roudi_memory_manager.hpp"

using namespace ::testing;

using iox::roudi::IceOryxRouDiMemoryManager;

namespace iox
{
namespace test
{

/// @brief This test file verifies that the BaseClass IceoryxRouDiMemoryManager is tested
class IceoryxRoudiMemoryManager_test : public Test
{
  public:
    std::unique_ptr<IceOryxRouDiMemoryManager> m_roudiMemoryManagerTest;

    void SetUp() override
    {
      auto config = iox::RouDiConfig_t().setDefaults();
      m_roudiMemoryManagerTest = std::unique_ptr<IceOryxRouDiMemoryManager>(new IceOryxRouDiMemoryManager(config));
    }

    void TearDown() override
    {
    }
};

/// @brief test to check function introspectionMemoryManager
TEST_F(IceoryxRoudiMemoryManager_test, IntrospectionMemoryManagerNotInitialized)
{
    auto result = m_roudiMemoryManagerTest->introspectionMemoryManager();
    EXPECT_THAT(result, Eq(iox::cxx::nullopt_t()));
}

/// @brief test to check function segmentManager
TEST_F(IceoryxRoudiMemoryManager_test, segmentManagerNotInitialized)
{
    auto resultTest = m_roudiMemoryManagerTest->segmentManager();
    EXPECT_THAT(resultTest, Eq(iox::cxx::nullopt_t()));
}

/// @brief test to check function portPool
TEST_F(IceoryxRoudiMemoryManager_test, portPoolNotInitialized)
{
    auto testResult = m_roudiMemoryManagerTest->portPool();
    EXPECT_THAT(testResult, Eq(iox::cxx::nullopt_t()));
}

} // namespace test
} // iox
<|endoftext|>


<commit_before>#include <stdio.h>
#include <iostream>
#include "MatrixStore.hpp"

int main(){

	class MatrixStore<double> MatA(3, 3); MatA.Zeros();
	class MatrixStore<double> MatB(3, 3); MatB.Zeros();

	for(unsigned int q=0; q<MatA.ColNum; q++){
		for(unsigned int p=0; p<MatA.RowNum; p++){
			MatA(p, q) = (MatA.ColNum)*p + q;
		}
	}

	printm(MatA); printf("\n");

	MatB(':', 0) = MatA(':', 1);
//	MatB(':', 1) = MatA(':', 2);
//	MatB(':', 2) = MatA(':', 0);

	printm(MatB); printf("\n");

	MatB(0, ':') = MatA(0, ':');
//	MatB(1, ':') = MatA(1, ':');
	MatB(2, ':') = MatA(2, ':');

	printm(MatB);

	return 0;
}
<commit_msg>Delete main.cpp<commit_after><|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreException.h"
#include "OgreScriptLexer.h"

namespace Ogre{

	ScriptLexer::ScriptLexer()
	{
	}

	ScriptTokenListPtr ScriptLexer::tokenize(const String &str, const String &source)
	{
		// State enums
		enum{ READY = 0, COMMENT, MULTICOMMENT, WORD, QUOTE, VAR, POSSIBLECOMMENT };

		// Set up some constant characters of interest
		const wchar_t varopener = '$', quote = '\"', slash = '/', backslash = '\\', openbrace = '{', closebrace = '}', colon = ':', star = '*', cr = '\r', lf = '\n';
		char c = 0, lastc = 0;

		String lexeme;
		uint32 line = 1, state = READY, lastQuote = 0;
		ScriptTokenListPtr tokens(OGRE_NEW_T(ScriptTokenList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

		// Iterate over the input
		String::const_iterator i = str.begin(), end = str.end();
		while(i != end)
		{
			lastc = c;
			c = *i;

			if(c == quote)
				lastQuote = line;

			switch(state)
			{
			case READY:
				if(c == slash && lastc == slash)
				{
					// Comment start, clear out the lexeme
					lexeme = "";
					state = COMMENT;
				}
				else if(c == star && lastc == slash)
				{
					lexeme = "";
					state = MULTICOMMENT;
				}
				else if(c == quote)
				{
					// Clear out the lexeme ready to be filled with quotes!
					lexeme = c;
					state = QUOTE;
				}
				else if(c == varopener)
				{
					// Set up to read in a variable
					lexeme = c;
					state = VAR;
				}
				else if(isNewline(c))
				{
					lexeme = c;
					setToken(lexeme, line, source, tokens.get());
				}
				else if(!isWhitespace(c))
				{
					lexeme = c;
					if(c == slash)
						state = POSSIBLECOMMENT;
					else
						state = WORD;
				}
				break;
			case COMMENT:
				if(isNewline(c))
				{
					lexeme = c;
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				break;
			case MULTICOMMENT:
				if(c == slash && lastc == star)
					state = READY;
				break;
			case POSSIBLECOMMENT:
				if(c == slash && lastc == slash)
				{
					lexeme = "";
					state = COMMENT;
					break;
				}
				else if(c == star && lastc == slash)
				{
					lexeme = "";
					state = MULTICOMMENT;
					break;
				}
				else
				{
					state = WORD;
				}
			case WORD:
				if(isNewline(c))
				{
					setToken(lexeme, line, source, tokens.get());
					lexeme = c;
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				else if(isWhitespace(c))
				{
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				else if(c == openbrace || c == closebrace || c == colon)
				{
					setToken(lexeme, line, source, tokens.get());
					lexeme = c;
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				else
				{
					lexeme += c;
				}
				break;
			case QUOTE:
				if(c != backslash)
				{
					// Allow embedded quotes with escaping
					if(c == quote && lastc == backslash)
					{
						lexeme += c;
					}
					else if(c == quote)
					{
						lexeme += c;
						setToken(lexeme, line, source, tokens.get());
						state = READY;
					}
					else
					{
						// Backtrack here and allow a backslash normally within the quote
						if(lastc == backslash)
							lexeme = lexeme + "\\" + c;
						else
							lexeme += c;
					}
				}
				break;
			case VAR:
				if(isNewline(c))
				{
					setToken(lexeme, line, source, tokens.get());
					lexeme = c;
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				else if(isWhitespace(c))
				{
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				else if(c == openbrace || c == closebrace || c == colon)
				{
					setToken(lexeme, line, source, tokens.get());
					lexeme = c;
					setToken(lexeme, line, source, tokens.get());
					state = READY;
				}
				else
				{
					lexeme += c;
				}
				break;
			}

			// Separate check for newlines just to track line numbers
			if(c == cr || (c == lf && lastc != cr))
				line++;

			i++;
		}

		// Check for valid exit states
		if(state == WORD || state == VAR)
		{
			if(!lexeme.empty())
				setToken(lexeme, line, source, tokens.get());
		}
		else
		{
			if(state == QUOTE)
			{
				OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
					Ogre::String("no matching \" found for \" at line ") +
						Ogre::StringConverter::toString(lastQuote),
					"ScriptLexer::tokenize");
			}
		}

		return tokens;
	}

	void ScriptLexer::setToken(const Ogre::String &lexeme, Ogre::uint32 line, const String &source, Ogre::ScriptTokenList *tokens)
	{
		const char openBracket = '{', closeBracket = '}', colon = ':',
			quote = '\"', var = '$';

		ScriptTokenPtr token(OGRE_NEW_T(ScriptToken, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
		token->lexeme = lexeme;
		token->line = line;
		token->file = source;
		bool ignore = false;

		// Check the user token map first
		if(lexeme.size() == 1 && isNewline(lexeme[0]))
		{
			token->type = TID_NEWLINE;
			if(!tokens->empty() && tokens->back()->type == TID_NEWLINE)
				ignore = true;
		}
		else if(lexeme.size() == 1 && lexeme[0] == openBracket)
			token->type = TID_LBRACKET;
		else if(lexeme.size() == 1 && lexeme[0] == closeBracket)
			token->type = TID_RBRACKET;
		else if(lexeme.size() == 1 && lexeme[0] == colon)
			token->type = TID_COLON;
		else if(lexeme[0] == var)
			token->type = TID_VARIABLE;
		else
		{
			// This is either a non-zero length phrase or quoted phrase
			if(lexeme.size() >= 2 && lexeme[0] == quote && lexeme[lexeme.size() - 1] == quote)
			{
				token->type = TID_QUOTE;
			}
			else
			{
				token->type = TID_WORD;
			}
		}

		if(!ignore)
			tokens->push_back(token);
	}

	bool ScriptLexer::isWhitespace(Ogre::String::value_type c) const
	{
		return c == ' ' || c == '\r' || c == '\t';
	}

	bool ScriptLexer::isNewline(Ogre::String::value_type c) const
	{
		return c == '\n' || c == '\r';
	}

}

<commit_msg>Corrected spaces/tabs of script lexer code for future merge<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "OgreStableHeaders.h"
#include "OgreException.h"
#include "OgreScriptLexer.h"

namespace Ogre{

    ScriptLexer::ScriptLexer()
    {
    }

    ScriptTokenListPtr ScriptLexer::tokenize(const String &str, const String &source)
    {
        // State enums
        enum{ READY = 0, COMMENT, MULTICOMMENT, WORD, QUOTE, VAR, POSSIBLECOMMENT };

        // Set up some constant characters of interest
        const wchar_t varopener = '$', quote = '\"', slash = '/', backslash = '\\', openbrace = '{', closebrace = '}', colon = ':', star = '*', cr = '\r', lf = '\n';
        char c = 0, lastc = 0;

        String lexeme;
        uint32 line = 1, state = READY, lastQuote = 0;
        ScriptTokenListPtr tokens(OGRE_NEW_T(ScriptTokenList, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);

        // Iterate over the input
        String::const_iterator i = str.begin(), end = str.end();
        while(i != end)
        {
            lastc = c;
            c = *i;

            if(c == quote)
                lastQuote = line;

            switch(state)
            {
            case READY:
                if(c == slash && lastc == slash)
                {
                    // Comment start, clear out the lexeme
                    lexeme = "";
                    state = COMMENT;
                }
                else if(c == star && lastc == slash)
                {
                    lexeme = "";
                    state = MULTICOMMENT;
                }
                else if(c == quote)
                {
                    // Clear out the lexeme ready to be filled with quotes!
                    lexeme = c;
                    state = QUOTE;
                }
                else if(c == varopener)
                {
                    // Set up to read in a variable
                    lexeme = c;
                    state = VAR;
                }
                else if(isNewline(c))
                {
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                }
                else if(!isWhitespace(c))
                {
                    lexeme = c;
                    if(c == slash)
                        state = POSSIBLECOMMENT;
                    else
                        state = WORD;
                }
                break;
            case COMMENT:
                if(isNewline(c))
                {
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                break;
            case MULTICOMMENT:
                if(c == slash && lastc == star)
                    state = READY;
                break;
            case POSSIBLECOMMENT:
                if(c == slash && lastc == slash)
                {
                    lexeme = "";
                    state = COMMENT;
                    break;
                }
                else if(c == star && lastc == slash)
                {
                    lexeme = "";
                    state = MULTICOMMENT;
                    break;
                }
                else
                {
                    state = WORD;
                }
            case WORD:
                if(isNewline(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(isWhitespace(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(c == openbrace || c == closebrace || c == colon)
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else
                {
                    lexeme += c;
                }
                break;
            case QUOTE:
                if(c != backslash)
                {
                    // Allow embedded quotes with escaping
                    if(c == quote && lastc == backslash)
                    {
                        lexeme += c;
                    }
                    else if(c == quote)
                    {
                        lexeme += c;
                        setToken(lexeme, line, source, tokens.get());
                        state = READY;
                    }
                    else
                    {
                        // Backtrack here and allow a backslash normally within the quote
                        if(lastc == backslash)
                            lexeme = lexeme + "\\" + c;
                        else
                            lexeme += c;
                    }
                }
                break;
            case VAR:
                if(isNewline(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(isWhitespace(c))
                {
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else if(c == openbrace || c == closebrace || c == colon)
                {
                    setToken(lexeme, line, source, tokens.get());
                    lexeme = c;
                    setToken(lexeme, line, source, tokens.get());
                    state = READY;
                }
                else
                {
                    lexeme += c;
                }
                break;
            }

            // Separate check for newlines just to track line numbers
            if(c == cr || (c == lf && lastc != cr))
                line++;

            i++;
        }

        // Check for valid exit states
        if(state == WORD || state == VAR)
        {
            if(!lexeme.empty())
                setToken(lexeme, line, source, tokens.get());
        }
        else
        {
            if(state == QUOTE)
            {
                OGRE_EXCEPT(Exception::ERR_INVALID_STATE,
                    Ogre::String("no matching \" found for \" at line ") +
                    Ogre::StringConverter::toString(lastQuote),
                    "ScriptLexer::tokenize");
            }
        }

        return tokens;
    }

    void ScriptLexer::setToken(const Ogre::String &lexeme, Ogre::uint32 line, const String &source, Ogre::ScriptTokenList *tokens)
    {
        const char openBracket = '{', closeBracket = '}', colon = ':',
            quote = '\"', var = '$';

        ScriptTokenPtr token(OGRE_NEW_T(ScriptToken, MEMCATEGORY_GENERAL)(), SPFM_DELETE_T);
        token->lexeme = lexeme;
        token->line = line;
        token->file = source;
        bool ignore = false;

        // Check the user token map first
        if(lexeme.size() == 1 && isNewline(lexeme[0]))
        {
            token->type = TID_NEWLINE;
            if(!tokens->empty() && tokens->back()->type == TID_NEWLINE)
                ignore = true;
        }
        else if(lexeme.size() == 1 && lexeme[0] == openBracket)
            token->type = TID_LBRACKET;
        else if(lexeme.size() == 1 && lexeme[0] == closeBracket)
            token->type = TID_RBRACKET;
        else if(lexeme.size() == 1 && lexeme[0] == colon)
            token->type = TID_COLON;
        else if(lexeme[0] == var)
            token->type = TID_VARIABLE;
        else
        {
            // This is either a non-zero length phrase or quoted phrase
            if(lexeme.size() >= 2 && lexeme[0] == quote && lexeme[lexeme.size() - 1] == quote)
            {
                token->type = TID_QUOTE;
            }
            else
            {
                token->type = TID_WORD;
            }
        }

        if(!ignore)
            tokens->push_back(token);
    }

    bool ScriptLexer::isWhitespace(Ogre::String::value_type c) const
    {
        return c == ' ' || c == '\r' || c == '\t';
    }

    bool ScriptLexer::isNewline(Ogre::String::value_type c) const
    {
        return c == '\n' || c == '\r';
    }

}

<|endoftext|>


<commit_before>/*
   Source File : PDFParserTokenizer.cpp

   Copyright 2011 Gal Kahana PDFWriter

   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 "PDFParserTokenizer.h"
#include "IByteReader.h"
#include "OutputStringBufferStream.h"

using namespace PDFHummus;
using namespace IOBasicTypes;

PDFParserTokenizer::PDFParserTokenizer(void)
{
	mStream = NULL;
	ResetReadState();
}

PDFParserTokenizer::~PDFParserTokenizer(void)
{
}

void PDFParserTokenizer::SetReadStream(IByteReader* inSourceStream)
{
	mStream = inSourceStream;
	ResetReadState();
}

void PDFParserTokenizer::ResetReadState()
{
	mHasTokenBuffer = false;
	mStreamPositionTracker = 0;
	mRecentTokenPosition = 0;
}

void PDFParserTokenizer::ResetReadState(const PDFParserTokenizer& inExternalTokenizer)
{
	mTokenBuffer = inExternalTokenizer.mTokenBuffer;
	mHasTokenBuffer = inExternalTokenizer.mHasTokenBuffer;
	mStreamPositionTracker = inExternalTokenizer.mStreamPositionTracker;
	mRecentTokenPosition = inExternalTokenizer.mRecentTokenPosition;
}

static const Byte scBackSlash[] = {'\\'};
static const std::string scStream = "stream";
static const char scCR = '\r';
static const char scLF = '\n';
BoolAndString PDFParserTokenizer::GetNextToken()
{
	BoolAndString result;
	Byte buffer;
	OutputStringBufferStream tokenBuffer;

	if(!mStream || (!mStream->NotEnded() && !mHasTokenBuffer))
	{
		result.first = false;
		return result;
	}

	do
	{
		SkipTillToken();
		if(!mStream->NotEnded())
		{
			result.first = false;
			break;
		}

		// before reading the first byte save the token position, for external queries
		mRecentTokenPosition = mStreamPositionTracker;

		// get the first byte of the token
		if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
		{
			result.first = false;
			break;
		}
		tokenBuffer.Write(&buffer,1);

		result.first = true; // will only be changed to false in case of read error

		// now determine how to continue based on the first byte of the token (there are some special cases)
		switch(buffer)
		{

			case '%':
			{
				// for a comment, the token goes on till the end of line marker [not including]
				while(mStream->NotEnded())
				{
					if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
					{
						result.first = false;
						break;
					}
					if(0xD == buffer|| 0xA == buffer)
						break;
					tokenBuffer.Write(&buffer,1);
				}
				result.second = tokenBuffer.ToString();
				break;
			}

			case '(':
			{
				// for a literal string, the token goes on until the balanced-closing right paranthesis
				int balanceLevel = 1;
				bool backSlashEncountered = false;
				while(balanceLevel > 0 && mStream->NotEnded())
				{
					if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
					{
						result.first = false;
						break;
					}

					if(backSlashEncountered)
					{
						backSlashEncountered = false;
						if(0xA == buffer || 0xD == buffer)
						{
							// ignore backslash and newline. might also need to read extra
							// for cr-ln
							if(0xD == buffer && mStream->NotEnded())
							{
								if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
								{
									result.first = false;
									break;
								}
								if(buffer != 0xA)
									SaveTokenBuffer(buffer);
							}
						}
						else
						{
							tokenBuffer.Write(scBackSlash,1);
							tokenBuffer.Write(&buffer,1);
						}
					}
					else
					{
						if('\\' == buffer)
						{
							backSlashEncountered = true;
							continue;
						}
						else if('(' == buffer)
							++balanceLevel;
						else if(')' == buffer)
							--balanceLevel;
						tokenBuffer.Write(&buffer,1);
					}
				}
				if(result.first)
					result.second = tokenBuffer.ToString();
				break;
			}

			case '<':
			{
				// k. this might be a dictionary start marker or a hax string start. depending on whether it has a < following it or not

				// Hex string, read till end of hex string marker
				if(!mStream->NotEnded())
				{
					result.second = tokenBuffer.ToString();
					break;
				}

				if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
				{
						result.first = false;
						break;
				}

				if('<' == buffer)
				{
					// Dictionary start marker
					tokenBuffer.Write(&buffer,1);
					result.second = tokenBuffer.ToString();
					break;
				}
				else
				{
					// Hex string

					tokenBuffer.Write(&buffer,1);

					while(mStream->NotEnded())
					{
						if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
						{
							result.first = false;
							break;
						}

						if(!IsPDFWhiteSpace(buffer))
							tokenBuffer.Write(&buffer,1);
						if('>' == buffer)
							break;
					}
				}
				result.second = tokenBuffer.ToString();
				break;
			}
			case '[': // for all array or executable tokanizers, the tokanizer is just the mark
			case ']':
			case '{':
			case '}':
				result.second = tokenBuffer.ToString();
				break;
			case '>': // parse end dictionary marker as a single entity or a hex string end marker
			{
				if(!mStream->NotEnded()) // this means a loose end string marker...wierd
				{
					result.second = tokenBuffer.ToString();
					break;
				}

				if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
				{
					result.first = false;
					break;
				}

				if('>' == buffer)
				{
					tokenBuffer.Write(&buffer,1);
					result.second = tokenBuffer.ToString();
					break;
				}
				else
				{
					// hex string loose end
					SaveTokenBuffer(buffer);
					result.second = tokenBuffer.ToString();
					break;
				}

				break;
			}

			default: // regular token. read till next breaker or whitespace
			{
				while(mStream->NotEnded())
				{
					if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
					{
						result.first = false;
						break;
					}
					if(IsPDFWhiteSpace(buffer))
					{
						break;
					}
					else if(IsPDFEntityBreaker(buffer))
					{
						SaveTokenBuffer(buffer); // for a non-space breaker, save the token for next token read
						break;
					}
					else
						tokenBuffer.Write(&buffer,1);
				}
				result.second = tokenBuffer.ToString();

				if(result.first && mStream->NotEnded() && scStream == result.second)
				{
					// k. a bit of a special case here for streams. the reading changes after the keyword "stream",
					// essentially forcing the next content to start after either CR, CR-LF or LF. so there might be a little
					// skip to do here.
					// if indeed there's a "stream", so the last buffer read should have been either CR or LF, which means (respectively)
					// that we should either skip one more "LF" or do nothing (based on what was parsed)

					// verify that when whitespaces are finished buffer is either CR or LF, and behave accordingly
					while(mStream->NotEnded()) {
						if (!IsPDFWhiteSpace(buffer)) {
							result.first = false; // something wrong! not whitespace
							break;
						}

						if (scCR == buffer) // CR. should be CR-LF or CR alone
						{
							if (GetNextByteForToken(buffer) == PDFHummus::eSuccess)
							{
								// if CR-LF treat as a single line, otherwise put back token nicely cause CR is alone
								if (buffer != scLF)
									SaveTokenBuffer(buffer);
							}
							result.first = true;
							break;
						}
						else if (scLF == buffer) {
							result.first = true;
							break;
						} // else - some other white space

						if (GetNextByteForToken(buffer) != PDFHummus::eSuccess) {
							result.first = false; //can't read but not eof. fail
							break;
						}
					}
				}
				break;
			}

		}

	}while(false);

	return result;
}

void PDFParserTokenizer::SkipTillToken()
{
	Byte buffer = 0;

	if(!mStream)
		return;

	// skip till hitting first non space, or segment end
	while(mStream->NotEnded())
	{
		if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
			break;

		if(!IsPDFWhiteSpace(buffer))
		{
			SaveTokenBuffer(buffer);
			break;
		}
	}
}

EStatusCode PDFParserTokenizer::GetNextByteForToken(Byte& outByte)
{
	++mStreamPositionTracker; // advance position tracker, because we are reading the next byte.
	if(mHasTokenBuffer)
	{
		outByte = mTokenBuffer;
		mHasTokenBuffer = false;
		return PDFHummus::eSuccess;
	}
	else
		return (mStream->Read(&outByte,1) != 1) ? PDFHummus::eFailure:PDFHummus::eSuccess;
}

static const Byte scWhiteSpaces[] = {0,0x9,0xA,0xC,0xD,0x20};
bool PDFParserTokenizer::IsPDFWhiteSpace(Byte inCharacter)
{
	bool isWhiteSpace = false;
	for(int i=0; i < 6 && !isWhiteSpace; ++i)
		isWhiteSpace =  (scWhiteSpaces[i] == inCharacter);
	return isWhiteSpace;
}

void PDFParserTokenizer::SaveTokenBuffer(Byte inToSave)
{
	mHasTokenBuffer = true;
	mTokenBuffer = inToSave;
	--mStreamPositionTracker; // decreasing position trakcer, because it is as if the byte is put back in the stream
}

IOBasicTypes::LongFilePositionType PDFParserTokenizer::GetReadBufferSize()
{
	return mHasTokenBuffer ? 1 : 0;
}

static const Byte scEntityBreakers[] = {'(',')','<','>',']','[','{','}','/','%'};
bool PDFParserTokenizer::IsPDFEntityBreaker(Byte inCharacter)
{
	bool isEntityBreak = false;
	for(int i=0; i < 10 && !isEntityBreak; ++i)
		isEntityBreak =  (scEntityBreakers[i] == inCharacter);
	return isEntityBreak;
}

LongFilePositionType PDFParserTokenizer::GetRecentTokenPosition()
{
	return mRecentTokenPosition;
}<commit_msg>allow zero length hex strings<commit_after>/*
   Source File : PDFParserTokenizer.cpp

   Copyright 2011 Gal Kahana PDFWriter

   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 "PDFParserTokenizer.h"
#include "IByteReader.h"
#include "OutputStringBufferStream.h"

using namespace PDFHummus;
using namespace IOBasicTypes;

PDFParserTokenizer::PDFParserTokenizer(void)
{
	mStream = NULL;
	ResetReadState();
}

PDFParserTokenizer::~PDFParserTokenizer(void)
{
}

void PDFParserTokenizer::SetReadStream(IByteReader* inSourceStream)
{
	mStream = inSourceStream;
	ResetReadState();
}

void PDFParserTokenizer::ResetReadState()
{
	mHasTokenBuffer = false;
	mStreamPositionTracker = 0;
	mRecentTokenPosition = 0;
}

void PDFParserTokenizer::ResetReadState(const PDFParserTokenizer& inExternalTokenizer)
{
	mTokenBuffer = inExternalTokenizer.mTokenBuffer;
	mHasTokenBuffer = inExternalTokenizer.mHasTokenBuffer;
	mStreamPositionTracker = inExternalTokenizer.mStreamPositionTracker;
	mRecentTokenPosition = inExternalTokenizer.mRecentTokenPosition;
}

static const Byte scBackSlash[] = {'\\'};
static const std::string scStream = "stream";
static const char scCR = '\r';
static const char scLF = '\n';
BoolAndString PDFParserTokenizer::GetNextToken()
{
	BoolAndString result;
	Byte buffer;
	OutputStringBufferStream tokenBuffer;

	if(!mStream || (!mStream->NotEnded() && !mHasTokenBuffer))
	{
		result.first = false;
		return result;
	}

	do
	{
		SkipTillToken();
		if(!mStream->NotEnded())
		{
			result.first = false;
			break;
		}

		// before reading the first byte save the token position, for external queries
		mRecentTokenPosition = mStreamPositionTracker;

		// get the first byte of the token
		if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
		{
			result.first = false;
			break;
		}
		tokenBuffer.Write(&buffer,1);

		result.first = true; // will only be changed to false in case of read error

		// now determine how to continue based on the first byte of the token (there are some special cases)
		switch(buffer)
		{

			case '%':
			{
				// for a comment, the token goes on till the end of line marker [not including]
				while(mStream->NotEnded())
				{
					if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
					{
						result.first = false;
						break;
					}
					if(0xD == buffer|| 0xA == buffer)
						break;
					tokenBuffer.Write(&buffer,1);
				}
				result.second = tokenBuffer.ToString();
				break;
			}

			case '(':
			{
				// for a literal string, the token goes on until the balanced-closing right paranthesis
				int balanceLevel = 1;
				bool backSlashEncountered = false;
				while(balanceLevel > 0 && mStream->NotEnded())
				{
					if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
					{
						result.first = false;
						break;
					}

					if(backSlashEncountered)
					{
						backSlashEncountered = false;
						if(0xA == buffer || 0xD == buffer)
						{
							// ignore backslash and newline. might also need to read extra
							// for cr-ln
							if(0xD == buffer && mStream->NotEnded())
							{
								if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
								{
									result.first = false;
									break;
								}
								if(buffer != 0xA)
									SaveTokenBuffer(buffer);
							}
						}
						else
						{
							tokenBuffer.Write(scBackSlash,1);
							tokenBuffer.Write(&buffer,1);
						}
					}
					else
					{
						if('\\' == buffer)
						{
							backSlashEncountered = true;
							continue;
						}
						else if('(' == buffer)
							++balanceLevel;
						else if(')' == buffer)
							--balanceLevel;
						tokenBuffer.Write(&buffer,1);
					}
				}
				if(result.first)
					result.second = tokenBuffer.ToString();
				break;
			}

			case '<':
			{
				// k. this might be a dictionary start marker or a hax string start. depending on whether it has a < following it or not

				// Hex string, read till end of hex string marker
				if(!mStream->NotEnded())
				{
					result.second = tokenBuffer.ToString();
					break;
				}

				if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
				{
						result.first = false;
						break;
				}

				if('<' == buffer)
				{
					// Dictionary start marker
					tokenBuffer.Write(&buffer,1);
					result.second = tokenBuffer.ToString();
					break;
				}
				else
				{
					// Hex string

					tokenBuffer.Write(&buffer,1);

					while(mStream->NotEnded() && buffer != '>')
					{
						if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
						{
							result.first = false;
							break;
						}

						if(!IsPDFWhiteSpace(buffer))
							tokenBuffer.Write(&buffer,1);
					}
				}
				result.second = tokenBuffer.ToString();
				break;
			}
			case '[': // for all array or executable tokanizers, the tokanizer is just the mark
			case ']':
			case '{':
			case '}':
				result.second = tokenBuffer.ToString();
				break;
			case '>': // parse end dictionary marker as a single entity or a hex string end marker
			{
				if(!mStream->NotEnded()) // this means a loose end string marker...wierd
				{
					result.second = tokenBuffer.ToString();
					break;
				}

				if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
				{
					result.first = false;
					break;
				}

				if('>' == buffer)
				{
					tokenBuffer.Write(&buffer,1);
					result.second = tokenBuffer.ToString();
					break;
				}
				else
				{
					// hex string loose end
					SaveTokenBuffer(buffer);
					result.second = tokenBuffer.ToString();
					break;
				}

				break;
			}

			default: // regular token. read till next breaker or whitespace
			{
				while(mStream->NotEnded())
				{
					if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
					{
						result.first = false;
						break;
					}
					if(IsPDFWhiteSpace(buffer))
					{
						break;
					}
					else if(IsPDFEntityBreaker(buffer))
					{
						SaveTokenBuffer(buffer); // for a non-space breaker, save the token for next token read
						break;
					}
					else
						tokenBuffer.Write(&buffer,1);
				}
				result.second = tokenBuffer.ToString();

				if(result.first && mStream->NotEnded() && scStream == result.second)
				{
					// k. a bit of a special case here for streams. the reading changes after the keyword "stream",
					// essentially forcing the next content to start after either CR, CR-LF or LF. so there might be a little
					// skip to do here.
					// if indeed there's a "stream", so the last buffer read should have been either CR or LF, which means (respectively)
					// that we should either skip one more "LF" or do nothing (based on what was parsed)

					// verify that when whitespaces are finished buffer is either CR or LF, and behave accordingly
					while(mStream->NotEnded()) {
						if (!IsPDFWhiteSpace(buffer)) {
							result.first = false; // something wrong! not whitespace
							break;
						}

						if (scCR == buffer) // CR. should be CR-LF or CR alone
						{
							if (GetNextByteForToken(buffer) == PDFHummus::eSuccess)
							{
								// if CR-LF treat as a single line, otherwise put back token nicely cause CR is alone
								if (buffer != scLF)
									SaveTokenBuffer(buffer);
							}
							result.first = true;
							break;
						}
						else if (scLF == buffer) {
							result.first = true;
							break;
						} // else - some other white space

						if (GetNextByteForToken(buffer) != PDFHummus::eSuccess) {
							result.first = false; //can't read but not eof. fail
							break;
						}
					}
				}
				break;
			}

		}

	}while(false);

	return result;
}

void PDFParserTokenizer::SkipTillToken()
{
	Byte buffer = 0;

	if(!mStream)
		return;

	// skip till hitting first non space, or segment end
	while(mStream->NotEnded())
	{
		if(GetNextByteForToken(buffer) != PDFHummus::eSuccess)
			break;

		if(!IsPDFWhiteSpace(buffer))
		{
			SaveTokenBuffer(buffer);
			break;
		}
	}
}

EStatusCode PDFParserTokenizer::GetNextByteForToken(Byte& outByte)
{
	++mStreamPositionTracker; // advance position tracker, because we are reading the next byte.
	if(mHasTokenBuffer)
	{
		outByte = mTokenBuffer;
		mHasTokenBuffer = false;
		return PDFHummus::eSuccess;
	}
	else
		return (mStream->Read(&outByte,1) != 1) ? PDFHummus::eFailure:PDFHummus::eSuccess;
}

static const Byte scWhiteSpaces[] = {0,0x9,0xA,0xC,0xD,0x20};
bool PDFParserTokenizer::IsPDFWhiteSpace(Byte inCharacter)
{
	bool isWhiteSpace = false;
	for(int i=0; i < 6 && !isWhiteSpace; ++i)
		isWhiteSpace =  (scWhiteSpaces[i] == inCharacter);
	return isWhiteSpace;
}

void PDFParserTokenizer::SaveTokenBuffer(Byte inToSave)
{
	mHasTokenBuffer = true;
	mTokenBuffer = inToSave;
	--mStreamPositionTracker; // decreasing position trakcer, because it is as if the byte is put back in the stream
}

IOBasicTypes::LongFilePositionType PDFParserTokenizer::GetReadBufferSize()
{
	return mHasTokenBuffer ? 1 : 0;
}

static const Byte scEntityBreakers[] = {'(',')','<','>',']','[','{','}','/','%'};
bool PDFParserTokenizer::IsPDFEntityBreaker(Byte inCharacter)
{
	bool isEntityBreak = false;
	for(int i=0; i < 10 && !isEntityBreak; ++i)
		isEntityBreak =  (scEntityBreakers[i] == inCharacter);
	return isEntityBreak;
}

LongFilePositionType PDFParserTokenizer::GetRecentTokenPosition()
{
	return mRecentTokenPosition;
}<|endoftext|>


<commit_before>/**
 * @file
 *
 * @ingroup pwg2_forward_scripts
 */

/**
 * Run first pass of the analysis - that is read in ESD and produce AOD
 *
 * @param esddir    ESD input directory. Any file matching the pattern
 *                  *AliESDs*.root are added to the chain
 * @param nEvents   Number of events to process.  If 0 or less, then
 *                  all events are analysed
 * @param proof     Run in proof mode
 * @param mc        Run over MC data
 *
 * If PROOF mode is selected, then Terminate will be run on the master node
 * in any case.
 *
 *
 * @ingroup pwg2_forward_scripts
 */
void MakeAOD(const char* esddir,
	     Int_t       nEvents=-1,
	     Int_t       proof=0,
	     Bool_t      mc=false)
{
  // --- Libraries to load -------------------------------------------
  gROOT->Macro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadLibs.C");

  // --- Check for proof mode, and possibly upload pars --------------
  if (proof> 0) {
    gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadPars.C");
    LoadPars(proof);
  }

  // --- Our data chain ----------------------------------------------
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/MakeChain.C");
  TChain* chain = MakeChain("ESD", esddir,true);
  // If 0 or less events is select, choose all
  if (nEvents <= 0) nEvents = chain->GetEntries();

  // --- Creating the manager and handlers ---------------------------
  AliAnalysisManager *mgr  = new AliAnalysisManager("Forward Train",
						    "Forward multiplicity");
  AliAnalysisManager::SetCommonFileName("forward.root");

  // --- ESD input handler -------------------------------------------
  AliESDInputHandler *esdHandler = new AliESDInputHandler();
  esdHandler->SetInactiveBranches(// "AliESDRun "
				  // "AliESDHeader "
				  // "AliESDZDC "
				  // "AliESDFMD "
				  // "AliESDVZERO "
				  "AliESDTZERO "
				  "TPCVertex "
				  // "SPDVertex "
				  // "PrimaryVertex "
				  // "AliMultiplicity "
				  "PHOSTrigger "
				  "EMCALTrigger "
				  "SPDPileupVertices "
				  "TrkPileupVertices "
				  // "Tracks "
				  "MuonTracks "
				  "PmdTracks "
				  "TrdTracks "
				  "V0s "
				  "Cascades "
				  "Kinks "
				  "CaloClusters "
				  "EMCALLCells "
				  "PHOSCells "
				  "AliRawDataErrorLogs "
				  "ALIESDCACORDE "
				  "HLTGlobalTrigger");
  mgr->SetInputEventHandler(esdHandler);

  // --- Monte Carlo handler -----------------------------------------
  if (mc) {
    AliMCEventHandler* mcHandler = new AliMCEventHandler();
    mgr->SetMCtruthEventHandler(mcHandler);
    mcHandler->SetReadTR(true);
  }

  // --- AOD output handler ------------------------------------------
  AliAODHandler* aodHandler   = new AliAODHandler();
  mgr->SetOutputEventHandler(aodHandler);
  aodHandler->SetOutputFileName("AliAODs.root");

  // --- Add tasks ---------------------------------------------------
  // Physics selection
  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
  AddTaskPhysicsSelection(mc, kTRUE, kTRUE);

#if 1
  // Centrality
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/Compile.C");
  // gDebug = 10;
  Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskCopyHeader.C","");
  // gDebug = 10;
  Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/AliESDCentrality.C","");
  // gDebug = 0;
  AddTaskCopyHeader();

  // Central multiplicity
  // Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskCentralMult.C","");
  // AddTaskCentralMult();
#endif

  // FMD
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskFMD.C");
  AddTaskFMD(mc);

  // --- Run the analysis --------------------------------------------
  TStopwatch t;
  if (!mgr->InitAnalysis()) {
    Error("MakeAOD", "Failed to initialize analysis train!");
    return;
  }
  // Skip terminate if we're so requested and not in Proof or full mode
  mgr->SetSkipTerminate(false);
  // Some informative output
  mgr->PrintStatus();
  // mgr->SetDebugLevel(3);
  if (mgr->GetDebugLevel() < 1 && !proof)
    mgr->SetUseProgressBar(kTRUE,100);

  // Run the train
  t.Start();
  Printf("=== RUNNING ANALYSIS ==================================");
  mgr->StartAnalysis(proof ? "proof" : "local", chain, nEvents);
  t.Stop();
  t.Print();
}
//
// EOF
//
<commit_msg>Add SPD cluster method<commit_after>/**
 * @file
 *
 * @ingroup pwg2_forward_scripts
 */

/**
 * Run first pass of the analysis - that is read in ESD and produce AOD
 *
 * @param esddir    ESD input directory. Any file matching the pattern
 *                  *AliESDs*.root are added to the chain
 * @param nEvents   Number of events to process.  If 0 or less, then
 *                  all events are analysed
 * @param proof     Run in proof mode
 * @param mc        Run over MC data
 *
 * If PROOF mode is selected, then Terminate will be run on the master node
 * in any case.
 *
 *
 * @ingroup pwg2_forward_scripts
 */
void MakeAOD(const char* esddir,
	     Int_t       nEvents=-1,
	     Int_t       proof=0,
	     Bool_t      mc=false)
{
  // --- Libraries to load -------------------------------------------
  gROOT->Macro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadLibs.C");

  // --- Check for proof mode, and possibly upload pars --------------
  if (proof> 0) {
    gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/LoadPars.C");
    LoadPars(proof);
  }

  // --- Our data chain ----------------------------------------------
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/MakeChain.C");
  TChain* chain = MakeChain("ESD", esddir,true);
  // If 0 or less events is select, choose all
  if (nEvents <= 0) nEvents = chain->GetEntries();

  // --- Creating the manager and handlers ---------------------------
  AliAnalysisManager *mgr  = new AliAnalysisManager("Forward Train",
						    "Forward multiplicity");
  AliAnalysisManager::SetCommonFileName("forward.root");

  // --- ESD input handler -------------------------------------------
  AliESDInputHandler *esdHandler = new AliESDInputHandler();
  esdHandler->SetInactiveBranches(// "AliESDRun "
				  // "AliESDHeader "
				  // "AliESDZDC "
				  // "AliESDFMD "
				  // "AliESDVZERO "
				  "AliESDTZERO "
				  "TPCVertex "
				  // "SPDVertex "
				  // "PrimaryVertex "
				  // "AliMultiplicity "
				  "PHOSTrigger "
				  "EMCALTrigger "
				  "SPDPileupVertices "
				  "TrkPileupVertices "
				  // "Tracks "
				  "MuonTracks "
				  "PmdTracks "
				  "TrdTracks "
				  "V0s "
				  "Cascades "
				  "Kinks "
				  "CaloClusters "
				  "EMCALLCells "
				  "PHOSCells "
				  "AliRawDataErrorLogs "
				  "ALIESDCACORDE "
				  "HLTGlobalTrigger");
  mgr->SetInputEventHandler(esdHandler);

  // --- Monte Carlo handler -----------------------------------------
  if (mc) {
    AliMCEventHandler* mcHandler = new AliMCEventHandler();
    mgr->SetMCtruthEventHandler(mcHandler);
    mcHandler->SetReadTR(true);
  }

  // --- AOD output handler ------------------------------------------
  AliAODHandler* aodHandler   = new AliAODHandler();
  mgr->SetOutputEventHandler(aodHandler);
  aodHandler->SetOutputFileName("AliAODs.root");

  // --- Add tasks ---------------------------------------------------
  // Physics selection
  gROOT->LoadMacro("$ALICE_ROOT/ANALYSIS/macros/AddTaskPhysicsSelection.C");
  AddTaskPhysicsSelection(mc, kTRUE, kTRUE);

#if 1
  // Centrality
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/Compile.C");
  Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskCopyHeader.C","");
  // Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/scripts/AliESDCentrality.C","");
  AddTaskCopyHeader();

  // Central multiplicity
  // Compile("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskCentralMult.C","");
  // AddTaskCentralMult();
#endif

  // FMD
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskFMD.C");
  AddTaskFMD(mc);

  // Central
  gROOT->LoadMacro("$ALICE_ROOT/PWG2/FORWARD/analysis2/AddTaskCentral.C");
  AddTaskCentral();

  // --- Run the analysis --------------------------------------------
  TStopwatch t;
  if (!mgr->InitAnalysis()) {
    Error("MakeAOD", "Failed to initialize analysis train!");
    return;
  }
  // Skip terminate if we're so requested and not in Proof or full mode
  mgr->SetSkipTerminate(false);
  // Some informative output
  mgr->PrintStatus();
  // mgr->SetDebugLevel(3);
  if (mgr->GetDebugLevel() < 1 && !proof)
    mgr->SetUseProgressBar(kTRUE,100);

  // Run the train
  t.Start();
  Printf("=== RUNNING ANALYSIS ==================================");
  mgr->StartAnalysis(proof ? "proof" : "local", chain, nEvents);
  t.Stop();
  t.Print();
}
//
// EOF
//
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "updateoperation.h"
#include <vespa/document/base/exceptions.h>
#include <vespa/document/update/documentupdate.h>
#include <cassert>

#include <vespa/log/log.h>
LOG_SETUP(".proton.feedoperation.updateoperation");

using document::BucketId;
using document::DocumentType;
using document::DocumentTypeRepo;
using document::DocumentUpdate;
using storage::spi::Timestamp;
using vespalib::make_string;

namespace proton {

UpdateOperation::UpdateOperation()
    : UpdateOperation(FeedOperation::UPDATE)
{
}

UpdateOperation::UpdateOperation(Type type)
    : DocumentOperation(type),
      _upd()
{
}

UpdateOperation::UpdateOperation(Type type, const BucketId &bucketId,
                                 const Timestamp &timestamp, const DocumentUpdate::SP &upd)
    : DocumentOperation(type, bucketId, timestamp),
      _upd(upd)
{
}

UpdateOperation::UpdateOperation(const BucketId &bucketId, const Timestamp &timestamp, const DocumentUpdate::SP &upd)
    : UpdateOperation(FeedOperation::UPDATE, bucketId, timestamp, upd)
{
}

void
UpdateOperation::serializeUpdate(vespalib::nbostream &os) const
{
    assert(getType() == UPDATE);
     _upd->serializeHEAD(os);
}

void
UpdateOperation::deserializeUpdate(vespalib::nbostream &is, const document::DocumentTypeRepo &repo)
{
    document::ByteBuffer buf(is.peek(), is.size());
    DocumentUpdate::UP update = (getType() == UPDATE_42) ? DocumentUpdate::create42(repo, buf) : DocumentUpdate::createHEAD(repo, buf);
    is.adjustReadPos(buf.getPos());
    _upd = std::move(update);
}

void
UpdateOperation::serialize(vespalib::nbostream &os) const
{
    assertValidBucketId(_upd->getId());
    DocumentOperation::serialize(os);
    serializeUpdate(os);
}

void
UpdateOperation::deserialize(vespalib::nbostream &is, const DocumentTypeRepo &repo)
{
    DocumentOperation::deserialize(is, repo);
    try {
        deserializeUpdate(is, repo);
    } catch (document::DocumentTypeNotFoundException &e) {
        LOG(warning, "Failed deserialize update operation using unknown document type '%s'",
            e.getDocumentTypeName().c_str());
        // Ignore this piece of data
        is.clear();
    }
}

void
UpdateOperation::deserializeUpdate(const DocumentTypeRepo &repo)
{
    vespalib::nbostream stream;
    serializeUpdate(stream);
    deserializeUpdate(stream, repo);
}

vespalib::string UpdateOperation::toString() const {
    return make_string("%s(%s, %s)",
                       ((getType() == FeedOperation::UPDATE_42) ? "Update42" : "Update"),
                       _upd.get() ?
                       _upd->getId().getScheme().toString().c_str() : "NULL",
                       docArgsToString().c_str());
}

} // namespace proton
<commit_msg>Add missing bytebuffer.h include<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "updateoperation.h"
#include <vespa/document/base/exceptions.h>
#include <vespa/document/update/documentupdate.h>
#include <vespa/document/util/bytebuffer.h>
#include <cassert>

#include <vespa/log/log.h>
LOG_SETUP(".proton.feedoperation.updateoperation");

using document::BucketId;
using document::DocumentType;
using document::DocumentTypeRepo;
using document::DocumentUpdate;
using storage::spi::Timestamp;
using vespalib::make_string;

namespace proton {

UpdateOperation::UpdateOperation()
    : UpdateOperation(FeedOperation::UPDATE)
{
}

UpdateOperation::UpdateOperation(Type type)
    : DocumentOperation(type),
      _upd()
{
}

UpdateOperation::UpdateOperation(Type type, const BucketId &bucketId,
                                 const Timestamp &timestamp, const DocumentUpdate::SP &upd)
    : DocumentOperation(type, bucketId, timestamp),
      _upd(upd)
{
}

UpdateOperation::UpdateOperation(const BucketId &bucketId, const Timestamp &timestamp, const DocumentUpdate::SP &upd)
    : UpdateOperation(FeedOperation::UPDATE, bucketId, timestamp, upd)
{
}

void
UpdateOperation::serializeUpdate(vespalib::nbostream &os) const
{
    assert(getType() == UPDATE);
     _upd->serializeHEAD(os);
}

void
UpdateOperation::deserializeUpdate(vespalib::nbostream &is, const document::DocumentTypeRepo &repo)
{
    document::ByteBuffer buf(is.peek(), is.size());
    DocumentUpdate::UP update = (getType() == UPDATE_42) ? DocumentUpdate::create42(repo, buf) : DocumentUpdate::createHEAD(repo, buf);
    is.adjustReadPos(buf.getPos());
    _upd = std::move(update);
}

void
UpdateOperation::serialize(vespalib::nbostream &os) const
{
    assertValidBucketId(_upd->getId());
    DocumentOperation::serialize(os);
    serializeUpdate(os);
}

void
UpdateOperation::deserialize(vespalib::nbostream &is, const DocumentTypeRepo &repo)
{
    DocumentOperation::deserialize(is, repo);
    try {
        deserializeUpdate(is, repo);
    } catch (document::DocumentTypeNotFoundException &e) {
        LOG(warning, "Failed deserialize update operation using unknown document type '%s'",
            e.getDocumentTypeName().c_str());
        // Ignore this piece of data
        is.clear();
    }
}

void
UpdateOperation::deserializeUpdate(const DocumentTypeRepo &repo)
{
    vespalib::nbostream stream;
    serializeUpdate(stream);
    deserializeUpdate(stream, repo);
}

vespalib::string UpdateOperation::toString() const {
    return make_string("%s(%s, %s)",
                       ((getType() == FeedOperation::UPDATE_42) ? "Update42" : "Update"),
                       _upd.get() ?
                       _upd->getId().getScheme().toString().c_str() : "NULL",
                       docArgsToString().c_str());
}

} // namespace proton
<|endoftext|>