<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 "net/flip/flip_network_transaction.h"

#include "base/scoped_ptr.h"
#include "base/compiler_specific.h"
#include "base/field_trial.h"
#include "base/string_util.h"
#include "base/trace_event.h"
#include "build/build_config.h"
#include "net/base/connection_type_histograms.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_basic_stream.h"
#include "net/http/http_chunked_decoder.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/ssl_client_socket.h"

using base::Time;

namespace net {

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

FlipNetworkTransaction::FlipNetworkTransaction(HttpNetworkSession* session)
    : flip_request_id_(0),
      user_callback_(0),
      user_buffer_bytes_remaining_(0),
      session_(session),
      request_(NULL),
      response_complete_(false),
      response_status_(net::OK),
      next_state_(STATE_NONE) {
}

FlipNetworkTransaction::~FlipNetworkTransaction() {
  LOG(INFO) << "FlipNetworkTransaction dead. " << this;
  if (flip_ && flip_request_id_)
    flip_->CancelStream(flip_request_id_);
}

const HttpRequestInfo* FlipNetworkTransaction::request() {
  return request_;
}

const UploadDataStream* FlipNetworkTransaction::data() {
  return request_body_stream_.get();
}

void FlipNetworkTransaction::OnRequestSent(int status) {
  if (status == OK)
    next_state_ = STATE_SEND_REQUEST_COMPLETE;
  else
    next_state_ = STATE_NONE;

  int rv = DoLoop(status);
}

void FlipNetworkTransaction::OnResponseReceived(HttpResponseInfo* response) {
  next_state_ = STATE_READ_HEADERS_COMPLETE;

  response_ = *response;  // TODO(mbelshe): avoid copy.

  int rv = DoLoop(net::OK);
}

void FlipNetworkTransaction::OnDataReceived(const char* buffer, int bytes) {
  // TODO(mbelshe): if data is received before a syn reply, this will crash.

  DCHECK(bytes >= 0);
  next_state_ = STATE_READ_BODY;

  if (bytes > 0) {
    DCHECK(buffer);

    // TODO(mbelshe): If read is pending, we should copy the data straight into
    // the read buffer here.  For now, we'll queue it always.

    IOBufferWithSize* io_buffer = new IOBufferWithSize(bytes);
    memcpy(io_buffer->data(), buffer, bytes);

    response_body_.push_back(io_buffer);
  }
  int rv = DoLoop(net::OK);
}

void FlipNetworkTransaction::OnClose(int status) {
  next_state_ = STATE_READ_BODY_COMPLETE;
  response_complete_ = true;
  response_status_ = status;
  flip_request_id_ = 0;  // TODO(mbelshe) - do we need this?
  int rv = DoLoop(status);
}

void FlipNetworkTransaction::OnCancel() {
  next_state_ = STATE_NONE;
  response_complete_ = true;
  response_status_ = net::ERR_ABORTED;
  flip_request_id_ = 0;  // TODO(mbelshe) - do we need this?
  // Clear any data in our buffer.
  while (response_body_.size())
    response_body_.pop_front();
}

int FlipNetworkTransaction::Start(const HttpRequestInfo* request_info,
                                  CompletionCallback* callback,
                                  LoadLog* load_log) {
  request_ = request_info;
  start_time_ = base::Time::Now();

  next_state_ = STATE_INIT_CONNECTION;
  int rv = DoLoop(OK);
  if (rv == ERR_IO_PENDING)
    user_callback_ = callback;
  return rv;
}

int FlipNetworkTransaction::RestartIgnoringLastError(
    CompletionCallback* callback) {
  // TODO(mbelshe): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int FlipNetworkTransaction::RestartWithCertificate(
    X509Certificate* client_cert, CompletionCallback* callback) {
  // TODO(mbelshe): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int FlipNetworkTransaction::RestartWithAuth(
    const std::wstring& username,
    const std::wstring& password,
    CompletionCallback* callback) {
  // TODO(mbelshe): implement me.
  NOTIMPLEMENTED();
  return 0;
}

int FlipNetworkTransaction::Read(IOBuffer* buf, int buf_len,
                                 CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(buf_len > 0);
  DCHECK(callback);
  DCHECK(flip_.get());

  // If we have data buffered, complete the IO immediately.
  if (response_body_.size()) {
    int bytes_read = 0;
    while (response_body_.size() && buf_len > 0) {
      scoped_refptr<IOBufferWithSize> data = response_body_.front();
      int bytes_to_copy = std::min(buf_len, data->size());
      memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
      buf_len -= bytes_to_copy;
      if (bytes_to_copy == data->size()) {
        response_body_.pop_front();
      } else {
        int bytes_remaining = data->size() - bytes_to_copy;
        IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
        memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
               bytes_remaining);
        response_body_.pop_front();
        response_body_.push_front(new_buffer);
      }
      bytes_read += bytes_to_copy;
    }
    return bytes_read;
  }

  if (response_complete_)
    return 0;  // We already finished reading this stream.

  user_callback_ = callback;
  user_buffer_ = buf;
  user_buffer_bytes_remaining_ = buf_len;
  return net::ERR_IO_PENDING;
}

const HttpResponseInfo* FlipNetworkTransaction::GetResponseInfo() const {
  return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
}

LoadState FlipNetworkTransaction::GetLoadState() const {
  switch (next_state_) {
    case STATE_INIT_CONNECTION_COMPLETE:
      if (flip_.get())
        return flip_->GetLoadState();
      return LOAD_STATE_CONNECTING;
    case STATE_SEND_REQUEST_COMPLETE:
      return LOAD_STATE_SENDING_REQUEST;
    case STATE_READ_HEADERS_COMPLETE:
      return LOAD_STATE_WAITING_FOR_RESPONSE;
    case STATE_READ_BODY_COMPLETE:
      return LOAD_STATE_READING_RESPONSE;
    default:
      return LOAD_STATE_IDLE;
  }
}

uint64 FlipNetworkTransaction::GetUploadProgress() const {
  if (!request_body_stream_.get())
    return 0;

  return request_body_stream_->position();
}

void FlipNetworkTransaction::DoHttpTransactionCallback(int rv) {
  DCHECK(rv != ERR_IO_PENDING);

  // Because IO is asynchronous from the caller, we could be completing an
  // IO even though the user hasn't issued a Read() yet.
  if (!user_callback_)
    return;

  // Since Run may result in Read being called, clear user_callback_ up front.
  CompletionCallback* c = user_callback_;
  user_callback_ = NULL;
  c->Run(rv);
}

int FlipNetworkTransaction::DoLoop(int result) {
  DCHECK(next_state_ != STATE_NONE);
  DCHECK(request_);

  if (!request_)
    return 0;

  int rv = result;
  do {
    State state = next_state_;
    next_state_ = STATE_NONE;
    switch (state) {
      case STATE_INIT_CONNECTION:
        DCHECK_EQ(OK, rv);
        rv = DoInitConnection();
        break;
      case STATE_INIT_CONNECTION_COMPLETE:
        rv = DoInitConnectionComplete(rv);
        break;
      case STATE_SEND_REQUEST:
        DCHECK_EQ(OK, rv);
        rv = DoSendRequest();
        break;
      case STATE_SEND_REQUEST_COMPLETE:
        rv = DoSendRequestComplete(rv);
        break;
      case STATE_READ_HEADERS:
        DCHECK_EQ(OK, rv);
        rv = DoReadHeaders();
        break;
      case STATE_READ_HEADERS_COMPLETE:
        // DoReadHeadersComplete only returns OK  becaue the transaction
        // could be destroyed as part of the call.
        rv = DoReadHeadersComplete(rv);
        DCHECK(rv == net::OK);
        return rv;
        break;
      case STATE_READ_BODY:
        DCHECK_EQ(OK, rv);
        rv = DoReadBody();
        // DoReadBody only returns OK  becaue the transaction could be
        // destroyed as part of the call.
        DCHECK(rv == net::OK);
        return rv;
        break;
      case STATE_READ_BODY_COMPLETE:
        // We return here because the Transaction could be destroyed after this
        // call.
        rv = DoReadBodyComplete(rv);
        DCHECK(rv == net::OK);
        return rv;
        break;
      case STATE_NONE:
        rv = ERR_FAILED;
        break;
      default:
        NOTREACHED() << "bad state";
        rv = ERR_FAILED;
        break;
    }
  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);

  return rv;
}

int FlipNetworkTransaction::DoInitConnection() {
  next_state_ = STATE_INIT_CONNECTION_COMPLETE;

  std::string host = request_->url.HostNoBrackets();
  int port = request_->url.EffectiveIntPort();

  std::string connection_group = "flip.";
  connection_group.append(host);

  HostResolver::RequestInfo resolve_info(host, port);

// TODO(mbelshe): Cleanup these testing tricks.
// If we want to use multiple connections, grab the flip session
// up front using the original domain name.
#undef USE_MULTIPLE_CONNECTIONS
#define DIVERT_URLS_TO_TEST_SERVER
#if defined(USE_MULTIPLE_CONNECTIONS) || !defined(DIVERT_URLS_TO_TEST_SERVER)
  flip_ = FlipSession::GetFlipSession(resolve_info, session_);
#endif

// Use this to divert URLs to a test server.
#ifdef DIVERT_URLS_TO_TEST_SERVER
  // Fake out this session to go to our test server.
  host = "servername";
  port = 443;
  resolve_info = HostResolver::RequestInfo(host, port);
#ifndef USE_MULTIPLE_CONNECTIONS
  flip_ = FlipSession::GetFlipSession(resolve_info, session_);
#endif  // USE_MULTIPLE_CONNECTIONS

#endif  // DIVERT_URLS_TO_TEST_SERVER

  int rv = flip_->Connect(connection_group, resolve_info, request_->priority);
  DCHECK(rv == net::OK);  // The API says it will always return OK.
  return net::OK;
}

int FlipNetworkTransaction::DoInitConnectionComplete(int result) {
  if (result < 0)
    return result;

  next_state_ = STATE_SEND_REQUEST;
  return net::OK;
}

int FlipNetworkTransaction::DoSendRequest() {
  // TODO(mbelshe): rethink this UploadDataStream wrapper.
  if (request_->upload_data)
    request_body_stream_.reset(new UploadDataStream(request_->upload_data));

  flip_request_id_ = flip_->CreateStream(this);

  if (response_complete_)
    return net::OK;

  // The FlipSession will always call us back when the send is complete.
  return net::ERR_IO_PENDING;
}

int FlipNetworkTransaction::DoSendRequestComplete(int result) {
  if (result < 0)
    return result;

  next_state_ = STATE_READ_HEADERS;
  return net::OK;
}

int FlipNetworkTransaction::DoReadHeaders() {
  // The FlipSession will always call us back when the headers have been
  // received.
  return net::ERR_IO_PENDING;
}

int FlipNetworkTransaction::DoReadHeadersComplete(int result) {
  // Notify the user that the headers are ready.
  DoHttpTransactionCallback(result);
  return net::OK;
}

int FlipNetworkTransaction::DoReadBody() {
  // The caller has not issued a read request yet.
  if (!user_callback_)
    return net::OK;

  int bytes_read = 0;
  while (response_body_.size() && user_buffer_bytes_remaining_ > 0) {
    scoped_refptr<IOBufferWithSize> data = response_body_.front();
    int bytes_to_copy = std::min(user_buffer_bytes_remaining_, data->size());
    memcpy(&(user_buffer_->data()[bytes_read]), data->data(), bytes_to_copy);
    user_buffer_bytes_remaining_ -= bytes_to_copy;
    if (bytes_to_copy == data->size()) {
      response_body_.pop_front();
    } else {
      int bytes_remaining = data->size() - bytes_to_copy;
      IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
      memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
             bytes_remaining);
      response_body_.pop_front();
      response_body_.push_front(new_buffer);
    }
    bytes_read += bytes_to_copy;
  }

  DoHttpTransactionCallback(bytes_read);
  return net::OK;
}

int FlipNetworkTransaction::DoReadBodyComplete(int result) {
  // TODO(mbelshe): record success or failure of the transaction?
  if (user_callback_)
    DoHttpTransactionCallback(result);
  return OK;
}

}  // namespace net
<commit_msg>Linux port fixup.<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 "net/flip/flip_network_transaction.h"

#include "base/scoped_ptr.h"
#include "base/compiler_specific.h"
#include "base/field_trial.h"
#include "base/string_util.h"
#include "base/trace_event.h"
#include "build/build_config.h"
#include "net/base/connection_type_histograms.h"
#include "net/base/host_resolver.h"
#include "net/base/io_buffer.h"
#include "net/base/load_flags.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/base/upload_data_stream.h"
#include "net/http/http_auth.h"
#include "net/http/http_auth_handler.h"
#include "net/http/http_basic_stream.h"
#include "net/http/http_chunked_decoder.h"
#include "net/http/http_network_session.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_util.h"
#include "net/socket/client_socket_factory.h"
#include "net/socket/ssl_client_socket.h"

using base::Time;

namespace net {

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

FlipNetworkTransaction::FlipNetworkTransaction(HttpNetworkSession* session)
    : flip_request_id_(0),
      user_callback_(0),
      user_buffer_bytes_remaining_(0),
      session_(session),
      request_(NULL),
      response_complete_(false),
      response_status_(net::OK),
      next_state_(STATE_NONE) {
}

FlipNetworkTransaction::~FlipNetworkTransaction() {
  LOG(INFO) << "FlipNetworkTransaction dead. " << this;
  if (flip_ && flip_request_id_)
    flip_->CancelStream(flip_request_id_);
}

const HttpRequestInfo* FlipNetworkTransaction::request() {
  return request_;
}

const UploadDataStream* FlipNetworkTransaction::data() {
  return request_body_stream_.get();
}

void FlipNetworkTransaction::OnRequestSent(int status) {
  if (status == OK)
    next_state_ = STATE_SEND_REQUEST_COMPLETE;
  else
    next_state_ = STATE_NONE;

  DoLoop(status);
}

void FlipNetworkTransaction::OnResponseReceived(HttpResponseInfo* response) {
  next_state_ = STATE_READ_HEADERS_COMPLETE;

  response_ = *response;  // TODO(mbelshe): avoid copy.

  DoLoop(net::OK);
}

void FlipNetworkTransaction::OnDataReceived(const char* buffer, int bytes) {
  // TODO(mbelshe): if data is received before a syn reply, this will crash.

  DCHECK(bytes >= 0);
  next_state_ = STATE_READ_BODY;

  if (bytes > 0) {
    DCHECK(buffer);

    // TODO(mbelshe): If read is pending, we should copy the data straight into
    // the read buffer here.  For now, we'll queue it always.

    IOBufferWithSize* io_buffer = new IOBufferWithSize(bytes);
    memcpy(io_buffer->data(), buffer, bytes);

    response_body_.push_back(io_buffer);
  }
  DoLoop(net::OK);
}

void FlipNetworkTransaction::OnClose(int status) {
  next_state_ = STATE_READ_BODY_COMPLETE;
  response_complete_ = true;
  response_status_ = status;
  flip_request_id_ = 0;  // TODO(mbelshe) - do we need this?
  DoLoop(status);
}

void FlipNetworkTransaction::OnCancel() {
  next_state_ = STATE_NONE;
  response_complete_ = true;
  response_status_ = net::ERR_ABORTED;
  flip_request_id_ = 0;  // TODO(mbelshe) - do we need this?
  // Clear any data in our buffer.
  while (response_body_.size())
    response_body_.pop_front();
}

int FlipNetworkTransaction::Start(const HttpRequestInfo* request_info,
                                  CompletionCallback* callback,
                                  LoadLog* load_log) {
  request_ = request_info;
  start_time_ = base::Time::Now();

  next_state_ = STATE_INIT_CONNECTION;
  int rv = DoLoop(OK);
  if (rv == ERR_IO_PENDING)
    user_callback_ = callback;
  return rv;
}

int FlipNetworkTransaction::RestartIgnoringLastError(
    CompletionCallback* callback) {
  // TODO(mbelshe): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int FlipNetworkTransaction::RestartWithCertificate(
    X509Certificate* client_cert, CompletionCallback* callback) {
  // TODO(mbelshe): implement me.
  NOTIMPLEMENTED();
  return ERR_NOT_IMPLEMENTED;
}

int FlipNetworkTransaction::RestartWithAuth(
    const std::wstring& username,
    const std::wstring& password,
    CompletionCallback* callback) {
  // TODO(mbelshe): implement me.
  NOTIMPLEMENTED();
  return 0;
}

int FlipNetworkTransaction::Read(IOBuffer* buf, int buf_len,
                                 CompletionCallback* callback) {
  DCHECK(buf);
  DCHECK(buf_len > 0);
  DCHECK(callback);
  DCHECK(flip_.get());

  // If we have data buffered, complete the IO immediately.
  if (response_body_.size()) {
    int bytes_read = 0;
    while (response_body_.size() && buf_len > 0) {
      scoped_refptr<IOBufferWithSize> data = response_body_.front();
      int bytes_to_copy = std::min(buf_len, data->size());
      memcpy(&(buf->data()[bytes_read]), data->data(), bytes_to_copy);
      buf_len -= bytes_to_copy;
      if (bytes_to_copy == data->size()) {
        response_body_.pop_front();
      } else {
        int bytes_remaining = data->size() - bytes_to_copy;
        IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
        memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
               bytes_remaining);
        response_body_.pop_front();
        response_body_.push_front(new_buffer);
      }
      bytes_read += bytes_to_copy;
    }
    return bytes_read;
  }

  if (response_complete_)
    return 0;  // We already finished reading this stream.

  user_callback_ = callback;
  user_buffer_ = buf;
  user_buffer_bytes_remaining_ = buf_len;
  return net::ERR_IO_PENDING;
}

const HttpResponseInfo* FlipNetworkTransaction::GetResponseInfo() const {
  return (response_.headers || response_.ssl_info.cert) ? &response_ : NULL;
}

LoadState FlipNetworkTransaction::GetLoadState() const {
  switch (next_state_) {
    case STATE_INIT_CONNECTION_COMPLETE:
      if (flip_.get())
        return flip_->GetLoadState();
      return LOAD_STATE_CONNECTING;
    case STATE_SEND_REQUEST_COMPLETE:
      return LOAD_STATE_SENDING_REQUEST;
    case STATE_READ_HEADERS_COMPLETE:
      return LOAD_STATE_WAITING_FOR_RESPONSE;
    case STATE_READ_BODY_COMPLETE:
      return LOAD_STATE_READING_RESPONSE;
    default:
      return LOAD_STATE_IDLE;
  }
}

uint64 FlipNetworkTransaction::GetUploadProgress() const {
  if (!request_body_stream_.get())
    return 0;

  return request_body_stream_->position();
}

void FlipNetworkTransaction::DoHttpTransactionCallback(int rv) {
  DCHECK(rv != ERR_IO_PENDING);

  // Because IO is asynchronous from the caller, we could be completing an
  // IO even though the user hasn't issued a Read() yet.
  if (!user_callback_)
    return;

  // Since Run may result in Read being called, clear user_callback_ up front.
  CompletionCallback* c = user_callback_;
  user_callback_ = NULL;
  c->Run(rv);
}

int FlipNetworkTransaction::DoLoop(int result) {
  DCHECK(next_state_ != STATE_NONE);
  DCHECK(request_);

  if (!request_)
    return 0;

  int rv = result;
  do {
    State state = next_state_;
    next_state_ = STATE_NONE;
    switch (state) {
      case STATE_INIT_CONNECTION:
        DCHECK_EQ(OK, rv);
        rv = DoInitConnection();
        break;
      case STATE_INIT_CONNECTION_COMPLETE:
        rv = DoInitConnectionComplete(rv);
        break;
      case STATE_SEND_REQUEST:
        DCHECK_EQ(OK, rv);
        rv = DoSendRequest();
        break;
      case STATE_SEND_REQUEST_COMPLETE:
        rv = DoSendRequestComplete(rv);
        break;
      case STATE_READ_HEADERS:
        DCHECK_EQ(OK, rv);
        rv = DoReadHeaders();
        break;
      case STATE_READ_HEADERS_COMPLETE:
        // DoReadHeadersComplete only returns OK  becaue the transaction
        // could be destroyed as part of the call.
        rv = DoReadHeadersComplete(rv);
        DCHECK(rv == net::OK);
        return rv;
        break;
      case STATE_READ_BODY:
        DCHECK_EQ(OK, rv);
        rv = DoReadBody();
        // DoReadBody only returns OK  becaue the transaction could be
        // destroyed as part of the call.
        DCHECK(rv == net::OK);
        return rv;
        break;
      case STATE_READ_BODY_COMPLETE:
        // We return here because the Transaction could be destroyed after this
        // call.
        rv = DoReadBodyComplete(rv);
        DCHECK(rv == net::OK);
        return rv;
        break;
      case STATE_NONE:
        rv = ERR_FAILED;
        break;
      default:
        NOTREACHED() << "bad state";
        rv = ERR_FAILED;
        break;
    }
  } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);

  return rv;
}

int FlipNetworkTransaction::DoInitConnection() {
  next_state_ = STATE_INIT_CONNECTION_COMPLETE;

  std::string host = request_->url.HostNoBrackets();
  int port = request_->url.EffectiveIntPort();

  std::string connection_group = "flip.";
  connection_group.append(host);

  HostResolver::RequestInfo resolve_info(host, port);

// TODO(mbelshe): Cleanup these testing tricks.
// If we want to use multiple connections, grab the flip session
// up front using the original domain name.
#undef USE_MULTIPLE_CONNECTIONS
#define DIVERT_URLS_TO_TEST_SERVER
#if defined(USE_MULTIPLE_CONNECTIONS) || !defined(DIVERT_URLS_TO_TEST_SERVER)
  flip_ = FlipSession::GetFlipSession(resolve_info, session_);
#endif

// Use this to divert URLs to a test server.
#ifdef DIVERT_URLS_TO_TEST_SERVER
  // Fake out this session to go to our test server.
  host = "servername";
  port = 443;
  resolve_info = HostResolver::RequestInfo(host, port);
#ifndef USE_MULTIPLE_CONNECTIONS
  flip_ = FlipSession::GetFlipSession(resolve_info, session_);
#endif  // USE_MULTIPLE_CONNECTIONS

#endif  // DIVERT_URLS_TO_TEST_SERVER

  int rv = flip_->Connect(connection_group, resolve_info, request_->priority);
  DCHECK(rv == net::OK);  // The API says it will always return OK.
  return net::OK;
}

int FlipNetworkTransaction::DoInitConnectionComplete(int result) {
  if (result < 0)
    return result;

  next_state_ = STATE_SEND_REQUEST;
  return net::OK;
}

int FlipNetworkTransaction::DoSendRequest() {
  // TODO(mbelshe): rethink this UploadDataStream wrapper.
  if (request_->upload_data)
    request_body_stream_.reset(new UploadDataStream(request_->upload_data));

  flip_request_id_ = flip_->CreateStream(this);

  if (response_complete_)
    return net::OK;

  // The FlipSession will always call us back when the send is complete.
  return net::ERR_IO_PENDING;
}

int FlipNetworkTransaction::DoSendRequestComplete(int result) {
  if (result < 0)
    return result;

  next_state_ = STATE_READ_HEADERS;
  return net::OK;
}

int FlipNetworkTransaction::DoReadHeaders() {
  // The FlipSession will always call us back when the headers have been
  // received.
  return net::ERR_IO_PENDING;
}

int FlipNetworkTransaction::DoReadHeadersComplete(int result) {
  // Notify the user that the headers are ready.
  DoHttpTransactionCallback(result);
  return net::OK;
}

int FlipNetworkTransaction::DoReadBody() {
  // The caller has not issued a read request yet.
  if (!user_callback_)
    return net::OK;

  int bytes_read = 0;
  while (response_body_.size() && user_buffer_bytes_remaining_ > 0) {
    scoped_refptr<IOBufferWithSize> data = response_body_.front();
    int bytes_to_copy = std::min(user_buffer_bytes_remaining_, data->size());
    memcpy(&(user_buffer_->data()[bytes_read]), data->data(), bytes_to_copy);
    user_buffer_bytes_remaining_ -= bytes_to_copy;
    if (bytes_to_copy == data->size()) {
      response_body_.pop_front();
    } else {
      int bytes_remaining = data->size() - bytes_to_copy;
      IOBufferWithSize* new_buffer = new IOBufferWithSize(bytes_remaining);
      memcpy(new_buffer->data(), &(data->data()[bytes_to_copy]),
             bytes_remaining);
      response_body_.pop_front();
      response_body_.push_front(new_buffer);
    }
    bytes_read += bytes_to_copy;
  }

  DoHttpTransactionCallback(bytes_read);
  return net::OK;
}

int FlipNetworkTransaction::DoReadBodyComplete(int result) {
  // TODO(mbelshe): record success or failure of the transaction?
  if (user_callback_)
    DoHttpTransactionCallback(result);
  return OK;
}

}  // namespace net
<|endoftext|>


<commit_before>/*
 * opencog/atoms/reduct/MinusLink.cc
 *
 * Copyright (C) 2015, 2018 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atoms/atom_types/atom_types.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/NumberNode.h>
#include "MinusLink.h"
#include "PlusLink.h"

using namespace opencog;

MinusLink::MinusLink(const HandleSeq& oset, Type t)
    : PlusLink(oset, t)
{
	init();
}

MinusLink::MinusLink(const Handle& a, const Handle& b)
    : PlusLink({a, b}, MINUS_LINK)
{
	init();
}

MinusLink::MinusLink(const Link& l)
    : PlusLink(l)
{
	init();
}

void MinusLink::init(void)
{
	Type tscope = get_type();
	if (not nameserver().isA(tscope, MINUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a MinusLink");

	_commutative = false;
	knil = createNumberNode(0);

	// Disallow unary Minus. This makes things easier, overall.
	if (1 == _outgoing.size())
		_outgoing.insert(_outgoing.begin(), HandleCast(knil));
}

static inline double get_double(const ValuePtr& pap)
{
	return NumberNodeCast(pap)->get_value();
}

ValuePtr MinusLink::kons(const ValuePtr& fi, const ValuePtr& fj) const
{
	// Try to yank out values, if possible.
	ValuePtr vi(get_value(fi));
	Type vitype = vi->get_type();

	ValuePtr vj(get_value(fj));
	Type vjtype = vj->get_type();

	// Are they numbers?
	if (NUMBER_NODE == vitype and NUMBER_NODE == vjtype)
	{
		double diff = get_double(vi) - get_double(vj);
		return createNumberNode(diff);
	}

	// If vj is zero, just drop it.
	if (NUMBER_NODE == vjtype and content_eq(HandleCast(vj), zero))
		return vi;

	// Collapse (3 - (5 + x)) and (3 - (x + 5))
	if (NUMBER_NODE == vitype and PLUS_LINK == vjtype)
	{
		Handle summand(HandleCast(vj)->getOutgoingAtom(0));
		Handle addend(HandleCast(vj)->getOutgoingAtom(1));
		if (NUMBER_NODE == summand->get_type())
		{
			double sum = get_double(vi) - get_double(summand);
			Handle hsum(createNumberNode(sum));
			return createMinusLink(hsum, addend);
		}
		if (NUMBER_NODE == addend->get_type())
		{
			double sum = get_double(vi) - get_double(addend);
			Handle hsum(createNumberNode(sum));
			return createMinusLink(hsum, summand);
		}
	}

	// Collapse ((x + 13) - 6) and ((13 + x) - 6)
	if (PLUS_LINK == vitype and NUMBER_NODE == vjtype)
	{
		Handle summand(HandleCast(vi)->getOutgoingAtom(0));
		Handle addend(HandleCast(vi)->getOutgoingAtom(1));
		if (NUMBER_NODE == summand->get_type())
		{
			double diff = get_double(summand) - get_double(vj);
			Handle hdiff(createNumberNode(diff));
			if (content_eq(hdiff, zero))
				return addend;
			return createPlusLink(addend, hdiff);
		}
		if (NUMBER_NODE == addend->get_type())
		{
			double diff = get_double(addend) - get_double(vj);
			Handle hdiff(createNumberNode(diff));
			if (content_eq(hdiff, zero))
				return summand;
			return createPlusLink(summand, hdiff);
		}
	}
	// ------------------------------------------------------------------
	// Values
	// Scalar minus vector
	if (NUMBER_NODE == vitype and nameserver().isA(vjtype, FLOAT_VALUE))
	{
		FloatValuePtr mj = FloatValueCast(times(-1.0, FloatValueCast(vj)));
		return plus(get_double(vi), mj);
	}

	// Vector minus scalar
	if (nameserver().isA(vitype, FLOAT_VALUE) and NUMBER_NODE == vjtype)
	{
		return plus(-get_double(vj), FloatValueCast(vi));
	}

	// Vector times vector
	if (nameserver().isA(vitype, FLOAT_VALUE) and nameserver().isA(vjtype, FLOAT_VALUE))
	{
		FloatValuePtr mj = FloatValueCast(times(-1.0, FloatValueCast(vj)));
		return plus(FloatValueCast(vi), mj);
	}

	Handle hi(HandleCast(vi));
	if (nullptr == hi) hi= HandleCast(fi);

	Handle hj(HandleCast(vj));
	if (nullptr == hj) hj= HandleCast(fj);

	// If we are here, we've been asked to subtract two things,
	// but they are not of a type that we know how to subtract.
	return createMinusLink(hi, hj);
}

DEFINE_LINK_FACTORY(MinusLink, MINUS_LINK)

// ============================================================
<commit_msg>Actually, the first argument is called the augend<commit_after>/*
 * opencog/atoms/reduct/MinusLink.cc
 *
 * Copyright (C) 2015, 2018 Linas Vepstas
 * All Rights Reserved
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <opencog/atoms/atom_types/atom_types.h>
#include <opencog/atoms/base/ClassServer.h>
#include <opencog/atoms/core/NumberNode.h>
#include "MinusLink.h"
#include "PlusLink.h"

using namespace opencog;

MinusLink::MinusLink(const HandleSeq& oset, Type t)
    : PlusLink(oset, t)
{
	init();
}

MinusLink::MinusLink(const Handle& a, const Handle& b)
    : PlusLink({a, b}, MINUS_LINK)
{
	init();
}

MinusLink::MinusLink(const Link& l)
    : PlusLink(l)
{
	init();
}

void MinusLink::init(void)
{
	Type tscope = get_type();
	if (not nameserver().isA(tscope, MINUS_LINK))
		throw InvalidParamException(TRACE_INFO, "Expecting a MinusLink");

	_commutative = false;
	knil = createNumberNode(0);

	// Disallow unary Minus. This makes things easier, overall.
	if (1 == _outgoing.size())
		_outgoing.insert(_outgoing.begin(), HandleCast(knil));
}

static inline double get_double(const ValuePtr& pap)
{
	return NumberNodeCast(pap)->get_value();
}

ValuePtr MinusLink::kons(const ValuePtr& fi, const ValuePtr& fj) const
{
	// Try to yank out values, if possible.
	ValuePtr vi(get_value(fi));
	Type vitype = vi->get_type();

	ValuePtr vj(get_value(fj));
	Type vjtype = vj->get_type();

	// Are they numbers?
	if (NUMBER_NODE == vitype and NUMBER_NODE == vjtype)
	{
		double diff = get_double(vi) - get_double(vj);
		return createNumberNode(diff);
	}

	// If vj is zero, just drop it.
	if (NUMBER_NODE == vjtype and content_eq(HandleCast(vj), zero))
		return vi;

	// Collapse (3 - (5 + x)) and (3 - (x + 5))
	if (NUMBER_NODE == vitype and PLUS_LINK == vjtype)
	{
		Handle augend(HandleCast(vj)->getOutgoingAtom(0));
		Handle addend(HandleCast(vj)->getOutgoingAtom(1));
		if (NUMBER_NODE == augend->get_type())
		{
			double diff = get_double(vi) - get_double(augend);
			Handle hdiff(createNumberNode(diff));
			return createMinusLink(hdiff, addend);
		}
		if (NUMBER_NODE == addend->get_type())
		{
			double diff = get_double(vi) - get_double(addend);
			Handle hdiff(createNumberNode(diff));
			return createMinusLink(hdiff, augend);
		}
	}

	// Collapse ((x + 13) - 6) and ((13 + x) - 6)
	if (PLUS_LINK == vitype and NUMBER_NODE == vjtype)
	{
		Handle augend(HandleCast(vi)->getOutgoingAtom(0));
		Handle addend(HandleCast(vi)->getOutgoingAtom(1));
		if (NUMBER_NODE == augend->get_type())
		{
			double diff = get_double(augend) - get_double(vj);
			Handle hdiff(createNumberNode(diff));
			if (content_eq(hdiff, zero))
				return addend;
			return createPlusLink(addend, hdiff);
		}
		if (NUMBER_NODE == addend->get_type())
		{
			double diff = get_double(addend) - get_double(vj);
			Handle hdiff(createNumberNode(diff));
			if (content_eq(hdiff, zero))
				return augend;
			return createPlusLink(augend, hdiff);
		}
	}

	// ------------------------------------------------------------------
	// Values
	// Scalar minus vector
	if (NUMBER_NODE == vitype and nameserver().isA(vjtype, FLOAT_VALUE))
	{
		FloatValuePtr mj = FloatValueCast(times(-1.0, FloatValueCast(vj)));
		return plus(get_double(vi), mj);
	}

	// Vector minus scalar
	if (nameserver().isA(vitype, FLOAT_VALUE) and NUMBER_NODE == vjtype)
	{
		return plus(-get_double(vj), FloatValueCast(vi));
	}

	// Vector times vector
	if (nameserver().isA(vitype, FLOAT_VALUE) and nameserver().isA(vjtype, FLOAT_VALUE))
	{
		FloatValuePtr mj = FloatValueCast(times(-1.0, FloatValueCast(vj)));
		return plus(FloatValueCast(vi), mj);
	}

	Handle hi(HandleCast(vi));
	if (nullptr == hi) hi= HandleCast(fi);

	Handle hj(HandleCast(vj));
	if (nullptr == hj) hj= HandleCast(fj);

	// If we are here, we've been asked to subtract two things,
	// but they are not of a type that we know how to subtract.
	return createMinusLink(hi, hj);
}

DEFINE_LINK_FACTORY(MinusLink, MINUS_LINK)

// ============================================================
<|endoftext|>


<commit_before>#include <vector>
#include <sys/mman.h>

#include "it.x64.asm.h"

static const struct rejit_threadset_t *NFA    = NULL;  // used for offset calculation
static const struct rejit_thread_t    *THREAD = NULL;

struct re2jit::native
{
    void *_code;
    void *_entry;
    size_t _size;

    native(re2::Prog *prog) : _code(NULL), _entry(NULL), _size(0)
    {
        size_t i;
        size_t n = prog->size();

        as code;
        std::vector<as::label> labels(n);

        as::label fail;  // return 0, meaning did not enter an accepting state
        as::label succeed;  // return 1, meaning there was a match somewhere
        code.mark(fail).xor_(as::eax, as::eax).mark(succeed).ret();

        // How many transitions have the i-th opcode as a target.
        // Opcodes with indegree 1 don't need to be tracked in the bit vector
        // (as there is only one way to reach them and we've already checked that).
        // Opcodes with indegree 0 are completely unreachable, no need to compile those.
        std::vector< unsigned > indegree(n);

        ssize_t *stack = new ssize_t[prog->size()];
        ssize_t *stptr = stack;
        indegree[*stptr++ = prog->start()]++;

        while (stptr != stack) {
            auto op  = prog->inst(*--stptr);
            auto vec = re2jit::is_extcode(prog, op);

            for (auto& op : vec)
                if (!indegree[op.out()]++)
                    *stptr++ = op.out();

            if (!vec.size())
                switch (op->opcode()) {
                    case re2::kInstAlt:
                    case re2::kInstAltMatch:
                        if (!indegree[op->out1()]++)
                            *stptr++ = op->out1();

                    default:
                        if (!indegree[op->out()]++)
                            *stptr++ = op->out();

                    case re2::kInstFail:
                    case re2::kInstMatch:
                        break;

                    case re2::kInstByteRange:
                        if (!indegree[op->out()])
                            *stptr++ = op->out();
                        // subsequent byte ranges are concatenated into one block of code
                        if (prog->inst(op->out())->opcode() != re2::kInstByteRange)
                            indegree[op->out()]++;
                }
        }

        delete[] stack;

        for (i = 0; i < n; i++) if (indegree[i]) {
            code.mark(labels[i]);
            // Each opcode should conform to the System V ABI calling convention.
            //   argument 1: %rdi = struct rejit_threadset_t *nfa
            //   return reg: %rax = 1 iff found a match somewhere
            auto op  = prog->inst(i);
            auto vec = re2jit::is_extcode(prog, op);

            // kInstFail will do `ret` anyway.
            if (op->opcode() != re2::kInstFail && indegree[i] > 1)
                code// if (bit(nfa->visited, i) == 1) return; bit(nfa->visited, i) = 1;
                    .mov  (as::mem{as::rdi} + &NFA->visited, as::rsi)
                    .test ((as::i8) (1 << (i % 8)), as::mem{as::rsi} + i / 8).jmp(fail, as::not_zero)
                    .or_  ((as::i8) (1 << (i % 8)), as::mem{as::rsi} + i / 8);

            if (vec.size()) {
                for (auto &op : vec) {
                    as::label fail;

                    switch (op.opcode()) {
                        case re2jit::inst::kUnicodeType:
                            code// utf8_chr = rejit_read_utf8(nfa->input, nfa->length);
                                .push (as::rdi)
                                .mov  (as::mem{as::rdi} + &NFA->length, as::rsi)
                                .mov  (as::mem{as::rdi} + &NFA->input,  as::rdi)
                                .call (&rejit_read_utf8)
                                .pop  (as::rdi)
                                // if ((utf8_length = utf8_chr >> 32) == 0) return;
                                .mov  (as::rax, as::rdx)
                                .shr  (32u,     as::rdx) .jmp(fail, as::zero)
                                // if ((UNICODE_CODEPOINT_TYPE[utf8_chr] & UNICODE_GENERAL) != arg) return;
                                .mov  ((uint64_t) UNICODE_CODEPOINT_TYPE, as::rsi)
                                .mov  (as::eax, as::eax)  // zero upper 32 bits
                                .add  (as::rsi, as::rax)
                                .mov  (as::mem{as::rax}, as::cl)
                                .and_ ((as::i8) UNICODE_GENERAL, as::cl)
                                .cmp  ((as::i8) op.arg(), as::cl).jmp(fail, as::not_equal)
                                // return rejit_thread_wait(nfa, &out, utf8_length);
                                .mov  (labels[op.out()], as::rsi)
                                .push (as::rdi)
                                .call (&rejit_thread_wait)
                                .pop  (as::rdi);

                            break;
                    }

                    code.mark(fail);
                }

                code.jmp(fail);
            } else switch (op->opcode()) {
                case re2::kInstAltMatch:
                case re2::kInstAlt:
                    code// if (out(nfa)) return 1;
                        .push  (as::rdi)
                        .call  (labels[op->out()])
                        .pop   (as::rdi)
                        .test  (as::eax, as::eax).jmp(succeed, as::not_zero);

                    if ((size_t) op->out1() != i + 1)
                        // else goto out1;
                        code.jmp(labels[op->out1()]);

                    break;

                case re2::kInstByteRange: {
                    std::vector<re2::Prog::Inst *> seq{ op };

                    while ((op = prog->inst(op->out()))->opcode() == re2::kInstByteRange)
                        seq.push_back(op);

                    // if (nfa->length < len) return; else rsi = nfa->input;
                    code.cmp((as::i32) seq.size(), as::mem{as::rdi} + &NFA->length).jmp(fail, as::less_u)
                        .mov(as::mem{as::rdi} + &NFA->input, as::rsi);

                    for (auto op : seq) {
                        code.mov(as::mem{as::rsi}, as::al)
                            .add(as::i8{1}, as::rsi);

                        if (op->foldcase())
                            // if ('A' <= al && al <= 'Z') al = al - 'A' + 'a';
                            code.lea(as::mem{as::rax} - 'A', as::ecx)
                                .lea(as::mem{as::rcx} + 'a', as::edx)
                                .cmp('Z' - 'A', as::cl)
                                .mov(as::edx, as::eax, as::less_equal_u);

                        if (op->hi() == op->lo())
                            // if (al != lo) return;
                            code.cmp(op->lo(), as::al).jmp(fail, as::not_equal);
                        else
                            // if (al < lo || hi < al) return;
                            code.sub(op->lo(),            as::al)
                                .cmp(op->hi() - op->lo(), as::al).jmp(fail, as::more_u);
                    }

                    // return rejit_thread_wait(nfa, &out, len);
                    code.mov(labels[seq.back()->out()], as::rsi)
                        .mov(seq.size(), as::edx)
                        .jmp(&rejit_thread_wait);

                    break;
                }

                case re2::kInstCapture:
                    code// if (nfa->groups <= cap) goto out;
                        .cmp  ((as::i32) op->cap(), as::mem{as::rdi} + &NFA->groups)
                        .jmp  (labels[op->out()], as::less_equal_u)
                        // esi = nfa->running->groups[cap]; nfa->running->groups[cap] = nfa->offset;
                        .mov  (as::mem{as::rdi} + &NFA->running, as::rcx)
                        .mov  (as::mem{as::rdi} + &NFA->offset,  as::rax)
                        .mov  (as::mem{as::rcx} + &THREAD->groups[op->cap()], as::esi)
                        .mov  (as::eax, as::mem{as::rcx} + &THREAD->groups[op->cap()])
                        // eax = out(nfa);
                        .push (as::rdi)
                        .push (as::rsi)
                        .call (labels[op->out()])
                        .pop  (as::rsi)
                        .pop  (as::rdi)
                        // nfa->running->groups[cap] = esi; return eax;
                        .mov  (as::mem{as::rdi} + &NFA->running, as::rcx)
                        .mov  (as::esi, as::mem{as::rcx} + &THREAD->groups[op->cap()])
                        .ret  ();

                    break;

                case re2::kInstEmptyWidth:
                    code// if (~nfa->empty & empty) return;
                        .mov  (as::mem{as::rdi} + &NFA->empty, as::eax)
                        .not_ (as::eax)
                        .test ((as::i32) op->empty(), as::eax).jmp(fail, as::not_zero);

                    if ((size_t) op->out() != i + 1)
                        // else goto out;
                        code.jmp(labels[op->out()]);

                    break;

                case re2::kInstNop:
                    if ((size_t) op->out() != i + 1)
                        // goto out;
                        code.jmp(labels[op->out()]);

                    break;

                case re2::kInstMatch:
                    // return rejit_thread_match(nfa);
                    code.jmp(&rejit_thread_match);
                    break;

                case re2::kInstFail:
                    code.ret();
                    break;
            }
        }

        uint8_t *target = (uint8_t *) mmap(0, code.size(),
                                           PROT_READ | PROT_WRITE,
                                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

        if (target == (uint8_t *) -1)
            return;

        code.write(target);

        if (mprotect(target, code.size(), PROT_READ | PROT_EXEC) == -1) {
            munmap(target, code.size());
            return;
        }

        _code  = target;
        _entry = target + labels[prog->start()]->offset;
        _size  = code.size();
    }

   ~native()
    {
        munmap(_code, _size);
    }

    rejit_entry_t entry() const
    {
        return (rejit_entry_t) _entry;
    }

    void run(struct rejit_threadset_t *nfa) const
    {
        rejit_thread_dispatch(nfa);
    }
};
<commit_msg>x64: slightly improve (?) formatting of code.<commit_after>#include <vector>
#include <sys/mman.h>

#include "it.x64.asm.h"

static const struct rejit_threadset_t *NFA    = NULL;  // used for offset calculation
static const struct rejit_thread_t    *THREAD = NULL;

struct re2jit::native
{
    void *_code;
    void *_entry;
    size_t _size;

    native(re2::Prog *prog) : _code(NULL), _entry(NULL), _size(0)
    {
        size_t i;
        size_t n = prog->size();

        as code;
        std::vector<as::label> labels(n);

        as::label fail;  // return 0, meaning did not enter an accepting state
        as::label succeed;  // return 1, meaning there was a match somewhere
        code.mark(fail).xor_(as::eax, as::eax).mark(succeed).ret();

        // How many transitions have the i-th opcode as a target.
        // Opcodes with indegree 1 don't need to be tracked in the bit vector
        // (as there is only one way to reach them and we've already checked that).
        // Opcodes with indegree 0 are completely unreachable, no need to compile those.
        std::vector< unsigned > indegree(n);

        ssize_t *stack = new ssize_t[prog->size()];
        ssize_t *stptr = stack;
        indegree[*stptr++ = prog->start()]++;

        while (stptr != stack) {
            auto op  = prog->inst(*--stptr);
            auto vec = re2jit::is_extcode(prog, op);

            for (auto& op : vec)
                if (!indegree[op.out()]++)
                    *stptr++ = op.out();

            if (!vec.size())
                switch (op->opcode()) {
                    case re2::kInstAlt:
                    case re2::kInstAltMatch:
                        if (!indegree[op->out1()]++)
                            *stptr++ = op->out1();

                    default:
                        if (!indegree[op->out()]++)
                            *stptr++ = op->out();

                    case re2::kInstFail:
                    case re2::kInstMatch:
                        break;

                    case re2::kInstByteRange:
                        if (!indegree[op->out()])
                            *stptr++ = op->out();
                        // subsequent byte ranges are concatenated into one block of code
                        if (prog->inst(op->out())->opcode() != re2::kInstByteRange)
                            indegree[op->out()]++;
                }
        }

        delete[] stack;

        for (i = 0; i < n; i++) if (indegree[i]) {
            code.mark(labels[i]);
            // Each opcode should conform to the System V ABI calling convention.
            //   argument 1: %rdi = struct rejit_threadset_t *nfa
            //   return reg: %rax = 1 iff found a match somewhere
            auto op  = prog->inst(i);
            auto vec = re2jit::is_extcode(prog, op);

            // kInstFail will do `ret` anyway.
            if (op->opcode() != re2::kInstFail && indegree[i] > 1)
                // if (bit(nfa->visited, i) == 1) return; bit(nfa->visited, i) = 1;
                code.mov  (as::mem(as::rdi) + &NFA->visited, as::rsi)
                    .test (as::i8(1 << (i % 8)), as::mem(as::rsi) + i / 8).jmp(fail, as::not_zero)
                    .or_  (as::i8(1 << (i % 8)), as::mem(as::rsi) + i / 8);

            if (vec.size()) {
                for (auto &op : vec) {
                    as::label fail;

                    switch (op.opcode()) {
                        case re2jit::inst::kUnicodeType:
                            // utf8_chr = rejit_read_utf8(nfa->input, nfa->length);
                            code.push (as::rdi)
                                .mov  (as::mem(as::rdi) + &NFA->length, as::rsi)
                                .mov  (as::mem(as::rdi) + &NFA->input,  as::rdi)
                                .call (&rejit_read_utf8)
                                .pop  (as::rdi)
                            // if ((utf8_length = utf8_chr >> 32) == 0) return;
                                .mov  (as::rax, as::rdx)
                                .shr  (32,      as::rdx).jmp(fail, as::zero)
                            // if ((UNICODE_CODEPOINT_TYPE[utf8_chr] & UNICODE_GENERAL) != arg) return;
                                .mov  (as::i64(UNICODE_CODEPOINT_TYPE), as::rsi)
                                .mov  (as::eax, as::eax)  // zero upper 32 bits
                                .add  (as::rsi, as::rax)  // TODO mov (%rsi, %rax, 1), %cl
                                .mov  (as::mem(as::rax), as::cl)
                                .and_ (UNICODE_GENERAL,  as::cl)
                                .cmp  (op.arg(),         as::cl).jmp(fail, as::not_equal)
                            // rejit_thread_wait(nfa, &out, utf8_length);
                                .mov  (labels[op.out()], as::rsi)
                                .push (as::rdi)
                                .call (&rejit_thread_wait)
                                .pop  (as::rdi);

                            break;
                    }

                    code.mark(fail);
                }

                code.jmp(fail);
            } else switch (op->opcode()) {
                case re2::kInstAltMatch:
                case re2::kInstAlt:
                    // if (out(nfa)) return 1;
                    code.push  (as::rdi)
                        .call  (labels[op->out()])
                        .pop   (as::rdi)
                        .test  (as::eax, as::eax).jmp(succeed, as::not_zero);

                    if ((size_t) op->out1() != i + 1)
                        code.jmp(labels[op->out1()]);

                    break;

                case re2::kInstByteRange: {
                    std::vector<re2::Prog::Inst *> seq{ op };

                    while ((op = prog->inst(op->out()))->opcode() == re2::kInstByteRange)
                        seq.push_back(op);

                    // if (nfa->length < len) return; else rsi = nfa->input;
                    code.cmp(as::i32(seq.size()), as::mem(as::rdi) + &NFA->length).jmp(fail, as::less_u)
                        .mov(as::mem(as::rdi) + &NFA->input, as::rsi);

                    for (auto op : seq) {
                        code.mov(as::mem(as::rsi), as::al)
                            .add(as::i8(1), as::rsi);

                        if (op->foldcase())
                            // if ('A' <= al && al <= 'Z') al = al - 'A' + 'a';
                            code.lea(as::mem(as::rax) - 'A', as::ecx)
                                .lea(as::mem(as::rcx) + 'a', as::edx)
                                .cmp('Z' - 'A', as::cl)
                                .mov(as::edx, as::eax, as::less_equal_u);

                        if (op->hi() == op->lo())
                            // if (al != lo) return;
                            code.cmp(op->lo(), as::al).jmp(fail, as::not_equal);
                        else
                            // if (al < lo || hi < al) return;
                            code.sub(op->lo(),            as::al)
                                .cmp(op->hi() - op->lo(), as::al).jmp(fail, as::more_u);
                    }

                    // return rejit_thread_wait(nfa, &out, len);
                    code.mov(labels[seq.back()->out()], as::rsi)
                        .mov(seq.size(), as::edx)
                        .jmp(&rejit_thread_wait);

                    break;
                }

                case re2::kInstCapture:
                    // if (nfa->groups <= cap) goto out;
                    code.cmp  (as::i32(op->cap()), as::mem(as::rdi) + &NFA->groups)
                        .jmp  (labels[op->out()], as::less_equal_u)
                        // esi = nfa->running->groups[cap]; nfa->running->groups[cap] = nfa->offset;
                        .mov  (as::mem(as::rdi) + &NFA->running, as::rcx)
                        .mov  (as::mem(as::rdi) + &NFA->offset,  as::eax)
                        .mov  (as::mem(as::rcx) + &THREAD->groups[op->cap()], as::esi)
                        .mov  (as::eax, as::mem(as::rcx) + &THREAD->groups[op->cap()])
                        // eax = out(nfa);
                        .push (as::rdi)
                        .push (as::rsi)
                        .push (as::rcx)
                        .call (labels[op->out()])
                        .pop  (as::rcx)
                        .pop  (as::rsi)
                        .pop  (as::rdi)
                        // nfa->running->groups[cap] = esi; return eax;
                        .mov  (as::esi, as::mem(as::rcx) + &THREAD->groups[op->cap()])
                        .ret  ();

                    break;

                case re2::kInstEmptyWidth:
                    // if (~nfa->empty & empty) return;
                    code.mov  (as::mem(as::rdi) + &NFA->empty, as::eax)
                        .not_ (as::eax)
                        .test (op->empty(), as::eax).jmp(fail, as::not_zero);

                    if ((size_t) op->out() != i + 1)
                        code.jmp(labels[op->out()]);

                    break;

                case re2::kInstNop:
                    if ((size_t) op->out() != i + 1)
                        code.jmp(labels[op->out()]);

                    break;

                case re2::kInstMatch:
                    // return rejit_thread_match(nfa);
                    code.jmp(&rejit_thread_match);
                    break;

                case re2::kInstFail:
                    code.ret();
                    break;
            }
        }

        uint8_t *target = (uint8_t *) mmap(0, code.size(),
                                           PROT_READ | PROT_WRITE,
                                           MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

        if (target == (uint8_t *) -1)
            return;

        code.write(target);

        if (mprotect(target, code.size(), PROT_READ | PROT_EXEC) == -1) {
            munmap(target, code.size());
            return;
        }

        _code  = target;
        _entry = target + labels[prog->start()]->offset;
        _size  = code.size();
    }

   ~native()
    {
        munmap(_code, _size);
    }

    rejit_entry_t entry() const
    {
        return (rejit_entry_t) _entry;
    }

    void run(struct rejit_threadset_t *nfa) const
    {
        rejit_thread_dispatch(nfa);
    }
};
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

#include "PosixTimespec.hpp"

struct TimespecTuple
{
    timespec lhs;
    timespec rhs;
    timespec result;
};

int main(int argc, char** argv)
{
    std::cout.precision(10);

    timespec tp;
    TimespecTuple tt;

    // Let's do some conclusive addition tests
    std::vector<TimespecTuple> addition_cases;
    std::vector<TimespecTuple> addition_cases_failed;

    // Let's do some conclusive subtraction tests
    std::vector<TimespecTuple> subtraction_cases;
    std::vector<TimespecTuple> subtraction_cases_failed;

    std::vector<timespec> timespecs;

    // SUBTRACTION CASE 1
    tp.tv_sec  = 0;
    tp.tv_nsec = 0;
    tt.lhs = tp;

    tp.tv_sec  = 0;
    tp.tv_nsec = 1;
    tt.rhs = tp;

    tp.tv_sec  -= 1;
    tp.tv_nsec = 999999999;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    // SUBTRACTION CASE 2
    tp.tv_sec = 2346;
    tp.tv_nsec = 999999999;
    tt.lhs = tp;

    tp.tv_sec = 1000;
    tp.tv_nsec = 40;
    tt.rhs = tp;

    tp.tv_sec = 1346;
    tp.tv_nsec = 999999959;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    // SUBTRACTION CASE 3
    tp.tv_sec = 5;
    tp.tv_nsec = 0;
    tt.lhs = tp;

    tp.tv_sec = 2;
    tp.tv_nsec = 500000000;
    tt.rhs = tp;

    tp.tv_sec = 2;
    tp.tv_nsec = 500000000;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    // SUBTRACTION CASE 4
    tp.tv_sec = 1;
    tp.tv_nsec = 250000000;
    tt.lhs = tp;

    tp.tv_sec = 0;
    tp.tv_nsec = 750000000;
    tt.rhs = tp;

    tp.tv_sec = 0;
    tp.tv_nsec = 500000000;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    for (unsigned int i = 0; i < subtraction_cases.size(); i++)
    {
        PosixTimespec result = PosixTimespec(subtraction_cases[i].lhs) -
            PosixTimespec(subtraction_cases[i].rhs);

        if (result != subtraction_cases[i].result)
        {
            subtraction_cases_failed.push_back(subtraction_cases[i]);
            timespec result_tp;
            result.getTimespec(result_tp);

            std::cout << subtraction_cases[i].lhs.tv_sec << "("
                      << subtraction_cases[i].lhs.tv_nsec << ") - "
                      << subtraction_cases[i].rhs.tv_sec << "("
                      << subtraction_cases[i].rhs.tv_nsec << ") = "
                      << result_tp.tv_sec << "("
                      << result_tp.tv_nsec << "), should be "
                      << subtraction_cases[i].result.tv_sec << "("
                      << subtraction_cases[i].result.tv_nsec << ")\n";
        }
    }

    std::cout << "Failed subtraction cases: " << subtraction_cases_failed.size()
              << "\n";

    // OTHER CASES
    // These are all tested against each other

    tp.tv_sec = 0;
    tp.tv_nsec = 0;
    timespecs.push_back(tp);

    tp.tv_sec = 0;
    tp.tv_nsec = 1;
    timespecs.push_back(tp);

    tp.tv_sec = 857693847;
    tp.tv_nsec = 736486;
    timespecs.push_back(tp);

    tp.tv_sec = 85769;
    tp.tv_nsec = 566486;
    timespecs.push_back(tp);

    tp.tv_sec = 8576946;
    tp.tv_nsec = 566486999;
    timespecs.push_back(tp);

    tp.tv_sec = 6;
    tp.tv_nsec = 999999999;
    timespecs.push_back(tp);

    std::vector<std::pair<unsigned int, unsigned int> > failed_cases;

    for (unsigned int i = 0; i < timespecs.size(); i++)
    {
        PosixTimespec ts1(timespecs[i]);

        for (unsigned int j = 0; j < timespecs.size(); j++)
        {
            PosixTimespec ts2(timespecs[j]);

            // Test addition
            PosixTimespec ts_sum1 = ts1 + ts2;
            PosixTimespec ts_sum2 = ts2 + ts1;

            timespec ts_sum1_tp;
            ts_sum1.getTimespec(ts_sum1_tp);

//            std::cout << timespecs[i].tv_sec << "("
//                      << timespecs[i].tv_nsec << ") + "
//                      << timespecs[j].tv_sec << "("
//                      << timespecs[j].tv_nsec << ") = "
//                      << ts_sum1_tp.tv_sec << "("
//                      << ts_sum1_tp.tv_nsec << ")\n";

            if (!(ts_sum1 == ts_sum2 && ts_sum2 == ts_sum1))
            {
                failed_cases.push_back(
                    std::pair<unsigned int, unsigned int>(i, j));

                continue;
            }

            // Test equality and inequality
            if (i == j)
            {
                if (!(ts1 == ts2 && ts2 == ts1 &&
                      timespecs[i] == ts2 && ts2 == timespecs[i] &&
                      ts1 == timespecs[j] && timespecs[j] == ts1))
                {
                    failed_cases.push_back(
                        std::pair<unsigned int, unsigned int>(i, j));
                }
            }
            else
            {
                if (!(ts1 != ts2 && ts2 != ts1 &&
                      timespecs[i] != ts2 && ts2 != timespecs[i] &&
                      ts1 != timespecs[j] && timespecs[j] != ts1))
                {
                    failed_cases.push_back(
                        std::pair<unsigned int, unsigned int>(i, j));
                }
            }
        }
    }

    std::cout << "Other failed cases: " << failed_cases.size() << "\n";

    // This unit test passes if no failed cases were recorded; remember that a
    // zero return value means success
    return !(failed_cases.size() == 0 && subtraction_cases_failed.size() == 0);
}
<commit_msg>Addition looks like its working<commit_after>#include <iostream>
#include <vector>

#include "PosixTimespec.hpp"

struct TimespecTuple
{
    timespec lhs;
    timespec rhs;
    timespec result;
};

int main(int argc, char** argv)
{
    std::cout.precision(10);

    timespec tp;
    TimespecTuple tt;

    // Let's do some conclusive addition tests
    std::vector<TimespecTuple> addition_cases;
    std::vector<TimespecTuple> addition_cases_failed;

    // ADDITION CASE 1
    tp.tv_sec  = 0;
    tp.tv_nsec = 0;
    tt.lhs = tp;

    tp.tv_sec  = 0;
    tp.tv_nsec = 1;
    tt.rhs = tp;

    tt.result = tp;

    addition_cases.push_back(tt);

    // ADDITION CASE 2
    tp.tv_sec = 2346;
    tp.tv_nsec = 999999999;
    tt.lhs = tp;

    tp.tv_sec = 1000;
    tp.tv_nsec = 40;
    tt.rhs = tp;

    tp.tv_sec = 3347;
    tp.tv_nsec = 39;
    tt.result = tp;

    addition_cases.push_back(tt);

    // ADDITION CASE 3
    tp.tv_sec = 5;
    tp.tv_nsec = 0;
    tt.lhs = tp;

    tp.tv_sec = 2;
    tp.tv_nsec = 500000000;
    tt.rhs = tp;

    tp.tv_sec = 7;
    tp.tv_nsec = 500000000;
    tt.result = tp;

    addition_cases.push_back(tt);

    // ADDITION CASE 4
    tp.tv_sec = 1;
    tp.tv_nsec = 250000000;
    tt.lhs = tp;

    tp.tv_sec = 0;
    tp.tv_nsec = 750000000;
    tt.rhs = tp;

    tp.tv_sec = 2;
    tp.tv_nsec = 0;
    tt.result = tp;

    addition_cases.push_back(tt);

    for (unsigned int i = 0; i < addition_cases.size(); i++)
    {
        PosixTimespec result = PosixTimespec(addition_cases[i].lhs) +
            PosixTimespec(addition_cases[i].rhs);

        if (result != addition_cases[i].result)
        {
            addition_cases_failed.push_back(addition_cases[i]);
            timespec result_tp;
            result.getTimespec(result_tp);

            std::cout << addition_cases[i].lhs.tv_sec << "("
                      << addition_cases[i].lhs.tv_nsec << ") - "
                      << addition_cases[i].rhs.tv_sec << "("
                      << addition_cases[i].rhs.tv_nsec << ") = "
                      << result_tp.tv_sec << "("
                      << result_tp.tv_nsec << "), should be "
                      << addition_cases[i].result.tv_sec << "("
                      << addition_cases[i].result.tv_nsec << ")\n";
        }
    }

    std::cout << "Failed addition cases: " << addition_cases_failed.size()
              << "\n";

    // Let's do some conclusive subtraction tests
    std::vector<TimespecTuple> subtraction_cases;
    std::vector<TimespecTuple> subtraction_cases_failed;

    std::vector<timespec> timespecs;

    // SUBTRACTION CASE 1
    tp.tv_sec  = 0;
    tp.tv_nsec = 0;
    tt.lhs = tp;

    tp.tv_sec  = 0;
    tp.tv_nsec = 1;
    tt.rhs = tp;

    tp.tv_sec  -= 1;
    tp.tv_nsec = 999999999;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    // SUBTRACTION CASE 2
    tp.tv_sec = 2346;
    tp.tv_nsec = 999999999;
    tt.lhs = tp;

    tp.tv_sec = 1000;
    tp.tv_nsec = 40;
    tt.rhs = tp;

    tp.tv_sec = 1346;
    tp.tv_nsec = 999999959;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    // SUBTRACTION CASE 3
    tp.tv_sec = 5;
    tp.tv_nsec = 0;
    tt.lhs = tp;

    tp.tv_sec = 2;
    tp.tv_nsec = 500000000;
    tt.rhs = tp;

    tp.tv_sec = 2;
    tp.tv_nsec = 500000000;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    // SUBTRACTION CASE 4
    tp.tv_sec = 1;
    tp.tv_nsec = 250000000;
    tt.lhs = tp;

    tp.tv_sec = 0;
    tp.tv_nsec = 750000000;
    tt.rhs = tp;

    tp.tv_sec = 0;
    tp.tv_nsec = 500000000;
    tt.result = tp;

    subtraction_cases.push_back(tt);

    for (unsigned int i = 0; i < subtraction_cases.size(); i++)
    {
        PosixTimespec result = PosixTimespec(subtraction_cases[i].lhs) -
            PosixTimespec(subtraction_cases[i].rhs);

        if (result != subtraction_cases[i].result)
        {
            subtraction_cases_failed.push_back(subtraction_cases[i]);
            timespec result_tp;
            result.getTimespec(result_tp);

            std::cout << subtraction_cases[i].lhs.tv_sec << "("
                      << subtraction_cases[i].lhs.tv_nsec << ") - "
                      << subtraction_cases[i].rhs.tv_sec << "("
                      << subtraction_cases[i].rhs.tv_nsec << ") = "
                      << result_tp.tv_sec << "("
                      << result_tp.tv_nsec << "), should be "
                      << subtraction_cases[i].result.tv_sec << "("
                      << subtraction_cases[i].result.tv_nsec << ")\n";
        }
    }

    std::cout << "Failed subtraction cases: " << subtraction_cases_failed.size()
              << "\n";

    // OTHER CASES
    // These are all tested against each other

    tp.tv_sec = 0;
    tp.tv_nsec = 0;
    timespecs.push_back(tp);

    tp.tv_sec = 0;
    tp.tv_nsec = 1;
    timespecs.push_back(tp);

    tp.tv_sec = 857693847;
    tp.tv_nsec = 736486;
    timespecs.push_back(tp);

    tp.tv_sec = 85769;
    tp.tv_nsec = 566486;
    timespecs.push_back(tp);

    tp.tv_sec = 8576946;
    tp.tv_nsec = 566486999;
    timespecs.push_back(tp);

    tp.tv_sec = 6;
    tp.tv_nsec = 999999999;
    timespecs.push_back(tp);

    std::vector<std::pair<unsigned int, unsigned int> > failed_cases;

    for (unsigned int i = 0; i < timespecs.size(); i++)
    {
        PosixTimespec ts1(timespecs[i]);

        for (unsigned int j = 0; j < timespecs.size(); j++)
        {
            PosixTimespec ts2(timespecs[j]);

            // Test addition
            PosixTimespec ts_sum1 = ts1 + ts2;
            PosixTimespec ts_sum2 = ts2 + ts1;

            timespec ts_sum1_tp;
            ts_sum1.getTimespec(ts_sum1_tp);

//            std::cout << timespecs[i].tv_sec << "("
//                      << timespecs[i].tv_nsec << ") + "
//                      << timespecs[j].tv_sec << "("
//                      << timespecs[j].tv_nsec << ") = "
//                      << ts_sum1_tp.tv_sec << "("
//                      << ts_sum1_tp.tv_nsec << ")\n";

            if (!(ts_sum1 == ts_sum2 && ts_sum2 == ts_sum1))
            {
                failed_cases.push_back(
                    std::pair<unsigned int, unsigned int>(i, j));

                continue;
            }

            // Test equality and inequality
            if (i == j)
            {
                if (!(ts1 == ts2 && ts2 == ts1 &&
                      timespecs[i] == ts2 && ts2 == timespecs[i] &&
                      ts1 == timespecs[j] && timespecs[j] == ts1))
                {
                    failed_cases.push_back(
                        std::pair<unsigned int, unsigned int>(i, j));
                }
            }
            else
            {
                if (!(ts1 != ts2 && ts2 != ts1 &&
                      timespecs[i] != ts2 && ts2 != timespecs[i] &&
                      ts1 != timespecs[j] && timespecs[j] != ts1))
                {
                    failed_cases.push_back(
                        std::pair<unsigned int, unsigned int>(i, j));
                }
            }
        }
    }

    std::cout << "Other failed cases: " << failed_cases.size() << "\n";

    // This unit test passes if no failed cases were recorded; remember that a
    // zero return value means success
    return !(failed_cases.size() == 0 && subtraction_cases_failed.size() == 0);
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: document.hxx,v $
 * $Revision: 1.11 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _DOCUMENT_HXX
#define _DOCUMENT_HXX

#include <list>
#include <set>
#include <sal/types.h>
#include <cppuhelper/implbase5.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/beans/StringPair.hpp>
#include <com/sun/star/xml/dom/XNode.hpp>
#include <com/sun/star/xml/dom/XAttr.hpp>
#include <com/sun/star/xml/dom/XElement.hpp>
#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp>
#include <com/sun/star/xml/dom/events/XEvent.hpp>
#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XActiveDataControl.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/io/XStreamListener.hpp>

#include "node.hxx"

#include <libxml/tree.h>

using namespace std;
using namespace rtl;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::xml::sax;
using namespace com::sun::star::io;
using namespace com::sun::star::xml::dom;
using namespace com::sun::star::xml::dom::events;

namespace DOM
{

    class CDocument : public cppu::ImplInheritanceHelper5<
        CNode, XDocument, XDocumentEvent,
        XActiveDataControl, XActiveDataSource, XSAXSerializable>
    {
        friend class CNode;
        typedef std::list< Reference< XNode >* > nodereflist_t;
        typedef set< Reference< XStreamListener > > listenerlist_t;
    private:

        nodereflist_t m_aNodeRefList;

        xmlDocPtr m_aDocPtr;

        // datacontrol/source state
        listenerlist_t m_streamListeners;
        Reference< XOutputStream > m_rOutputStream;

    protected:
        CDocument(xmlDocPtr aDocPtr);

        void addnode(xmlNodePtr aNode);

    public:

        virtual ~CDocument();

        virtual void SAL_CALL saxify(
            const Reference< XDocumentHandler >& i_xHandler);

        /**
        Creates an Attr of the given name.
        */
        virtual Reference< XAttr > SAL_CALL createAttribute(const OUString& name)
            throw (RuntimeException, DOMException);

        /**
        Creates an attribute of the given qualified name and namespace URI.
        */
        virtual Reference< XAttr > SAL_CALL createAttributeNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (RuntimeException, DOMException);

        /**
        Creates a CDATASection node whose value is the specified string.
        */
        virtual Reference< XCDATASection > SAL_CALL createCDATASection(const OUString& data)
            throw (RuntimeException);

        /**
        Creates a Comment node given the specified string.
        */
        virtual Reference< XComment > SAL_CALL createComment(const OUString& data)
            throw (RuntimeException);

        /**
        Creates an empty DocumentFragment object.
        */
        virtual Reference< XDocumentFragment > SAL_CALL createDocumentFragment()
            throw (RuntimeException);

        /**
        Creates an element of the type specified.
        */
        virtual Reference< XElement > SAL_CALL createElement(const OUString& tagName)
            throw (RuntimeException, DOMException);

        /**
        Creates an element of the given qualified name and namespace URI.
        */
        virtual Reference< XElement > SAL_CALL createElementNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (RuntimeException, DOMException);

        /**
        Creates an EntityReference object.
        */
        virtual Reference< XEntityReference > SAL_CALL createEntityReference(const OUString& name)
            throw (RuntimeException, DOMException);

        /**
        Creates a ProcessingInstruction node given the specified name and
        data strings.
        */
        virtual Reference< XProcessingInstruction > SAL_CALL createProcessingInstruction(
                const OUString& target, const OUString& data)
            throw (RuntimeException, DOMException);

        /**
        Creates a Text node given the specified string.
        */
        virtual Reference< XText > SAL_CALL createTextNode(const OUString& data)
            throw (RuntimeException);

        /**
        The Document Type Declaration (see DocumentType) associated with this
        document.
        */
        virtual Reference< XDocumentType > SAL_CALL getDoctype()
            throw (RuntimeException);

        /**
        This is a convenience attribute that allows direct access to the child
        node that is the root element of the document.
        */
        virtual Reference< XElement > SAL_CALL getDocumentElement()
            throw (RuntimeException);

        /**
        Returns the Element whose ID is given by elementId.
        */
        virtual Reference< XElement > SAL_CALL getElementById(const OUString& elementId)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given tag name in the
        order in which they are encountered in a preorder traversal of the
        Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagName(const OUString& tagname)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given local name and
        namespace URI in the order in which they are encountered in a preorder
        traversal of the Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagNameNS(const OUString& namespaceURI, const OUString& localName)
            throw (RuntimeException);

        /**
        The DOMImplementation object that handles this document.
        */
        virtual Reference< XDOMImplementation > SAL_CALL getImplementation()
            throw (RuntimeException);

        /**
        Imports a node from another document to this document.
        */
        virtual Reference< XNode > SAL_CALL importNode(const Reference< XNode >& importedNode, sal_Bool deep)
            throw (RuntimeException, DOMException);

        // XDocumentEvent
        virtual Reference< XEvent > SAL_CALL createEvent(const OUString& eventType) throw (RuntimeException);

        // XActiveDataControl,
        // see http://api.openoffice.org/docs/common/ref/com/sun/star/io/XActiveDataControl.html
        virtual void SAL_CALL addListener(const Reference< XStreamListener >& aListener )  throw (RuntimeException);
        virtual void SAL_CALL removeListener(const Reference< XStreamListener >& aListener ) throw (RuntimeException);
        virtual void SAL_CALL start() throw (RuntimeException);
        virtual void SAL_CALL terminate() throw (RuntimeException);

        // XActiveDataSource
        // see http://api.openoffice.org/docs/common/ref/com/sun/star/io/XActiveDataSource.html
        virtual void SAL_CALL setOutputStream(  const Reference< XOutputStream >& aStream ) throw (RuntimeException);
        virtual Reference< XOutputStream > SAL_CALL getOutputStream() throw (RuntimeException);

        // ---- resolve uno inheritance problems...
        // overrides for XNode base
        virtual OUString SAL_CALL getNodeName()
            throw (RuntimeException);
        virtual OUString SAL_CALL getNodeValue()
            throw (RuntimeException);
        // --- delegation for XNde base.
        virtual Reference< XNode > SAL_CALL appendChild(const Reference< XNode >& newChild)
            throw (RuntimeException, DOMException)
        {
            return CNode::appendChild(newChild);
        }
        virtual Reference< XNode > SAL_CALL cloneNode(sal_Bool deep)
            throw (RuntimeException)
        {
            return CNode::cloneNode(deep);
        }
        virtual Reference< XNamedNodeMap > SAL_CALL getAttributes()
            throw (RuntimeException)
        {
            return CNode::getAttributes();
        }
        virtual Reference< XNodeList > SAL_CALL getChildNodes()
            throw (RuntimeException)
        {
            return CNode::getChildNodes();
        }
        virtual Reference< XNode > SAL_CALL getFirstChild()
            throw (RuntimeException)
        {
            return CNode::getFirstChild();
        }
        virtual Reference< XNode > SAL_CALL getLastChild()
            throw (RuntimeException)
        {
            return CNode::getLastChild();
        }
        virtual OUString SAL_CALL getLocalName()
            throw (RuntimeException)
        {
            return CNode::getLocalName();
        }
        virtual OUString SAL_CALL getNamespaceURI()
            throw (RuntimeException)
        {
            return CNode::getNamespaceURI();
        }
        virtual Reference< XNode > SAL_CALL getNextSibling()
            throw (RuntimeException)
        {
            return CNode::getNextSibling();
        }
        virtual NodeType SAL_CALL getNodeType()
            throw (RuntimeException)
        {
            return CNode::getNodeType();
        }
        virtual Reference< XDocument > SAL_CALL getOwnerDocument()
            throw (RuntimeException)
        {
            return CNode::getOwnerDocument();
        }
        virtual Reference< XNode > SAL_CALL getParentNode()
            throw (RuntimeException)
        {
            return CNode::getParentNode();
        }
        virtual OUString SAL_CALL getPrefix()
            throw (RuntimeException)
        {
           return CNode::getPrefix();
        }
        virtual Reference< XNode > SAL_CALL getPreviousSibling()
            throw (RuntimeException)
        {
            return CNode::getPreviousSibling();
        }
        virtual sal_Bool SAL_CALL hasAttributes()
            throw (RuntimeException)
        {
            return CNode::hasAttributes();
        }
        virtual sal_Bool SAL_CALL hasChildNodes()
            throw (RuntimeException)
        {
            return CNode::hasChildNodes();
        }
        virtual Reference< XNode > SAL_CALL insertBefore(
                const Reference< XNode >& newChild, const Reference< XNode >& refChild)
            throw (DOMException)
        {
            return CNode::insertBefore(newChild, refChild);
        }
        virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver)
            throw (RuntimeException)
        {
            return CNode::isSupported(feature, ver);
        }
        virtual void SAL_CALL normalize()
            throw (RuntimeException)
        {
            CNode::normalize();
        }
        virtual Reference< XNode > SAL_CALL removeChild(const Reference< XNode >& oldChild)
            throw (RuntimeException, DOMException)
        {
            return CNode::removeChild(oldChild);
        }
        virtual Reference< XNode > SAL_CALL replaceChild(
                const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
            throw (RuntimeException, DOMException)
        {
            return CNode::replaceChild(newChild, oldChild);
        }
        virtual void SAL_CALL setNodeValue(const OUString& nodeValue)
            throw (RuntimeException, DOMException)
        {
            return CNode::setNodeValue(nodeValue);
        }
        virtual void SAL_CALL setPrefix(const OUString& prefix)
            throw (RuntimeException, DOMException)
        {
            return CNode::setPrefix(prefix);
        }

    // ::com::sun::star::xml::sax::XSAXSerializable
    virtual void SAL_CALL serialize(
            const Reference< XDocumentHandler >& i_xHandler,
            const Sequence< beans::StringPair >& i_rNamespaces)
        throw (RuntimeException, SAXException);
    };
}

#endif
<commit_msg>INTEGRATION: CWS xmlfix2 (1.10.2); FILE MERGED 2008/05/15 17:26:23 mst 1.10.2.2: RESYNC: (1.10-1.11); FILE MERGED 2008/03/31 14:19:29 mst 1.10.2.1: - unoxml/source/dom/{document.hxx,node.hxx,documentbuilder{.hxx,.cxx}}:   + fix mess resulting from "using namespace rtl"<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: document.hxx,v $
 * $Revision: 1.12 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#ifndef _DOCUMENT_HXX
#define _DOCUMENT_HXX

#include <list>
#include <set>
#include <sal/types.h>
#include <cppuhelper/implbase5.hxx>
#include <com/sun/star/uno/Reference.h>
#include <com/sun/star/uno/Exception.hpp>
#include <com/sun/star/beans/StringPair.hpp>
#include <com/sun/star/xml/dom/XNode.hpp>
#include <com/sun/star/xml/dom/XAttr.hpp>
#include <com/sun/star/xml/dom/XElement.hpp>
#include <com/sun/star/xml/dom/XDOMImplementation.hpp>
#include <com/sun/star/xml/dom/events/XDocumentEvent.hpp>
#include <com/sun/star/xml/dom/events/XEvent.hpp>
#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XActiveDataControl.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/io/XStreamListener.hpp>

#include "node.hxx"

#include <libxml/tree.h>

using namespace std;
using ::rtl::OUString;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::xml::sax;
using namespace com::sun::star::io;
using namespace com::sun::star::xml::dom;
using namespace com::sun::star::xml::dom::events;

namespace DOM
{

    class CDocument : public cppu::ImplInheritanceHelper5<
        CNode, XDocument, XDocumentEvent,
        XActiveDataControl, XActiveDataSource, XSAXSerializable>
    {
        friend class CNode;
        typedef std::list< Reference< XNode >* > nodereflist_t;
        typedef set< Reference< XStreamListener > > listenerlist_t;
    private:

        nodereflist_t m_aNodeRefList;

        xmlDocPtr m_aDocPtr;

        // datacontrol/source state
        listenerlist_t m_streamListeners;
        Reference< XOutputStream > m_rOutputStream;

    protected:
        CDocument(xmlDocPtr aDocPtr);

        void addnode(xmlNodePtr aNode);

    public:

        virtual ~CDocument();

        virtual void SAL_CALL saxify(
            const Reference< XDocumentHandler >& i_xHandler);

        /**
        Creates an Attr of the given name.
        */
        virtual Reference< XAttr > SAL_CALL createAttribute(const OUString& name)
            throw (RuntimeException, DOMException);

        /**
        Creates an attribute of the given qualified name and namespace URI.
        */
        virtual Reference< XAttr > SAL_CALL createAttributeNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (RuntimeException, DOMException);

        /**
        Creates a CDATASection node whose value is the specified string.
        */
        virtual Reference< XCDATASection > SAL_CALL createCDATASection(const OUString& data)
            throw (RuntimeException);

        /**
        Creates a Comment node given the specified string.
        */
        virtual Reference< XComment > SAL_CALL createComment(const OUString& data)
            throw (RuntimeException);

        /**
        Creates an empty DocumentFragment object.
        */
        virtual Reference< XDocumentFragment > SAL_CALL createDocumentFragment()
            throw (RuntimeException);

        /**
        Creates an element of the type specified.
        */
        virtual Reference< XElement > SAL_CALL createElement(const OUString& tagName)
            throw (RuntimeException, DOMException);

        /**
        Creates an element of the given qualified name and namespace URI.
        */
        virtual Reference< XElement > SAL_CALL createElementNS(const OUString& namespaceURI, const OUString& qualifiedName)
            throw (RuntimeException, DOMException);

        /**
        Creates an EntityReference object.
        */
        virtual Reference< XEntityReference > SAL_CALL createEntityReference(const OUString& name)
            throw (RuntimeException, DOMException);

        /**
        Creates a ProcessingInstruction node given the specified name and
        data strings.
        */
        virtual Reference< XProcessingInstruction > SAL_CALL createProcessingInstruction(
                const OUString& target, const OUString& data)
            throw (RuntimeException, DOMException);

        /**
        Creates a Text node given the specified string.
        */
        virtual Reference< XText > SAL_CALL createTextNode(const OUString& data)
            throw (RuntimeException);

        /**
        The Document Type Declaration (see DocumentType) associated with this
        document.
        */
        virtual Reference< XDocumentType > SAL_CALL getDoctype()
            throw (RuntimeException);

        /**
        This is a convenience attribute that allows direct access to the child
        node that is the root element of the document.
        */
        virtual Reference< XElement > SAL_CALL getDocumentElement()
            throw (RuntimeException);

        /**
        Returns the Element whose ID is given by elementId.
        */
        virtual Reference< XElement > SAL_CALL getElementById(const OUString& elementId)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given tag name in the
        order in which they are encountered in a preorder traversal of the
        Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagName(const OUString& tagname)
            throw (RuntimeException);

        /**
        Returns a NodeList of all the Elements with a given local name and
        namespace URI in the order in which they are encountered in a preorder
        traversal of the Document tree.
        */
        virtual Reference< XNodeList > SAL_CALL getElementsByTagNameNS(const OUString& namespaceURI, const OUString& localName)
            throw (RuntimeException);

        /**
        The DOMImplementation object that handles this document.
        */
        virtual Reference< XDOMImplementation > SAL_CALL getImplementation()
            throw (RuntimeException);

        /**
        Imports a node from another document to this document.
        */
        virtual Reference< XNode > SAL_CALL importNode(const Reference< XNode >& importedNode, sal_Bool deep)
            throw (RuntimeException, DOMException);

        // XDocumentEvent
        virtual Reference< XEvent > SAL_CALL createEvent(const OUString& eventType) throw (RuntimeException);

        // XActiveDataControl,
        // see http://api.openoffice.org/docs/common/ref/com/sun/star/io/XActiveDataControl.html
        virtual void SAL_CALL addListener(const Reference< XStreamListener >& aListener )  throw (RuntimeException);
        virtual void SAL_CALL removeListener(const Reference< XStreamListener >& aListener ) throw (RuntimeException);
        virtual void SAL_CALL start() throw (RuntimeException);
        virtual void SAL_CALL terminate() throw (RuntimeException);

        // XActiveDataSource
        // see http://api.openoffice.org/docs/common/ref/com/sun/star/io/XActiveDataSource.html
        virtual void SAL_CALL setOutputStream(  const Reference< XOutputStream >& aStream ) throw (RuntimeException);
        virtual Reference< XOutputStream > SAL_CALL getOutputStream() throw (RuntimeException);

        // ---- resolve uno inheritance problems...
        // overrides for XNode base
        virtual OUString SAL_CALL getNodeName()
            throw (RuntimeException);
        virtual OUString SAL_CALL getNodeValue()
            throw (RuntimeException);
        // --- delegation for XNde base.
        virtual Reference< XNode > SAL_CALL appendChild(const Reference< XNode >& newChild)
            throw (RuntimeException, DOMException)
        {
            return CNode::appendChild(newChild);
        }
        virtual Reference< XNode > SAL_CALL cloneNode(sal_Bool deep)
            throw (RuntimeException)
        {
            return CNode::cloneNode(deep);
        }
        virtual Reference< XNamedNodeMap > SAL_CALL getAttributes()
            throw (RuntimeException)
        {
            return CNode::getAttributes();
        }
        virtual Reference< XNodeList > SAL_CALL getChildNodes()
            throw (RuntimeException)
        {
            return CNode::getChildNodes();
        }
        virtual Reference< XNode > SAL_CALL getFirstChild()
            throw (RuntimeException)
        {
            return CNode::getFirstChild();
        }
        virtual Reference< XNode > SAL_CALL getLastChild()
            throw (RuntimeException)
        {
            return CNode::getLastChild();
        }
        virtual OUString SAL_CALL getLocalName()
            throw (RuntimeException)
        {
            return CNode::getLocalName();
        }
        virtual OUString SAL_CALL getNamespaceURI()
            throw (RuntimeException)
        {
            return CNode::getNamespaceURI();
        }
        virtual Reference< XNode > SAL_CALL getNextSibling()
            throw (RuntimeException)
        {
            return CNode::getNextSibling();
        }
        virtual NodeType SAL_CALL getNodeType()
            throw (RuntimeException)
        {
            return CNode::getNodeType();
        }
        virtual Reference< XDocument > SAL_CALL getOwnerDocument()
            throw (RuntimeException)
        {
            return CNode::getOwnerDocument();
        }
        virtual Reference< XNode > SAL_CALL getParentNode()
            throw (RuntimeException)
        {
            return CNode::getParentNode();
        }
        virtual OUString SAL_CALL getPrefix()
            throw (RuntimeException)
        {
           return CNode::getPrefix();
        }
        virtual Reference< XNode > SAL_CALL getPreviousSibling()
            throw (RuntimeException)
        {
            return CNode::getPreviousSibling();
        }
        virtual sal_Bool SAL_CALL hasAttributes()
            throw (RuntimeException)
        {
            return CNode::hasAttributes();
        }
        virtual sal_Bool SAL_CALL hasChildNodes()
            throw (RuntimeException)
        {
            return CNode::hasChildNodes();
        }
        virtual Reference< XNode > SAL_CALL insertBefore(
                const Reference< XNode >& newChild, const Reference< XNode >& refChild)
            throw (DOMException)
        {
            return CNode::insertBefore(newChild, refChild);
        }
        virtual sal_Bool SAL_CALL isSupported(const OUString& feature, const OUString& ver)
            throw (RuntimeException)
        {
            return CNode::isSupported(feature, ver);
        }
        virtual void SAL_CALL normalize()
            throw (RuntimeException)
        {
            CNode::normalize();
        }
        virtual Reference< XNode > SAL_CALL removeChild(const Reference< XNode >& oldChild)
            throw (RuntimeException, DOMException)
        {
            return CNode::removeChild(oldChild);
        }
        virtual Reference< XNode > SAL_CALL replaceChild(
                const Reference< XNode >& newChild, const Reference< XNode >& oldChild)
            throw (RuntimeException, DOMException)
        {
            return CNode::replaceChild(newChild, oldChild);
        }
        virtual void SAL_CALL setNodeValue(const OUString& nodeValue)
            throw (RuntimeException, DOMException)
        {
            return CNode::setNodeValue(nodeValue);
        }
        virtual void SAL_CALL setPrefix(const OUString& prefix)
            throw (RuntimeException, DOMException)
        {
            return CNode::setPrefix(prefix);
        }

    // ::com::sun::star::xml::sax::XSAXSerializable
    virtual void SAL_CALL serialize(
            const Reference< XDocumentHandler >& i_xHandler,
            const Sequence< beans::StringPair >& i_rNamespaces)
        throw (RuntimeException, SAXException);
    };
}

#endif
<|endoftext|>